From: <dav...@us...> - 2012-09-10 21:02:53
|
Revision: 5029 http://qore.svn.sourceforge.net/qore/?rev=5029&view=rev Author: david_nichols Date: 2012-09-10 21:02:42 +0000 (Mon, 10 Sep 2012) Log Message: ----------- * started implementing basic number operations * implemented parser supoprt for number values (suffixed with n; ex: "100n", "50e-16n", "0.000000233n", etc * implemented suport for parsing floating-point values with an exponent (ex: 2.323e+20) Modified Paths: -------------- qore/trunk/configure.ac qore/trunk/include/qore/QoreLib.h qore/trunk/include/qore/QoreNumberNode.h qore/trunk/include/qore/QoreString.h qore/trunk/include/qore/intern/Operator.h qore/trunk/include/qore/intern/QoreLibIntern.h qore/trunk/include/qore/intern/QoreTypeInfo.h qore/trunk/include/qore/intern/ThreadResourceList.h qore/trunk/lib/Operator.cpp qore/trunk/lib/QoreNumberNode.cpp qore/trunk/lib/QoreString.cpp qore/trunk/lib/parser.ypp qore/trunk/lib/scanner.lpp qore/trunk/lib/thread.cpp Modified: qore/trunk/configure.ac =================================================================== --- qore/trunk/configure.ac 2012-09-10 10:06:02 UTC (rev 5028) +++ qore/trunk/configure.ac 2012-09-10 21:02:42 UTC (rev 5029) @@ -681,6 +681,22 @@ AC_MSG_RESULT([includes $with_zlib_includes libs $with_zlib_libs (shared)]) fi +AC_MSG_CHECKING([for mpfr libraries and header files]) +for dir in "${with_mpfr_dir}" "${with_lib_prefix}" "${find_prefix}" /usr / /usr/local /opt/gnu /opt/mpfr /usr/local/mpfr /opt/local /sw /usr/sfw /opt/sfw; do + find_mpfr $dir + if test -n "$MPFR_LDFLAGS"; then + break + fi +done +if test -z "$MPFR_LDFLAGS"; then + AC_MSG_ERROR([no mpfr library found]) +fi +if test -n "$mpfr_static"; then + AC_MSG_RESULT([includes $with_mpfr_includes libs $with_mpfr_libs (static)]) +else + AC_MSG_RESULT([includes $with_mpfr_includes libs $with_mpfr_libs (shared)]) +fi + AC_MSG_CHECKING([for gmp libraries and header files]) for dir in "${with_gmp_dir}" "${with_lib_prefix}" "${find_prefix}" /usr / /usr/local /opt/gnu /opt/gmp /usr/local/gmp /opt/local /sw /usr/sfw /opt/sfw; do find_gmp $dir @@ -697,22 +713,6 @@ AC_MSG_RESULT([includes $with_gmp_includes libs $with_gmp_libs (shared)]) fi -AC_MSG_CHECKING([for mpfr libraries and header files]) -for dir in "${with_mpfr_dir}" "${with_lib_prefix}" "${find_prefix}" /usr / /usr/local /opt/gnu /opt/mpfr /usr/local/mpfr /opt/local /sw /usr/sfw /opt/sfw; do - find_mpfr $dir - if test -n "$MPFR_LDFLAGS"; then - break - fi -done -if test -z "$MPFR_LDFLAGS"; then - AC_MSG_ERROR([no mpfr library found]) -fi -if test -n "$mpfr_static"; then - AC_MSG_RESULT([includes $with_mpfr_includes libs $with_mpfr_libs (static)]) -else - AC_MSG_RESULT([includes $with_mpfr_includes libs $with_mpfr_libs (shared)]) -fi - set_pcre_cppflags() { if test "$1" != "/usr/include"; then PCRE_CPPFLAGS=-I$1 @@ -1270,7 +1270,7 @@ # Checks for header files. AC_HEADER_STDC AC_HEADER_SYS_WAIT -AC_CHECK_HEADERS([fcntl.h inttypes.h netdb.h netinet/in.h stddef.h stdlib.h string.h strings.h sys/socket.h sys/time.h unistd.h execinfo.h cxxabi.h arpa/inet.h sys/socket.h sys/statvfs.h winsock2.h ws2tcpip.h glob.h sys/un.h termios.h netinet/tcp.h pwd.h sys/wait.h getopt.h]) +AC_CHECK_HEADERS([fcntl.h inttypes.h netdb.h netinet/in.h stddef.h stdlib.h string.h strings.h sys/socket.h sys/time.h unistd.h execinfo.h cxxabi.h arpa/inet.h sys/socket.h sys/statvfs.h winsock2.h ws2tcpip.h glob.h sys/un.h termios.h netinet/tcp.h pwd.h sys/wait.h getopt.h stdint.h]) # check for umem.h AC_CHECK_HEADER([umem.h], have_umem_h=yes, have_umem_h=no) Modified: qore/trunk/include/qore/QoreLib.h =================================================================== --- qore/trunk/include/qore/QoreLib.h 2012-09-10 10:06:02 UTC (rev 5028) +++ qore/trunk/include/qore/QoreLib.h 2012-09-10 21:02:42 UTC (rev 5029) @@ -396,6 +396,9 @@ //! macro to return the maximum of 2 numbers #define QORE_MAX(a, b) ((a) > (b) ? (a) : (b)) +//! macro to return the minimum of 2 numbers +#define QORE_MIN(a, b) ((a) < (b) ? (a) : (b)) + #define QORE_PARAM_NO_ARG (NULL) // define QORE_PATH_MAX Modified: qore/trunk/include/qore/QoreNumberNode.h =================================================================== --- qore/trunk/include/qore/QoreNumberNode.h 2012-09-10 10:06:02 UTC (rev 5028) +++ qore/trunk/include/qore/QoreNumberNode.h 2012-09-10 21:02:42 UTC (rev 5029) @@ -53,7 +53,13 @@ */ DLLEXPORT virtual ~QoreNumberNode(); + // private + DLLLOCAL QoreNumberNode(struct qore_number_private* p); + public: + //! creates a new number value from the node, if not possible then the new number will be assigned 0 + DLLEXPORT QoreNumberNode(const AbstractQoreNode* n); + //! creates a new number value and assigns the initial value to it /** @param f the value for the object @@ -154,6 +160,12 @@ */ DLLEXPORT virtual const char* getTypeName() const; + //! add the argument to this value and return the result + DLLEXPORT QoreNumberNode* doPlus(const QoreNumberNode* right) const; + + //! returns true if the number is zero + DLLEXPORT bool zero() const; + //! returns the type information DLLLOCAL virtual AbstractQoreNode* parseInit(LocalVar* oflag, int pflag, int& lvids, const QoreTypeInfo*& typeInfo); Modified: qore/trunk/include/qore/QoreString.h =================================================================== --- qore/trunk/include/qore/QoreString.h 2012-09-10 10:06:02 UTC (rev 5028) +++ qore/trunk/include/qore/QoreString.h 2012-09-10 21:02:42 UTC (rev 5029) @@ -450,10 +450,28 @@ //! returns the string's buffer; this data should not be changed DLLEXPORT const char* getBuffer() const; - // Make sure the internal buffer has at least expected size in bytes. - // Useful to eliminate repeated reallocate() when data are appended in a loop. + //! Ensure the internal buffer has at least expected size in bytes + /** Useful to eliminate repeated buffer reallocations when data are appended in a loop + */ DLLEXPORT void allocate(unsigned requested_size); + //! insert a character at a certain position in the string a number of times + /** @param c the character to insert + @param pos the position to insert the character(s) (first position is 0) + @param times the number of times the character should be inserted + + @return 0 = OK, -1 = error (pos is greater than the string's length) + */ + DLLEXPORT int insertch(char c, qore_size_t pos, unsigned times); + + //! inserts a character string at a certain position in the string + /** @param str the string to insert + @param pos the position to insert the string (first position is 0) + + @return 0 = OK, -1 = error (pos is greater than the string's length) + */ + DLLEXPORT int insert(const char* str, qore_size_t pos); + //! append a character to the string a number of times DLLEXPORT void addch(char c, unsigned times); Modified: qore/trunk/include/qore/intern/Operator.h =================================================================== --- qore/trunk/include/qore/intern/Operator.h 2012-09-10 10:06:02 UTC (rev 5028) +++ qore/trunk/include/qore/intern/Operator.h 2012-09-10 21:02:42 UTC (rev 5029) @@ -94,6 +94,8 @@ typedef int64 (*op_bigint_func_t)(const AbstractQoreNode *l, const AbstractQoreNode *r, ExceptionSink *xsink); typedef double (*op_float_func_t)(const AbstractQoreNode *l, const AbstractQoreNode *r, ExceptionSink *xsink); +typedef QoreNumberNode *(*op_number_func_t)(const QoreNumberNode* l, const QoreNumberNode* r, ExceptionSink* xsink); + class AbstractOperatorFunction { public: qore_type_t ltype, rtype; @@ -568,6 +570,20 @@ DLLLOCAL virtual double float_eval(const AbstractQoreNode *l, const AbstractQoreNode *r, int args, ExceptionSink *xsink) const; }; +class NumberOperatorFunction : public AbstractOperatorFunction { + private: + op_number_func_t op_func; + + public: + DLLLOCAL NumberOperatorFunction(op_number_func_t f) : AbstractOperatorFunction(NT_NUMBER, NT_NUMBER), op_func(f) { + } + DLLLOCAL virtual ~NumberOperatorFunction() {} + DLLLOCAL virtual AbstractQoreNode *eval(const AbstractQoreNode *l, const AbstractQoreNode *r, bool ref_rv, int args, ExceptionSink *xsink) const; + DLLLOCAL virtual bool bool_eval(const AbstractQoreNode *l, const AbstractQoreNode *r, int args, ExceptionSink *xsink) const; + DLLLOCAL virtual int64 bigint_eval(const AbstractQoreNode *l, const AbstractQoreNode *r, int args, ExceptionSink *xsink) const; + DLLLOCAL virtual double float_eval(const AbstractQoreNode *l, const AbstractQoreNode *r, int args, ExceptionSink *xsink) const; +}; + class DefaultNothingOperatorFunction : public AbstractOperatorFunction { public: DLLLOCAL DefaultNothingOperatorFunction() : AbstractOperatorFunction(NT_ALL, NT_ALL) { @@ -704,6 +720,9 @@ DLLLOCAL void addFunction(op_compare_float_func_t f) { functions.push_back(new CompareFloatOperatorFunction(f)); } + DLLLOCAL void addFunction(op_number_func_t f) { + functions.push_back(new NumberOperatorFunction(f)); + } DLLLOCAL void addFunction(op_logic_func_t f) { functions.push_back(new LogicOperatorFunction(f)); } Modified: qore/trunk/include/qore/intern/QoreLibIntern.h =================================================================== --- qore/trunk/include/qore/intern/QoreLibIntern.h 2012-09-10 10:06:02 UTC (rev 5028) +++ qore/trunk/include/qore/intern/QoreLibIntern.h 2012-09-10 21:02:42 UTC (rev 5029) @@ -75,6 +75,13 @@ #include <netinet/tcp.h> #endif +#ifdef HAVE_STDINT_H +#include <stdint.h> +#endif +#ifdef HAVE_INTTYPES_H +#include <inttypes.h> +#endif + // for arbitrary-precision numeric support #include <mpfr.h> @@ -187,7 +194,6 @@ #ifndef HAVE_ATOLL #ifdef HAVE_STRTOIMAX -#include <inttypes.h> static inline long long atoll(const char* str) { return strtoimax(str, 0, 10); } Modified: qore/trunk/include/qore/intern/QoreTypeInfo.h =================================================================== --- qore/trunk/include/qore/intern/QoreTypeInfo.h 2012-09-10 10:06:02 UTC (rev 5028) +++ qore/trunk/include/qore/intern/QoreTypeInfo.h 2012-09-10 21:02:42 UTC (rev 5029) @@ -1359,7 +1359,7 @@ } }; -// accepts int, float, string, date, null, or boolean and returns an int +// accepts int, float, number, string, date, null, or boolean and returns an int class SoftBigIntTypeInfo : public AcceptsMultiFilterTypeInfo { protected: DLLLOCAL virtual const char *getNameImpl() const { @@ -1373,10 +1373,11 @@ return true; if (t != NT_FLOAT - && t != NT_STRING - && t != NT_BOOLEAN - && t != NT_DATE - && t != NT_NULL) + && t != NT_NUMBER + && t != NT_STRING + && t != NT_BOOLEAN + && t != NT_DATE + && t != NT_NULL) return false; int64 rv = n->getAsBigInt(); @@ -1392,6 +1393,7 @@ DLLLOCAL void init() { at.push_back(floatTypeInfo); + at.push_back(numberTypeInfo); at.push_back(stringTypeInfo); at.push_back(boolTypeInfo); at.push_back(dateTypeInfo); @@ -1423,10 +1425,11 @@ return true; if (t != NT_FLOAT - && t != NT_STRING - && t != NT_BOOLEAN - && t != NT_DATE - && t != NT_NULL) + && t != NT_NUMBER + && t != NT_STRING + && t != NT_BOOLEAN + && t != NT_DATE + && t != NT_NULL) return false; int64 rv = n->getAsBigInt(); @@ -1443,7 +1446,7 @@ } }; -// accepts int, float, string, date, null, or boolean and returns a float +// accepts int, float, number, string, date, null, or boolean and returns a float class SoftFloatTypeInfo : public AcceptsMultiFilterTypeInfo { protected: DLLLOCAL virtual const char *getNameImpl() const { @@ -1457,10 +1460,11 @@ return true; if (t != NT_INT && (t < QORE_NUM_TYPES || !dynamic_cast<const QoreBigIntNode *>(n)) - && t != NT_STRING - && t != NT_BOOLEAN - && t != NT_DATE - && t != NT_NULL) + && t != NT_NUMBER + && t != NT_STRING + && t != NT_BOOLEAN + && t != NT_DATE + && t != NT_NULL) return false; double rv = n->getAsFloat(); @@ -1476,6 +1480,7 @@ public: DLLLOCAL SoftFloatTypeInfo(bool n_returns_mult = false) : AcceptsMultiFilterTypeInfo(0, NT_FLOAT, n_returns_mult, false, true, n_returns_mult ? false : true, false, n_returns_mult ? false : true) { + at.push_back(numberTypeInfo); at.push_back(bigIntTypeInfo); at.push_back(stringTypeInfo); at.push_back(boolTypeInfo); @@ -1503,10 +1508,11 @@ return true; if (t != NT_INT && (t < QORE_NUM_TYPES || !dynamic_cast<const QoreBigIntNode *>(n)) - && t != NT_STRING - && t != NT_BOOLEAN - && t != NT_DATE - && t != NT_NULL) + && t != NT_NUMBER + && t != NT_STRING + && t != NT_BOOLEAN + && t != NT_DATE + && t != NT_NULL) return false; double rv = n->getAsFloat(); @@ -1543,9 +1549,21 @@ return true; } - if (t != NT_INT && (t < QORE_NUM_TYPES || !dynamic_cast<const QoreBigIntNode *>(n)) - && t != NT_STRING - && t != NT_BOOLEAN + if (t == NT_STRING) { + QoreNumberNode* nn = new QoreNumberNode(reinterpret_cast<const QoreStringNode*>(n)->getBuffer()); + n->deref(xsink); + n = nn; + return true; + } + + if (t == NT_INT || (t > QORE_NUM_TYPES && dynamic_cast<const QoreBigIntNode*>(n))) { + QoreNumberNode* nn = new QoreNumberNode(reinterpret_cast<const QoreBigIntNode*>(n)->val); + n->deref(xsink); + n = nn; + return true; + } + + if (t != NT_BOOLEAN && t != NT_DATE && t != NT_NULL) return false; @@ -1598,9 +1616,21 @@ return true; } - if (t != NT_INT && (t < QORE_NUM_TYPES || !dynamic_cast<const QoreBigIntNode*>(n)) - && t != NT_STRING - && t != NT_BOOLEAN + if (t == NT_STRING) { + QoreNumberNode* nn = new QoreNumberNode(reinterpret_cast<const QoreStringNode*>(n)->getBuffer()); + n->deref(xsink); + n = nn; + return true; + } + + if (t == NT_INT || (t > QORE_NUM_TYPES && dynamic_cast<const QoreBigIntNode*>(n))) { + QoreNumberNode* nn = new QoreNumberNode(reinterpret_cast<const QoreBigIntNode*>(n)->val); + n->deref(xsink); + n = nn; + return true; + } + + if (t != NT_BOOLEAN && t != NT_DATE && t != NT_NULL) return false; @@ -1619,7 +1649,7 @@ } }; -// accepts int, float, string, date, null, or boolean and returns a boolean +// accepts int, float, number, string, date, null, or boolean and returns a boolean class SoftBoolTypeInfo : public AcceptsMultiFilterTypeInfo { protected: DLLLOCAL virtual const char *getNameImpl() const { @@ -1633,10 +1663,11 @@ return true; if (t != NT_INT && (t < QORE_NUM_TYPES || !dynamic_cast<const QoreBigIntNode *>(n)) - && t != NT_FLOAT - && t != NT_STRING - && t != NT_DATE - && t != NT_NULL) + && t != NT_FLOAT + && t != NT_NUMBER + && t != NT_STRING + && t != NT_DATE + && t != NT_NULL) return false; bool rv = n->getAsBool(); @@ -1654,6 +1685,7 @@ DLLLOCAL SoftBoolTypeInfo(bool n_returns_mult = false) : AcceptsMultiFilterTypeInfo(0, NT_BOOLEAN, n_returns_mult, false, true, n_returns_mult ? false : true, false, n_returns_mult ? false : true) { at.push_back(bigIntTypeInfo); at.push_back(floatTypeInfo); + at.push_back(numberTypeInfo); at.push_back(stringTypeInfo); at.push_back(dateTypeInfo); at.push_back(nullTypeInfo); @@ -1679,10 +1711,11 @@ return true; if (t != NT_INT && (t < QORE_NUM_TYPES || !dynamic_cast<const QoreBigIntNode *>(n)) - && t != NT_FLOAT - && t != NT_STRING - && t != NT_DATE - && t != NT_NULL) + && t != NT_NUMBER + && t != NT_FLOAT + && t != NT_STRING + && t != NT_DATE + && t != NT_NULL) return false; bool rv = n->getAsBool(); @@ -1699,7 +1732,7 @@ } }; -// accepts int, float, string, date, bool, or null and returns a date +// accepts int, float, number, string, date, bool, or null and returns a date class SoftDateTypeInfo : public AcceptsMultiFilterTypeInfo { protected: DLLLOCAL virtual const char *getNameImpl() const { @@ -1712,8 +1745,9 @@ if (t == NT_DATE) return true; - if (t != NT_INT && (t < QORE_NUM_TYPES || !dynamic_cast<const QoreBigIntNode *>(n)) + if (t != NT_INT && (t < QORE_NUM_TYPES || !dynamic_cast<const QoreBigIntNode*>(n)) && t != NT_FLOAT + && t != NT_NUMBER && t != NT_STRING && t != NT_BOOLEAN && t != NT_NULL) @@ -1735,6 +1769,7 @@ DLLLOCAL SoftDateTypeInfo(bool n_returns_mult = false) : AcceptsMultiFilterTypeInfo(0, NT_DATE, n_returns_mult, false, true, n_returns_mult ? false : true, false, n_returns_mult ? false : true) { at.push_back(bigIntTypeInfo); at.push_back(floatTypeInfo); + at.push_back(numberTypeInfo); at.push_back(stringTypeInfo); at.push_back(boolTypeInfo); at.push_back(nullTypeInfo); @@ -1761,6 +1796,7 @@ if (t != NT_INT && (t < QORE_NUM_TYPES || !dynamic_cast<const QoreBigIntNode *>(n)) && t != NT_FLOAT + && t != NT_NUMBER && t != NT_STRING && t != NT_BOOLEAN && t != NT_NULL) @@ -1781,7 +1817,7 @@ } }; -// accepts int, float, string, date, null, or boolean and returns a string +// accepts int, float, number, string, date, null, or boolean and returns a string class SoftStringTypeInfo : public AcceptsMultiFilterTypeInfo { protected: DLLLOCAL virtual const char *getNameImpl() const { @@ -1796,6 +1832,7 @@ if (t != NT_INT && (t < QORE_NUM_TYPES || !dynamic_cast<const QoreBigIntNode *>(n)) && t != NT_FLOAT + && t != NT_NUMBER && t != NT_BOOLEAN && t != NT_DATE && t != NT_NULL) @@ -1817,6 +1854,7 @@ DLLLOCAL SoftStringTypeInfo(bool n_returns_mult = false) : AcceptsMultiFilterTypeInfo(0, NT_STRING, n_returns_mult, false, true, n_returns_mult ? false : true, false, n_returns_mult ? false : true) { at.push_back(bigIntTypeInfo); at.push_back(floatTypeInfo); + at.push_back(numberTypeInfo); at.push_back(boolTypeInfo); at.push_back(dateTypeInfo); at.push_back(nullTypeInfo); @@ -1843,6 +1881,7 @@ if (t != NT_INT && (t < QORE_NUM_TYPES || !dynamic_cast<const QoreBigIntNode *>(n)) && t != NT_FLOAT + && t != NT_NUMBER && t != NT_BOOLEAN && t != NT_DATE && t != NT_NULL) Modified: qore/trunk/include/qore/intern/ThreadResourceList.h =================================================================== --- qore/trunk/include/qore/intern/ThreadResourceList.h 2012-09-10 10:06:02 UTC (rev 5028) +++ qore/trunk/include/qore/intern/ThreadResourceList.h 2012-09-10 21:02:42 UTC (rev 5029) @@ -89,6 +89,4 @@ } }; - - #endif Modified: qore/trunk/lib/Operator.cpp =================================================================== --- qore/trunk/lib/Operator.cpp 2012-09-10 10:06:02 UTC (rev 5028) +++ qore/trunk/lib/Operator.cpp 2012-09-10 21:02:42 UTC (rev 5029) @@ -400,6 +400,10 @@ return left - right; } +static QoreNumberNode* op_plus_number(const QoreNumberNode* left, const QoreNumberNode* right, ExceptionSink* xsink) { + return left->doPlus(right); +} + static double op_plus_float(double left, double right) { return left + right; } @@ -1476,6 +1480,9 @@ if (t == NT_FLOAT) return new QoreFloatNode(n->getAsFloat()); + if (t == NT_NUMBER) + return new QoreNumberNode(n); + if (t == NT_BOOLEAN) return get_bool_node(n->getAsBool()); @@ -2585,6 +2592,122 @@ return op_func(left, right, xsink); } +AbstractQoreNode *NumberOperatorFunction::eval(const AbstractQoreNode *left, const AbstractQoreNode *right, bool ref_rv, int args, ExceptionSink *xsink) const { + ReferenceHolder<AbstractQoreNode> l(xsink); + + // convert node type to required argument types for operator if necessary + if ((left->getType() != ltype) && (ltype != NT_ALL)) { + l = get_node_type(left, ltype); + left = *l; + } + + if (args == 1) { + QoreNumberNode* rv = op_func(reinterpret_cast<const QoreNumberNode*>(left), reinterpret_cast<const QoreNumberNode*>(right), xsink); + assert(!(*xsink && rv)); + if (!ref_rv || *xsink) + return 0; + return rv; + } + + ReferenceHolder<AbstractQoreNode> r(xsink); + + // convert node type to required argument types for operator if necessary + if ((right->getType() != rtype) && (rtype != NT_ALL)) { + r = get_node_type(right, rtype); + right = *r; + } + + QoreNumberNode* rv = op_func(reinterpret_cast<const QoreNumberNode*>(left), reinterpret_cast<const QoreNumberNode*>(right), xsink); + assert(!(*xsink && rv)); + if (!ref_rv || xsink->isException()) + return 0; + return rv; +} + +bool NumberOperatorFunction::bool_eval(const AbstractQoreNode *left, const AbstractQoreNode *right, int args, ExceptionSink *xsink) const { + ReferenceHolder<AbstractQoreNode> l(xsink); + + // convert node type to required argument types for operator if necessary + if ((left->getType() != ltype) && (ltype != NT_ALL)) { + l = get_node_type(left, ltype); + left = *l; + } + + if (args == 1) { + SimpleRefHolder<QoreNumberNode> rv(op_func(reinterpret_cast<const QoreNumberNode*>(left), reinterpret_cast<const QoreNumberNode*>(right), xsink)); + assert(!(*xsink && rv)); + return !rv->zero(); + } + + ReferenceHolder<AbstractQoreNode> r(xsink); + + // convert node type to required argument types for operator if necessary + if ((right->getType() != rtype) && (rtype != NT_ALL)) { + r = get_node_type(right, rtype); + right = *r; + } + + SimpleRefHolder<QoreNumberNode> rv(op_func(reinterpret_cast<const QoreNumberNode*>(left), reinterpret_cast<const QoreNumberNode*>(right), xsink)); + assert(!(*xsink && rv)); + return !rv->zero(); +} + +int64 NumberOperatorFunction::bigint_eval(const AbstractQoreNode *left, const AbstractQoreNode *right, int args, ExceptionSink *xsink) const { + ReferenceHolder<AbstractQoreNode> l(xsink); + + // convert node type to required argument types for operator if necessary + if ((left->getType() != ltype) && (ltype != NT_ALL)) { + l = get_node_type(left, ltype); + left = *l; + } + + if (args == 1) { + SimpleRefHolder<QoreNumberNode> rv(op_func(reinterpret_cast<const QoreNumberNode*>(left), reinterpret_cast<const QoreNumberNode*>(right), xsink)); + assert(!(*xsink && rv)); + return rv->getAsBigInt(); + } + + ReferenceHolder<AbstractQoreNode> r(xsink); + + // convert node type to required argument types for operator if necessary + if ((right->getType() != rtype) && (rtype != NT_ALL)) { + r = get_node_type(right, rtype); + right = *r; + } + + SimpleRefHolder<QoreNumberNode> rv(op_func(reinterpret_cast<const QoreNumberNode*>(left), reinterpret_cast<const QoreNumberNode*>(right), xsink)); + assert(!(*xsink && rv)); + return rv->getAsBigInt(); +} + +double NumberOperatorFunction::float_eval(const AbstractQoreNode *left, const AbstractQoreNode *right, int args, ExceptionSink *xsink) const { + ReferenceHolder<AbstractQoreNode> l(xsink); + + // convert node type to required argument types for operator if necessary + if ((left->getType() != ltype) && (ltype != NT_ALL)) { + l = get_node_type(left, ltype); + left = *l; + } + + if (args == 1) { + SimpleRefHolder<QoreNumberNode> rv(op_func(reinterpret_cast<const QoreNumberNode*>(left), reinterpret_cast<const QoreNumberNode*>(right), xsink)); + assert(!(*xsink && rv)); + return rv->getAsFloat(); + } + + ReferenceHolder<AbstractQoreNode> r(xsink); + + // convert node type to required argument types for operator if necessary + if ((right->getType() != rtype) && (rtype != NT_ALL)) { + r = get_node_type(right, rtype); + right = *r; + } + + SimpleRefHolder<QoreNumberNode> rv(op_func(reinterpret_cast<const QoreNumberNode*>(left), reinterpret_cast<const QoreNumberNode*>(right), xsink)); + assert(!(*xsink && rv)); + return rv->getAsFloat(); +} + Operator::~Operator() { // erase all functions for (unsigned i = 0, size = functions.size(); i < size; i++) @@ -2604,7 +2727,7 @@ } AbstractQoreNode *Operator::parseInit(QoreTreeNode *tree, LocalVar *oflag, int pflag, int &lvids, const QoreTypeInfo *&resultTypeInfo) { - // check for illegal changes to local variables in background expressions + // check for illegal changes to local variables in background expressions if (pflag & PF_BACKGROUND && lvalue) { if (tree->left && tree->left->getType() == NT_VARREF && reinterpret_cast<VarRefNode *>(tree->left)->getType() == VT_LOCAL) parse_error("illegal local variable modification in background expression"); @@ -2612,7 +2735,7 @@ if (!check_args) return tree->defaultParseInit(oflag, pflag, lvids, resultTypeInfo); - + return check_args(tree, oflag, pflag, lvids, resultTypeInfo, name, description); } @@ -2635,7 +2758,7 @@ t = opMatrix[nleft->getType()][NT_NOTHING]; else t = findFunction(nleft->getType(), NT_NOTHING); - + printd(5, "Operator::get_function() found function %d\n", t); return t; } @@ -2682,11 +2805,11 @@ return 0; if (!nright) nright.assign(false, &Nothing); - + // find operator function if ((t = get_function(nleft, nright, xsink)) == -1) return 0; - + return functions[t]->eval(*nleft, *nright, ref_rv, 2, xsink); } @@ -2708,7 +2831,7 @@ return 0; if (!nleft) nleft.assign(false, &Nothing); - + int t; if (args == 1) { if ((t = get_function(nleft, xsink)) == -1) @@ -2722,11 +2845,11 @@ return 0; if (!nright) nright.assign(false, &Nothing); - + // find operator function if ((t = get_function(nleft, nright, xsink)) == -1) return 0; - + return functions[t]->bool_eval(*nleft, *nright, 2, xsink); } @@ -2763,11 +2886,11 @@ return 0; if (!nright) nright.assign(false, &Nothing); - + // find operator function if ((t = get_function(nleft, nright, xsink)) == -1) return 0; - + return functions[t]->bigint_eval(*nleft, *nright, 2, xsink); } @@ -2804,7 +2927,7 @@ return 0; if (!nright) nright.assign(false, &Nothing); - + // find operator function if ((t = get_function(nleft, nright, xsink)) == -1) return 0; @@ -2819,10 +2942,10 @@ int Operator::findFunction(qore_type_t ltype, qore_type_t rtype) const { int m = -1; - + //QORE_TRACE("Operator::findFunction()"); // loop through all operator functions - + for (int i = 0, size = functions.size(); i < size; i++) { AbstractOperatorFunction *f = functions[i]; @@ -2837,20 +2960,20 @@ if (match(ltype, f->ltype)) { /* if there is only one operator or there is also * a match on the right side, return */ - if ((args == 1) || - ((args == 2) && match(rtype, f->rtype))) { + if ((args == 1) || + ((args == 2) && match(rtype, f->rtype))) { return i; } if (!f->needsExactMatch() && m == -1) m = i; continue; } - if ((args == 2) && !f->needsExactMatch() && match(rtype, f->rtype) + if ((args == 2) && !f->needsExactMatch() && match(rtype, f->rtype) && (m == -1)) m = i; } /* if there is no match of any kind, take the highest priority function - * (row 0), and try to convert the arguments, otherwise return the best + * (row 0), and try to convert the arguments, otherwise return the best * partial match */ @@ -2889,9 +3012,9 @@ return o; } -// checks for illegal $self assignments in an object context +// checks for illegal $self assignments in an object context void check_self_assignment(AbstractQoreNode *n, LocalVar *selfid) { - // if it's a variable reference + // if it's a variable reference qore_type_t ntype = n->getType(); if (ntype == NT_VARREF) { VarRefNode *v = reinterpret_cast<VarRefNode *>(n); @@ -2905,7 +3028,7 @@ QoreTreeNode *tree = reinterpret_cast<QoreTreeNode *>(n); - // otherwise it's a tree: go to root expression + // otherwise it's a tree: go to root expression while (tree->left->getType() == NT_TREE) { n = tree->left; tree = reinterpret_cast<QoreTreeNode *>(n); @@ -2916,8 +3039,8 @@ VarRefNode *v = reinterpret_cast<VarRefNode *>(tree->left); - // left must be variable reference, check if the tree is - // a list reference; if so, it's invalid + // left must be variable reference, check if the tree is + // a list reference; if so, it's invalid if (v->getType() == VT_LOCAL && v->ref.id == selfid && tree->getOp() == OP_LIST_REF) parse_error("illegal conversion of 'self' to a list"); } @@ -2942,7 +3065,7 @@ // check for illegal assignment to $self if (oflag) check_self_assignment(v, oflag); - + ri.parseInit(argInfo); if (prototypeInfo->hasType()) { @@ -3042,25 +3165,25 @@ return tree->evalSubst(returnTypeInfo); // if either side is a date, then the return type is date (highest priority) - if (leftTypeInfo->isType(NT_DATE) + if (leftTypeInfo->isType(NT_DATE) || rightTypeInfo->isType(NT_DATE)) returnTypeInfo = dateTypeInfo; // otherwise we have to make sure types are known on both sides of the expression else if (leftTypeInfo->hasType() && rightTypeInfo->hasType()) { - if (leftTypeInfo->isType(NT_FLOAT) + if (leftTypeInfo->isType(NT_FLOAT) || rightTypeInfo->isType(NT_FLOAT)) returnTypeInfo = floatTypeInfo; - else if (leftTypeInfo->isType(NT_INT) + else if (leftTypeInfo->isType(NT_INT) || rightTypeInfo->isType(NT_INT)) returnTypeInfo = bigIntTypeInfo; - else if ((leftTypeInfo->isType(NT_HASH) + else if ((leftTypeInfo->isType(NT_HASH) || leftTypeInfo->isType(NT_OBJECT)) && (rightTypeInfo->isType(NT_STRING) || rightTypeInfo->isType(NT_LIST))) returnTypeInfo = hashTypeInfo; - else if (leftTypeInfo->returnsSingle() && rightTypeInfo->returnsSingle()) + else if (leftTypeInfo->returnsSingle() && rightTypeInfo->returnsSingle()) // only return type nothing if both types are available and return a single type - returnTypeInfo = nothingTypeInfo; + returnTypeInfo = nothingTypeInfo; } else returnTypeInfo = 0; @@ -3080,41 +3203,45 @@ return tree->evalSubst(returnTypeInfo); // if either side is a list, then the return type is list (highest priority) - if (leftTypeInfo->isType(NT_LIST) + if (leftTypeInfo->isType(NT_LIST) || rightTypeInfo->isType(NT_LIST)) returnTypeInfo = listTypeInfo; // otherwise only set return type if return types on both sides are known at parse time else if (leftTypeInfo->hasType() && rightTypeInfo->hasType()) { - if (leftTypeInfo->isType(NT_STRING) + if (leftTypeInfo->isType(NT_STRING) || rightTypeInfo->isType(NT_STRING)) returnTypeInfo = stringTypeInfo; - else if (leftTypeInfo->isType(NT_DATE) + else if (leftTypeInfo->isType(NT_DATE) || rightTypeInfo->isType(NT_DATE)) returnTypeInfo = dateTypeInfo; - else if (leftTypeInfo->isType(NT_FLOAT) + else if (leftTypeInfo->isType(NT_NUMBER) + || rightTypeInfo->isType(NT_NUMBER)) + returnTypeInfo = numberTypeInfo; + + else if (leftTypeInfo->isType(NT_FLOAT) || rightTypeInfo->isType(NT_FLOAT)) returnTypeInfo = floatTypeInfo; - else if (leftTypeInfo->isType(NT_INT) + else if (leftTypeInfo->isType(NT_INT) || rightTypeInfo->isType(NT_INT)) returnTypeInfo = bigIntTypeInfo; else if (leftTypeInfo->isType(NT_HASH) || leftTypeInfo->isType(NT_OBJECT)) returnTypeInfo = hashTypeInfo; - + else if (rightTypeInfo->isType(NT_OBJECT)) returnTypeInfo = objectTypeInfo; - else if (leftTypeInfo->isType(NT_BINARY) + else if (leftTypeInfo->isType(NT_BINARY) || rightTypeInfo->isType(NT_BINARY)) returnTypeInfo = binaryTypeInfo; - else if (leftTypeInfo->returnsSingle() && rightTypeInfo->returnsSingle()) + else if (leftTypeInfo->returnsSingle() && rightTypeInfo->returnsSingle()) // only return type nothing if both types are available and return a single type returnTypeInfo = nothingTypeInfo; } @@ -3393,19 +3520,19 @@ // registers the system operators and system operator functions void OperatorList::init() { QORE_TRACE("OperatorList::init()"); - + OP_LOG_AND = add(new Operator(2, "&&", "logical-and", 0, false, false, check_op_logical)); OP_LOG_AND->addEffectFunction(op_log_and); OP_LOG_OR = add(new Operator(2, "||", "logical-or", 0, false, false, check_op_logical)); OP_LOG_OR->addEffectFunction(op_log_or); - + OP_LOG_LT = add(new Operator(2, "<", "less-than", 1, false, false, check_op_logical)); OP_LOG_LT->addFunction(op_log_lt_float); OP_LOG_LT->addFunction(op_log_lt_bigint); OP_LOG_LT->addFunction(op_log_lt_string); OP_LOG_LT->addFunction(op_log_lt_date); - + OP_LOG_GT = add(new Operator(2, ">", "greater-than", 1, false, false, check_op_logical)); OP_LOG_GT->addFunction(op_log_gt_float); OP_LOG_GT->addFunction(op_log_gt_bigint); @@ -3427,7 +3554,7 @@ OP_LOG_NE->addFunction(op_log_ne_boolean); OP_LOG_NE->addFunction(op_log_ne_date); OP_LOG_NE->addNoConvertFunction(NT_ALL, NT_ALL, op_log_ne_all); - + OP_LOG_LE = add(new Operator(2, "<=", "less-than-or-equals", 1, false, false, check_op_logical)); OP_LOG_LE->addFunction(op_log_le_float); OP_LOG_LE->addFunction(op_log_le_bigint); @@ -3442,25 +3569,25 @@ OP_ABSOLUTE_EQ = add(new Operator(2, "===", "absolute logical-equals", 0, false, false, check_op_logical)); OP_ABSOLUTE_EQ->addFunction(NT_ALL, NT_ALL, op_absolute_log_eq); - + OP_ABSOLUTE_NE = add(new Operator(2, "!==", "absolute logical-not-equals", 0, false, false, check_op_logical)); OP_ABSOLUTE_NE->addFunction(NT_ALL, NT_ALL, op_absolute_log_neq); - + OP_REGEX_MATCH = add(new Operator(2, "=~", "regular expression match", 0, false, false, check_op_logical)); OP_REGEX_MATCH->addFunction(op_regex_match); - + OP_REGEX_NMATCH = add(new Operator(2, "!~", "regular expression negative match", 0, false, false, check_op_logical)); OP_REGEX_NMATCH->addFunction(op_regex_nmatch); OP_EXISTS = add(new Operator(1, "exists", "exists", 1, false, false, check_op_logical)); OP_EXISTS->addFunction(NT_ALL, NT_NONE, op_exists); - + OP_INSTANCEOF = add(new Operator(2, "instanceof", "instanceof", 0, false, false, check_op_logical)); OP_INSTANCEOF->addFunction(NT_ALL, NT_CLASSREF, op_instanceof); - + OP_NOT = add(new Operator(1, "!", "logical-not", 1, false, false, check_op_logical)); OP_NOT->addBoolNotFunction(); - + // bigint operators OP_LOG_CMP = add(new Operator(2, "<=>", "logical-comparison", 1, false, false, check_op_returns_integer)); OP_LOG_CMP->addFunction(op_cmp_string); @@ -3477,7 +3604,7 @@ // non-boolean operators OP_LIST_ASSIGNMENT = add(new Operator(2, "(list) =", "list assignment", 0, true, true, check_op_list_assignment)); OP_LIST_ASSIGNMENT->addFunction(NT_ALL, NT_ALL, op_list_assignment); - + OP_BIN_AND = add(new Operator(2, "&", "binary-and", 1, false, false, check_op_returns_integer)); OP_BIN_AND->addFunction(op_bin_and_int); @@ -3502,6 +3629,7 @@ OP_PLUS->addFunction(NT_LIST, NT_LIST, op_plus_list); OP_PLUS->addFunction(op_plus_string); OP_PLUS->addFunction(op_plus_date); + OP_PLUS->addFunction(op_plus_number); OP_PLUS->addFunction(op_plus_float); OP_PLUS->addFunction(op_plus_bigint); OP_PLUS->addFunction(NT_HASH, NT_HASH, op_plus_hash_hash); @@ -3531,7 +3659,7 @@ // cannot validate return type here yet OP_OBJECT_REF = add(new Operator(2, ".", "hash/object-reference", 0, false, false, check_op_object_ref)); - OP_OBJECT_REF->addFunction(NT_ALL, NT_ALL, op_object_ref); + OP_OBJECT_REF->addFunction(NT_ALL, NT_ALL, op_object_ref); // can return a list or NOTHING OP_KEYS = add(new Operator(1, "keys", "list of keys", 0, false, false, check_op_keys)); Modified: qore/trunk/lib/QoreNumberNode.cpp =================================================================== --- qore/trunk/lib/QoreNumberNode.cpp 2012-09-10 10:06:02 UTC (rev 5028) +++ qore/trunk/lib/QoreNumberNode.cpp 2012-09-10 21:02:42 UTC (rev 5029) @@ -22,23 +22,186 @@ #include <qore/Qore.h> -struct qore_number_private { - DLLLOCAL qore_number_private() { +#define QORE_DEFAULT_PREC 128 +#define QORE_MAX_PREC 8192 +// round to nearest (roundTiesToEven in IEEE 754-2008) +#define QORE_MPFR_RND MPFR_RNDN +// MPFR_RNDA + +struct qore_number_private_intern { + mpfr_t num; + + DLLLOCAL qore_number_private_intern() { + mpfr_init2(num, QORE_DEFAULT_PREC); } + DLLLOCAL qore_number_private_intern(mpfr_prec_t prec) { + if (prec > QORE_MAX_PREC) + prec = QORE_MAX_PREC; + mpfr_init2(num, prec); + } + + DLLLOCAL ~qore_number_private_intern() { + mpfr_clear(num); + } +}; + +struct qore_number_private : public qore_number_private_intern { + DLLLOCAL explicit qore_number_private(mpfr_prec_t prec) : qore_number_private_intern(prec) { + } + DLLLOCAL qore_number_private(double f) { + mpfr_set_d(num, f, QORE_MPFR_RND); } DLLLOCAL qore_number_private(int64 i) { + mpfr_set_sj(num, i, QORE_MPFR_RND); } - DLLLOCAL qore_number_private(const char* str) { + DLLLOCAL qore_number_private(const char* str) : qore_number_private_intern(QORE_MAX(QORE_DEFAULT_PREC, strlen(str)*10)) { + mpfr_set_str(num, str, 10, QORE_MPFR_RND); } - DLLLOCAL qore_number_private(const qore_number_private& old) { + DLLLOCAL qore_number_private(const qore_number_private& old) : qore_number_private_intern(mpfr_get_prec(old.num)) { + mpfr_set(num, old.num, QORE_MPFR_RND); } + + DLLLOCAL double getAsFloat() const { + return mpfr_get_d(num, QORE_MPFR_RND); + } + + DLLLOCAL int64 getAsBigInt() const { + return mpfr_get_sj(num, QORE_MPFR_RND); + } + + DLLLOCAL bool getAsBool() const { + return !zero(); + } + + DLLLOCAL bool zero() const { + return (bool)mpfr_zero_p(num); + } + + DLLLOCAL bool nan() const { + return (bool)mpfr_nan_p(num); + } + + DLLLOCAL bool inf() const { + return (bool)mpfr_inf_p(num); + } + + DLLLOCAL bool number() const { + return (bool)mpfr_number_p(num); + } + + // regular and not zero + DLLLOCAL bool regular() const { + return (bool)mpfr_regular_p(num); + } + + DLLLOCAL void getAsString(QoreString& str) const { + // first check if it's zero + if (zero()) { + str.concat("0n"); + return; + } + mpfr_exp_t exp; + char* buf = mpfr_get_str(0, &exp, 10, 0, num, QORE_MPFR_RND); + if (!buf) { + str.concat("<number error>"); + return; + } + + // if it's a regular number, then format accordingly + if (number()) { + qore_size_t len = str.size(); + //printd(0, "QoreNumberNode::getAsString() this: %p '%s' exp "QLLD" len: "QLLD"\n", this, buf, exp, len); + + str.concat(buf); + // trim the trailing zeros off the end + str.trim_trailing('0'); + if (exp <= 0) { + exp = -exp; + str.insert("0.", len); + if (exp) + str.insertch('0', len + 2, exp); + } + else { + // get remaining length of string (how many characters were added) + qore_size_t rlen = str.size() - len; + + //printd(0, "QoreNumberNode::getAsString() this: %p str: '%s' rlen: "QLLD"\n", this, str.getBuffer(), rlen); + + // assert that we have added at least 1 character + assert(rlen > 0); + if (exp > rlen) + str.insertch('0', str.size(), exp - rlen); + else if (exp < rlen) + str.insertch('.', len + exp, 1); + } + str.concat('n'); + } + + mpfr_free_str(buf); + } + + DLLLOCAL int compare(const qore_number_private& right) const { + return mpfr_cmp(num, right.num); + } + + DLLLOCAL int compare(double right) const { + return mpfr_cmp_d(num, right); + } + + DLLLOCAL int compare(int64 right) const { + MPFR_DECL_INIT(r, QORE_DEFAULT_PREC); + mpfr_set_sj(r, right, QORE_MPFR_RND); + return mpfr_cmp(num, r); + } + + DLLLOCAL qore_number_private* doPlus(const qore_number_private& r) const { + mpfr_prec_t prec = QORE_MAX(mpfr_get_prec(num), mpfr_get_prec(r.num)); + qore_number_private* p = new qore_number_private(prec); + mpfr_add(p->num, num, r.num, QORE_MPFR_RND); + return p; + } }; +QoreNumberNode::QoreNumberNode(struct qore_number_private* p) : SimpleValueQoreNode(NT_NUMBER), priv(p) { +} + +QoreNumberNode::QoreNumberNode(const AbstractQoreNode* n) : SimpleValueQoreNode(NT_NUMBER), priv(0) { + qore_type_t t = get_node_type(n); + if (t == NT_NUMBER) { + priv = new qore_number_private(*reinterpret_cast<const QoreNumberNode*>(n)->priv); + return; + } + + if (t == NT_FLOAT) { + priv = new qore_number_private(reinterpret_cast<const QoreFloatNode*>(n)->f); + return; + } + + if (t == NT_STRING) { + priv = new qore_number_private(reinterpret_cast<const QoreStringNode*>(n)->getBuffer()); + return; + } + + if (t == NT_INT || (t > QORE_NUM_TYPES && dynamic_cast<const QoreBigIntNode*>(n))) { + priv = new qore_number_private(reinterpret_cast<const QoreBigIntNode*>(n)->val); + return; + } + + if (t != NT_BOOLEAN + && t != NT_DATE + && t != NT_NULL) { + priv = new qore_number_private(0ll); + return; + } + + priv = new qore_number_private(n->getAsFloat()); +} + QoreNumberNode::QoreNumberNode(double f) : SimpleValueQoreNode(NT_NUMBER), priv(new qore_number_private(f)) { } @@ -48,7 +211,7 @@ QoreNumberNode::QoreNumberNode(const char* str) : SimpleValueQoreNode(NT_NUMBER), priv(new qore_number_private(str)) { } -QoreNumberNode::QoreNumberNode() : SimpleValueQoreNode(NT_NUMBER), priv(new qore_number_private) { +QoreNumberNode::QoreNumberNode() : SimpleValueQoreNode(NT_NUMBER), priv(new qore_number_private(0ll)) { } QoreNumberNode::QoreNumberNode(const QoreNumberNode& old) : SimpleValueQoreNode(old), priv(new qore_number_private(*old.priv)) { @@ -61,83 +224,92 @@ // get the value of the type in a string context (default implementation = del = false and returns NullString) // if del is true, then the returned QoreString * should be deleted, if false, then it must not be // use the QoreStringValueHelper class (defined in QoreStringNode.h) instead of using this function directly -QoreString *QoreNumberNode::getStringRepresentation(bool& del) const { +QoreString* QoreNumberNode::getStringRepresentation(bool& del) const { del = true; - return new QoreString("xxx"); + QoreString* str = new QoreString; + priv->getAsString(*str); + return str; } // concatenate string representation to a QoreString (no action for complex types = default implementation) void QoreNumberNode::getStringRepresentation(QoreString& str) const { - str.concat("xxx"); + priv->getAsString(str); } // if del is true, then the returned DateTime * should be deleted, if false, then it should not DateTime *QoreNumberNode::getDateTimeRepresentation(bool& del) const { del = true; - return DateTime::makeAbsoluteLocal(currentTZ(), (int64)0, (int)0); + double f = priv->getAsFloat(); + return DateTime::makeAbsoluteLocal(currentTZ(), (int64)f, (int)((f - (float)((int)f)) * 1000000)); } // assign date representation to a DateTime (no action for complex types = default implementation) void QoreNumberNode::getDateTimeRepresentation(DateTime& dt) const { - dt.setLocalDate(currentTZ(), (int64)0, (int)0); + double f = priv->getAsFloat(); + dt.setLocalDate(currentTZ(), (int64)f, (int)((f - (float)((int)f)) * 1000000)); } bool QoreNumberNode::getAsBoolImpl() const { - return (bool)false; + return priv->getAsBool(); } int QoreNumberNode::getAsIntImpl() const { - return (int)0; + return priv->getAsBigInt(); } int64 QoreNumberNode::getAsBigIntImpl() const { - return (int64)0; + return priv->getAsBigInt(); } double QoreNumberNode::getAsFloatImpl() const { - return 0.0; + return priv->getAsFloat(); } -// get string representation (for %n and %N), foff is for multi-line formatting offset, -1 = no line breaks -// the ExceptionSink is only needed for QoreObject where a method may be executed -// use the QoreNodeAsStringHelper class (defined in QoreStringNode.h) instead of using these functions directly -// returns -1 for exception raised, 0 = OK -int QoreNumberNode::getAsString(QoreString& str, int foff, ExceptionSink *xsink) const { +int QoreNumberNode::getAsString(QoreString& str, int foff, ExceptionSink* xsink) const { getStringRepresentation(str); return 0; } // if del is true, then the returned QoreString * should be deleted, if false, then it must not be -QoreString *QoreNumberNode::getAsString(bool& del, int foff, ExceptionSink *xsink) const { +QoreString *QoreNumberNode::getAsString(bool& del, int foff, ExceptionSink* xsink) const { return getStringRepresentation(del); } -AbstractQoreNode *QoreNumberNode::realCopy() const { +AbstractQoreNode* QoreNumberNode::realCopy() const { return new QoreNumberNode(*this); } -// performs a lexical compare, return -1, 0, or 1 if the "this" value is less than, equal, or greater than -// the "val" passed -//DLLLOCAL virtual int compare(const AbstractQoreNode *val) const; // the type passed must always be equal to the current type -bool QoreNumberNode::is_equal_soft(const AbstractQoreNode *v, ExceptionSink *xsink) const { - return false; +bool QoreNumberNode::is_equal_soft(const AbstractQoreNode* v, ExceptionSink* xsink) const { + if (v->getType() == NT_NUMBER) + return !priv->compare(*reinterpret_cast<const QoreNumberNode*>(v)->priv); + if (v->getType() == NT_INT || dynamic_cast<const QoreBigIntNode*>(v)) + return !priv->compare(reinterpret_cast<const QoreBigIntNode*>(v)->val); + + return !priv->compare(v->getAsFloat()); } -bool QoreNumberNode::is_equal_hard(const AbstractQoreNode *v, ExceptionSink *xsink) const { - const QoreNumberNode *fn = dynamic_cast<const QoreNumberNode *>(v); - if (!fn) +bool QoreNumberNode::is_equal_hard(const AbstractQoreNode* v, ExceptionSink* xsink) const { + if (v->getType() != NT_NUMBER) return false; - - return false; + const QoreNumberNode* n = reinterpret_cast<const QoreNumberNode*>(v); + return !priv->compare(*n->priv); } // returns the type name as a c string -const char *QoreNumberNode::getTypeName() const { +const char* QoreNumberNode::getTypeName() const { return getStaticTypeName(); } -AbstractQoreNode *QoreNumberNode::parseInit(LocalVar *oflag, int pflag, int& lvids, const QoreTypeInfo*& typeInfo) { +AbstractQoreNode* QoreNumberNode::parseInit(LocalVar* oflag, int pflag, int& lvids, const QoreTypeInfo*& typeInfo) { typeInfo = numberTypeInfo; return this; } + +bool QoreNumberNode::zero() const { + return priv->zero(); +} + +QoreNumberNode* QoreNumberNode::doPlus(const QoreNumberNode* right) const { + return new QoreNumberNode(priv->doPlus(*right->priv)); +} Modified: qore/trunk/lib/QoreString.cpp =================================================================== --- qore/trunk/lib/QoreString.cpp 2012-09-10 10:06:02 UTC (rev 5028) +++ qore/trunk/lib/QoreString.cpp 2012-09-10 21:02:42 UTC (rev 5029) @@ -1591,19 +1591,41 @@ } void QoreString::addch(char c, unsigned times) { - if (priv->allocated) { - priv->check_char(priv->len + times + STR_CLASS_BLOCK); // more data will follow the padding - memset(priv->buf + priv->len, c, times); - } else { - priv->allocated = times + STR_CLASS_BLOCK; - priv->allocated = (priv->allocated / 16 + 1) * 16; // use complete cache line - priv->buf = (char*)malloc(sizeof(char) * priv->allocated); - memset(priv->buf, c, times); - } + priv->check_char(priv->len + times); // more data will follow the padding + memset(priv->buf + priv->len, c, times); priv->len += times; priv->buf[priv->len] = 0; } +int QoreString::insertch(char c, qore_size_t pos, unsigned times) { + //printd(5, "QoreString::insertch(c: %c pos: "QLLD" times: %d) this: %p\n", c, pos, times, this); + if (pos > priv->len || !times) + return -1; + + priv->check_char(priv->len + times); // more data will follow the padding + if (pos < priv->len) + memmove(priv->buf + pos + times, priv->buf + pos, priv->len - pos); + memset(priv->buf + pos, c, times); + priv->len += times; + priv->buf[priv->len] = 0; + return 0; +} + +int QoreString::insert(const char* str, qore_size_t pos) { + if (pos > priv->len) + return -1; + + size_t sl = ::strlen(str); + + priv->check_char(priv->len + sl); // more data will follow the padding + if (pos < priv->len) + memmove(priv->buf + pos + sl, priv->buf + pos, priv->len - pos); + strncpy(priv->buf + pos, str, sl); + priv->len += sl; + priv->buf[priv->len] = 0; + return 0; +} + int QoreString::concatUnicode(unsigned code, ExceptionSink *xsink) { if (priv->charset == QCS_UTF8) { concatUTF8FromUnicode(code); Modified: qore/trunk/lib/parser.ypp =================================================================== --- qore/trunk/lib/parser.ypp 2012-09-10 10:06:02 UTC (rev 5028) +++ qore/trunk/lib/parser.ypp 2012-09-10 21:02:42 UTC (rev 5029) @@ -1188,6 +1188,7 @@ class ParseUserFunction* parsefunc; class ParseScopedUserFunction* sparsefunc; struct GVarDecl* gv; + QoreNumberNode* num; } %{ @@ -1306,6 +1307,7 @@ // tokens returning data %token <integer> INTEGER "integer value" %token <decimal> QFLOAT "floating-point value" +%token <num> NUMBER "arbitrary-precision number" %token <string> IDENTIFIER "identifier" %token <string> VAR_REF "variable reference" %token <string> BACKQUOTE "backquote expression" @@ -3145,6 +3147,7 @@ | INTEGER { $$ = new QoreBigIntNode($1); } | string { $$ = $1; } | DATETIME { $$ = $1; } + | NUMBER { $$ = $1; } ; %% Modified: qore/trunk/lib/scanner.lpp =================================================================== --- qore/trunk/lib/scanner.lpp 2012-09-10 10:06:02 UTC (rev 5028) +++ qore/trunk/lib/scanner.lpp 2012-09-10 21:02:42 UTC (rev 5029) @@ -1204,6 +1204,11 @@ cast\<{WS}*{WORD}{WS}*\> yylval->string = make_cast(yytext); return QORE_CAST; ({WORD}::)+\$\.{WORD} yylval->nscope = new NamedScope(strdup(yytext)); yylval->nscope->fixBCCall(); return BASE_CLASS_CALL; {DIGIT}+"."{DIGIT}+ yylval->decimal = strtod(yytext, 0); return QFLOAT; +{DIGIT}+[eE][+-]?{DIGIT}+ yylval->decimal = strtod(yytext, 0); return QFLOAT; +{DIGIT}+"."{DIGIT}+[eE][+-]?{DIGIT}+ yylval->decimal = strtod(yytext, 0); return QFLOAT; +{DIGIT}+"."{DIGIT}+n yylval->num = new QoreNumberNode(yytext); return NUMBER; +{DIGIT}+[eE][+-]?{DIGIT}+n yylval->num = new QoreNumberNode(yytext); return NUMBER; +{DIGIT}+"."{DIGIT}+[eE][+-]?{DIGIT}+n yylval->num = new QoreNumberNode(yytext); return NUMBER; 0[0-7]+ yylval->integer = strtoll(yytext+1, 0, 8); return INTEGER; {DIGIT}+ yylval->integer = parse_get_integer(yytext); return INTEGER; {DIGIT}+Y yylval->datetime = makeYears(strtol(yytext, 0, 10)); return DATETIME; Modified: qore/trunk/lib/thread.cpp =================================================================== --- qore/trunk/lib/thread.cpp 2012-09-10 10:06:02 UTC (rev 5028) +++ qore/trunk/lib/thread.cpp 2012-09-10 21:02:42 UTC (rev 5029) @@ -1507,6 +1507,10 @@ td->tpd->saveProgram(true); } +static void qore_thread_cleanup(void* n) { + mpfr_free_cache(); +} + // put "op_background_thread" in an unnamed namespace to make it 'static extern "C"' namespace { extern "C" void* op_background_thread(void* x) { @@ -1516,6 +1520,8 @@ printd(5, "op_background_thread() btp=%p TID %d started\n", btp, btp->tid); //printf("op_background_thread() btp=%p TID %d started\n", btp, btp->tid); + pthread_cleanup_push(qore_thread_cleanup, (void*)0); + { ExceptionSink xsink; @@ -1571,6 +1577,8 @@ } } + pthread_cleanup_pop(1); + pthread_exit(0); return 0; } This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |