--- /dev/null
+#define BOOST_TEST_MODULE cppbind
+#include <BoostTestTargetConfig.h>
+
+#include "NasalCallContext.hxx"
+
+class TestContext:
+ public nasal::CallContext
+{
+ public:
+ TestContext():
+ CallContext(naNewContext(), 0, 0)
+ {}
+
+ ~TestContext()
+ {
+ naFreeContext(c);
+ }
+
+ template<class T>
+ T from_str(const std::string& str)
+ {
+ return from_nasal<T>(to_nasal(str));
+ }
+
+ naRef exec(const std::string& code_str, nasal::Me me)
+ {
+ int err_line = -1;
+ naRef code = naParseCode( c, to_nasal("<TextContext::exec>"), 0,
+ (char*)code_str.c_str(), code_str.length(),
+ &err_line );
+ if( !naIsCode(code) )
+ throw std::runtime_error("Failed to parse code: " + code_str);
+
+ return naCallMethod(code, me, 0, 0, naNil());
+ }
+
+ template<class T>
+ T exec(const std::string& code)
+ {
+ return from_nasal<T>(exec(code, naNil()));
+ }
+
+ template<class T>
+ T convert(const std::string& str)
+ {
+ return from_nasal<T>(to_nasal(str));
+ }
+};
+
+static void runNumTests( double (TestContext::*test_double)(const std::string&),
+ int (TestContext::*test_int)(const std::string&) )
+{
+ TestContext c;
+
+ BOOST_CHECK_CLOSE((c.*test_double)("0.5"), 0.5, 1e-5);
+ BOOST_CHECK_CLOSE((c.*test_double)(".6"), 0.6, 1e-5);
+ BOOST_CHECK_CLOSE((c.*test_double)("-.7"), -0.7, 1e-5);
+ BOOST_CHECK_CLOSE((c.*test_double)("-0.8"), -0.8, 1e-5);
+ BOOST_CHECK_SMALL((c.*test_double)("0.0"), 1e-5);
+ BOOST_CHECK_SMALL((c.*test_double)("-.0"), 1e-5);
+
+ BOOST_CHECK_CLOSE((c.*test_double)("1.23e4"), 1.23e4, 1e-5);
+ BOOST_CHECK_CLOSE((c.*test_double)("1.23e-4"), 1.23e-4, 1e-5);
+ BOOST_CHECK_CLOSE((c.*test_double)("-1.23e4"), -1.23e4, 1e-5);
+ BOOST_CHECK_CLOSE((c.*test_double)("-1.23e-4"), -1.23e-4, 1e-5);
+ BOOST_CHECK_CLOSE((c.*test_double)("1e-4"), 1e-4, 1e-5);
+ BOOST_CHECK_CLOSE((c.*test_double)("-1e-4"), -1e-4, 1e-5);
+
+ BOOST_CHECK_EQUAL((c.*test_int)("123"), 123);
+ BOOST_CHECK_EQUAL((c.*test_int)("-958"), -958);
+
+ BOOST_CHECK_CLOSE((c.*test_int)("-1e7"), -1e7, 1e-5);
+ BOOST_CHECK_CLOSE((c.*test_int)("2E07"), 2e07, 1e-5);
+
+ BOOST_CHECK_EQUAL((c.*test_int)("0755"), 0755);
+ BOOST_CHECK_EQUAL((c.*test_int)("0055"), 055);
+ BOOST_CHECK_EQUAL((c.*test_int)("-0155"), -0155);
+
+ BOOST_CHECK_EQUAL((c.*test_int)("0x755"), 0x755);
+ BOOST_CHECK_EQUAL((c.*test_int)("0x055"), 0x55);
+ BOOST_CHECK_EQUAL((c.*test_int)("-0x155"), -0x155);
+}
+
+BOOST_AUTO_TEST_CASE( parse_num )
+{
+ runNumTests(&TestContext::convert<double>, &TestContext::convert<int>);
+}
+
+BOOST_AUTO_TEST_CASE( lex_num )
+{
+ runNumTests(&TestContext::exec<double>, &TestContext::exec<int>);
+}
return i+1;
}
-static int lexHexLiteral(struct Parser* p, int index)
+static int lexIntLiteral(struct Parser* p, int index, int base)
{
int nib, i = index;
double d = 0;
- while(i < p->len && (nib = hex(p->buf[i])) >= 0) {
- d = d*16 + nib;
+ while(i < p->len && (nib = hex(p->buf[i])) >= 0 && nib < base) {
+ d = d * base + nib;
i++;
}
newToken(p, index, TOK_LITERAL, 0, 0, d);
unsigned char* buf = (unsigned char*)p->buf;
double d;
- if(buf[i] == '0' && i+2<len && buf[i+1] == 'x' && ISHEX(buf[i+2]))
- return lexHexLiteral(p, index+2);
+ if(buf[i] == '0') {
+ if(i+2<len && buf[i+1] == 'x' && ISHEX(buf[i+2]))
+ return lexIntLiteral(p, index+2, 16);
+ if(i+1<len && ISNUM(buf[i+1]) )
+ return lexIntLiteral(p, index+1, 8);
+ }
while(i<len && ISNUM(buf[i])) i++;
if(i<len && buf[i] == '.') {
// remaining 67%.
////////////////////////////////////////////////////////////////////////
-// Reads an unsigned decimal out of the scalar starting at i, stores
+// TODO unify with number conversion in lex.c
+static int hex(char c)
+{
+ if(c >= '0' && c <= '9') return c - '0';
+ if(c >= 'A' && c <= 'F') return c - 'A' + 10;
+ if(c >= 'a' && c <= 'f') return c - 'a' + 10;
+ return -1;
+}
+
+// Reads an unsigned integer out of the scalar starting at i, stores
// it in v, and returns the next index to start at. Zero-length
-// decimal numbers are allowed, and are returned as zero.
-static int readdec(unsigned char* s, int len, int i, double* v)
+// integer numbers are allowed, and are returned as zero.
+static int readint(unsigned char* s, int len, int i, double* v, int base)
{
+ int val;
*v = 0;
if(i >= len) return len;
- while(i < len && s[i] >= '0' && s[i] <= '9') {
- *v= (*v) * 10 + (s[i] - '0');
+ while(i < len && (val = hex(s[i])) >= 0 && val < base) {
+ *v= (*v) * base + val;
i++;
}
return i;
// decimal numbers are allowed, and are returned as zero.
static int readsigned(unsigned char* s, int len, int i, double* v)
{
- int i0 = i, i2;
+ int i0 = i, i2, base = 10;
double sgn=1, val;
if(i >= len) { *v = 0; return len; }
if(s[i] == '+') { i++; }
else if(s[i] == '-') { i++; sgn = -1; }
- i2 = readdec(s, len, i, &val);
+ if(s[i] == '0') {
+ i++; base = 8;
+ if( i < len && s[i] == 'x' ) { i++; base = 16; }
+ }
+ i2 = readint(s, len, i, &val, base);
if(i0 == i && i2 == i) {
*v = 0;
return i0; // don't successfully parse bare "+" or "-"
// Read the fractional part, if any
if(i < len && s[i] == '.') {
i++;
- fraclen = readdec(s, len, i, &frac) - i;
+ fraclen = readint(s, len, i, &frac, 10) - i;
i += fraclen;
}