diff --git a/src/common/sstream.c b/src/common/sstream.c index aabdd6ab..336a65cb 100644 --- a/src/common/sstream.c +++ b/src/common/sstream.c @@ -7,6 +7,7 @@ #include #include #include +#include #include void c11_sbuf__ctor(c11_sbuf* self) { @@ -53,21 +54,23 @@ void c11_sbuf__write_f64(c11_sbuf* self, double val, int precision) { char b[32]; int size; if(precision < 0) { - int prec = 17 - 1; // std::numeric_limits::max_digits10 == 17 - size = snprintf(b, sizeof(b), "%.*g", prec, val); - } else { - int prec = precision; - size = snprintf(b, sizeof(b), "%.*f", prec, val); - } - c11_sbuf__write_cstr(self, b); - bool all_is_digit = true; - for(int i = 1; i < size; i++) { - if(!isdigit(b[i])) { - all_is_digit = false; - break; + size = snprintf(b, sizeof(b), "%.*g", 15, val); + if(strtod(b, NULL) != val) { + size = snprintf(b, sizeof(b), "%.*g", 17, val); } + c11_sbuf__write_cstr(self, b); + bool all_is_digit = true; + for(int i = 1; i < size; i++) { + if(!isdigit(b[i])) { + all_is_digit = false; + break; + } + } + if(all_is_digit) c11_sbuf__write_cstr(self, ".0"); + } else { + size = snprintf(b, sizeof(b), "%.*f", precision, val); + c11_sbuf__write_cstr(self, b); } - if(all_is_digit) c11_sbuf__write_cstr(self, ".0"); } void c11_sbuf__write_sv(c11_sbuf* self, c11_sv sv) { diff --git a/src/compiler/lexer.c b/src/compiler/lexer.c index bbedf6fc..0d6bedef 100644 --- a/src/compiler/lexer.c +++ b/src/compiler/lexer.c @@ -37,16 +37,24 @@ static void Lexer__dtor(Lexer* self) { c11_vector__dtor(&self->indents); } +static const char* lexer_source_end(Lexer* self) { + return self->src->source->data + self->src->source->size; +} + static char eatchar(Lexer* self) { + const char* end = lexer_source_end(self); + if(self->curr_char > end) return '\0'; char c = *self->curr_char; assert(c != '\n'); // eatchar() cannot consume a newline - self->curr_char++; + self->curr_char = (self->curr_char < end) ? self->curr_char + 1 : end + 1; return c; } static char eatchar_include_newline(Lexer* self) { + const char* end = lexer_source_end(self); + if(self->curr_char > end) return '\0'; char c = *self->curr_char; - self->curr_char++; + self->curr_char = (self->curr_char < end) ? self->curr_char + 1 : end + 1; if(c == '\n') { self->current_line++; c11_vector__push(const char*, &self->src->line_starts, self->curr_char); @@ -189,7 +197,8 @@ static Error* LexerError(Lexer* self, const char* fmt, ...) { err->src = self->src; PK_INCREF(self->src); err->lineno = self->current_line; - if(*self->curr_char == '\n') { err->lineno--; } + const char* end = lexer_source_end(self); + if(self->curr_char <= end && *self->curr_char == '\n') { err->lineno--; } va_list args; va_start(args, fmt); vsnprintf(err->msg, sizeof(err->msg), fmt, args); diff --git a/src/modules/json.c b/src/modules/json.c index 181d4aff..fca273f6 100644 --- a/src/modules/json.c +++ b/src/modules/json.c @@ -102,7 +102,7 @@ static bool json__write_namedict_kv(py_Name k, py_Ref v, void* ctx_) { static bool json__write_object(c11_sbuf* buf, py_TValue* obj, int indent, int depth) { switch(obj->type) { case tp_NoneType: c11_sbuf__write_cstr(buf, "null"); return true; - case tp_int: c11_sbuf__write_int(buf, obj->_i64); return true; + case tp_int: c11_sbuf__write_i64(buf, obj->_i64); return true; case tp_float: { if(dmath_isnan(obj->_f64)) { c11_sbuf__write_cstr(buf, "NaN"); diff --git a/src/public/PyList.c b/src/public/PyList.c index a30c412d..88f2c843 100644 --- a/src/public/PyList.c +++ b/src/public/PyList.c @@ -384,7 +384,10 @@ static bool list_insert(int argc, py_Ref argv) { return true; } -static int lt_with_key(py_TValue* a, py_TValue* b, py_TValue* key) { +static int lt_with_key(const void* a_, const void* b_, void* extra) { + py_TValue* a = (py_TValue*)a_; + py_TValue* b = (py_TValue*)b_; + py_TValue* key = (py_TValue*)extra; if(!key) return py_less(a, b); VM* vm = pk_current_vm; // project a @@ -416,7 +419,7 @@ static bool list_sort(int argc, py_Ref argv) { bool ok = c11__stable_sort(self->data, self->length, sizeof(py_TValue), - (int (*)(const void*, const void*, void*))lt_with_key, + lt_with_key, key); if(!ok) return false; diff --git a/tests/250_rfstring.py b/tests/250_rfstring.py index 5b687bd6..d2f93ed8 100644 --- a/tests/250_rfstring.py +++ b/tests/250_rfstring.py @@ -64,6 +64,7 @@ assert f'{a:010f}' == '010.000000' assert f'{a:010.2f}' == '0000010.00' assert f'{a:.2f}' == '10.00' assert f'{a:.5f}' == '10.00000' +assert f'{2.5:.0f}' == '2' b = '123' assert f'{b:10}' == '123 ' diff --git a/tests/660_eval.py b/tests/660_eval.py index 93c3e7a5..f0a88fc0 100644 --- a/tests/660_eval.py +++ b/tests/660_eval.py @@ -75,4 +75,11 @@ assert res == [42, 42] assert x == 33 # test removing trailing newlines -assert eval('[1, 2, 3]\n \n') == [1, 2, 3] \ No newline at end of file +assert eval('[1, 2, 3]\n \n') == [1, 2, 3] + +# lexer doesn't read past NUL on error at end of input +try: + eval('"\\x4') + exit(1) +except SyntaxError: + pass \ No newline at end of file diff --git a/tests/721_json.py b/tests/721_json.py index 29d168bc..8509d02b 100644 --- a/tests/721_json.py +++ b/tests/721_json.py @@ -48,6 +48,9 @@ _j = json.dumps(c) _c = json.loads(_j) assert c == _c +assert json.dumps(9223372036854775807) == '9223372036854775807' +assert json.loads(json.dumps(0.1 + 0.2)) == 0.1 + 0.2 + d = True _j = json.dumps(d) _d = json.loads(_j)