diff --git a/include/pocketpy/common/sstream.h b/include/pocketpy/common/sstream.h index cf79ad47..b679f80f 100644 --- a/include/pocketpy/common/sstream.h +++ b/include/pocketpy/common/sstream.h @@ -14,39 +14,13 @@ typedef struct pk_SStream { c11_vector data; } pk_SStream; -typedef struct pk_AnyStr { - int type; - union { - int _int; - int64_t _i64; - float _float; - double _double; - char _char; - const py_Str* _str; - c11_string _sv; - const char* _cstr; - void* _ptr; - }; -} pk_AnyStr; - -PK_INLINE pk_AnyStr pk_AnyStr__int(int x) { pk_AnyStr s; s.type = 1; s._int = x; return s; } -PK_INLINE pk_AnyStr pk_AnyStr__i64(int64_t x) { pk_AnyStr s; s.type = 2; s._i64 = x; return s; } -PK_INLINE pk_AnyStr pk_AnyStr__float(float x) { pk_AnyStr s; s.type = 3; s._float = x; return s; } -PK_INLINE pk_AnyStr pk_AnyStr__double(double x) { pk_AnyStr s; s.type = 4; s._double = x; return s; } -PK_INLINE pk_AnyStr pk_AnyStr__char(char x) { pk_AnyStr s; s.type = 5; s._char = x; return s; } -PK_INLINE pk_AnyStr pk_AnyStr__str(const py_Str* x) { pk_AnyStr s; s.type = 6; s._str = x; return s; } -PK_INLINE pk_AnyStr pk_AnyStr__sv(c11_string x) { pk_AnyStr s; s.type = 7; s._sv = x; return s; } -PK_INLINE pk_AnyStr pk_AnyStr__cstr(const char* x) { pk_AnyStr s; s.type = 8; s._cstr = x; return s; } -PK_INLINE pk_AnyStr pk_AnyStr__ptr(void* x) { pk_AnyStr s; s.type = 9; s._ptr = x; return s; } - void pk_SStream__ctor(pk_SStream* self); void pk_SStream__ctor2(pk_SStream* self, int capacity); void pk_SStream__dtor(pk_SStream* self); void pk_SStream__write_int(pk_SStream* self, int); void pk_SStream__write_i64(pk_SStream* self, int64_t); -void pk_SStream__write_float(pk_SStream* self, float, int precision); -void pk_SStream__write_double(pk_SStream* self, double, int precision); +void pk_SStream__write_f64(pk_SStream* self, double, int precision); void pk_SStream__write_char(pk_SStream* self, char); void pk_SStream__write_Str(pk_SStream* self, const py_Str*); void pk_SStream__write_sv(pk_SStream* self, c11_string); @@ -54,35 +28,11 @@ void pk_SStream__write_cstr(pk_SStream* self, const char*); void pk_SStream__write_cstrn(pk_SStream* self, const char*, int); void pk_SStream__write_hex(pk_SStream* self, unsigned char, bool non_zero); void pk_SStream__write_ptr(pk_SStream* self, void*); - -void pk_SStream__write_any(pk_SStream* self, const char* fmt, const pk_AnyStr* args, int n); -const char* pk_format_any(const char* fmt, const pk_AnyStr* args, int n); - // Submit the stream and return the final string. The stream becomes invalid after this call py_Str pk_SStream__submit(pk_SStream* self); -#define pk__anystr(x) _Generic((x), \ - int: pk_AnyStr__int, \ - int64_t: pk_AnyStr__i64, \ - float: pk_AnyStr__float, \ - double: pk_AnyStr__double, \ - char: pk_AnyStr__char, \ - const py_Str*: pk_AnyStr__str, \ - c11_string: pk_AnyStr__sv, \ - const char*: pk_AnyStr__cstr, \ - void*: pk_AnyStr__ptr \ -)(x) - -#define pk__anystr_list_1(a) (pk_AnyStr[]){pk__anystr(a)}, 1 -#define pk__anystr_list_2(a, b) (pk_AnyStr[]){pk__anystr(a), pk__anystr(b)}, 2 -#define pk__anystr_list_3(a, b, c) (pk_AnyStr[]){pk__anystr(a), pk__anystr(b), pk__anystr(c)}, 3 -#define pk__anystr_list_4(a, b, c, d) (pk_AnyStr[]){pk__anystr(a), pk__anystr(b), pk__anystr(c), pk__anystr(d)}, 4 - -#define pk__anystr_list_dispatcher(...) PK_NARGS_SEQ(__VA_ARGS__, pk__anystr_list_4, pk__anystr_list_3, pk__anystr_list_2, pk__anystr_list_1, 0) -#define pk__anystr_list(...) pk__anystr_list_dispatcher(__VA_ARGS__)(__VA_ARGS__) - -#define pk_SStream__write(self, fmt, ...) pk_SStream__write_any(self, fmt, pk__anystr_list(__VA_ARGS__)) -#define pk_format(fmt, ...) pk_format_any(fmt, pk__anystr_list(__VA_ARGS__)) +void pk_vsprintf(pk_SStream* ss, const char* fmt, va_list args); +void pk_sprintf(pk_SStream* ss, const char* fmt, ...); #ifdef __cplusplus } diff --git a/include/pocketpy/pocketpy.h b/include/pocketpy/pocketpy.h index 889bd05a..93e3bdf1 100644 --- a/include/pocketpy/pocketpy.h +++ b/include/pocketpy/pocketpy.h @@ -2,6 +2,7 @@ #include #include +#include /************* Public Types *************/ typedef struct py_TValue py_TValue; @@ -141,7 +142,6 @@ void py_bindmethod2(py_Type type, const char* name, py_CFunction f, BindType bt) void py_bindnativefunc(py_Ref obj, const char* name, py_CFunction f); /// Get the reference to the i-th register. -/// @lifespan: Permanent. py_GlobalRef py_reg(int i); /// Get the reference of the object's `__dict__`. @@ -302,14 +302,26 @@ typedef struct pk_TypeInfo pk_TypeInfo; pk_TypeInfo* pk_tpinfo(const py_Ref self); /// Search the magic method from the given type to the base type. -/// Returns the reference or NULL if not found. -/// @lifespan: Permanent. +/// Return the reference or NULL if not found. py_GlobalRef py_tpfindmagic(py_Type, py_Name name); /// Get the type object of the given type. -/// @lifespan: Permanent. py_GlobalRef py_tpobject(py_Type type); +/// Get the type name. +const char* py_tpname(py_Type type); + +/// Python favored string formatting. +/// %d: int +/// %i: py_i64 (int64_t) +/// %f: py_f64 (double) +/// %s: const char* +/// %c: char +/// %p: void* +/// %t: py_Type +/// %n: py_Name +const char* py_fmt(const char* fmt, ...); + #define MAGIC_METHOD(x) extern uint16_t x; #include "pocketpy/xmacros/magics.h" #undef MAGIC_METHOD diff --git a/src/common/sourcedata.c b/src/common/sourcedata.c index bd2719c3..fdd1bcbb 100644 --- a/src/common/sourcedata.c +++ b/src/common/sourcedata.c @@ -5,10 +5,10 @@ #include static void pk_SourceData__ctor(struct pk_SourceData* self, - const char* source, - const char* filename, - enum CompileMode mode, - bool is_dynamic) { + const char* source, + const char* filename, + enum CompileMode mode, + bool is_dynamic) { py_Str__ctor(&self->filename, filename); self->mode = mode; c11_vector__ctor(&self->line_starts, sizeof(const char*)); @@ -19,7 +19,7 @@ static void pk_SourceData__ctor(struct pk_SourceData* self, // Drop all '\r' pk_SStream ss; pk_SStream__ctor(&ss); - while(true){ + while(true) { char c = *source; if(c == '\0') break; if(c != '\r') pk_SStream__write_char(&ss, c); @@ -36,21 +36,27 @@ static void pk_SourceData__dtor(struct pk_SourceData* self) { py_Str__dtor(&self->source); c11_vector__dtor(&self->line_starts); - for(int i=0; i_precompiled_tokens.count; i++){ + for(int i = 0; i < self->_precompiled_tokens.count; i++) { py_Str__dtor(c11__at(py_Str, &self->_precompiled_tokens, i)); } c11_vector__dtor(&self->_precompiled_tokens); } -pk_SourceData_ pk_SourceData__rcnew(const char* source, const char* filename, enum CompileMode mode, bool is_dynamic) { +pk_SourceData_ pk_SourceData__rcnew(const char* source, + const char* filename, + enum CompileMode mode, + bool is_dynamic) { pk_SourceData_ self = malloc(sizeof(struct pk_SourceData)); pk_SourceData__ctor(self, source, filename, mode, is_dynamic); self->rc.count = 1; - self->rc.dtor = (void(*)(void*))pk_SourceData__dtor; + self->rc.dtor = (void (*)(void*))pk_SourceData__dtor; return self; } -bool pk_SourceData__get_line(const struct pk_SourceData* self, int lineno, const char** st, const char** ed) { +bool pk_SourceData__get_line(const struct pk_SourceData* self, + int lineno, + const char** st, + const char** ed) { if(self->is_precompiled || lineno == -1) { return false; } lineno -= 1; if(lineno < 0) lineno = 0; @@ -64,7 +70,10 @@ bool pk_SourceData__get_line(const struct pk_SourceData* self, int lineno, const return true; } -py_Str pk_SourceData__snapshot(const struct pk_SourceData* self, int lineno, const char* cursor, const char* name) { +py_Str pk_SourceData__snapshot(const struct pk_SourceData* self, + int lineno, + const char* cursor, + const char* name) { pk_SStream ss; pk_SStream__ctor(&ss); @@ -73,11 +82,13 @@ py_Str pk_SourceData__snapshot(const struct pk_SourceData* self, int lineno, con // pk_SStream__write_cstr(&ss, "\", line "); // pk_SStream__write_int(&ss, lineno); - pk_SStream__write(&ss, - " File \"{}\", line {}", - &self->filename, - lineno - ); + // pk_SStream__write(&ss, + // " File \"{}\", line {}", + // &self->filename, + // lineno + // ); + + pk_sprintf(&ss, " File \"%S\", line %d", &self->filename, lineno); if(name && *name) { pk_SStream__write_cstr(&ss, ", in "); diff --git a/src/common/sstream.c b/src/common/sstream.c index 8a6dcdb8..f6a66bc0 100644 --- a/src/common/sstream.c +++ b/src/common/sstream.c @@ -1,31 +1,27 @@ #include "pocketpy/common/sstream.h" #include "pocketpy/common/config.h" #include "pocketpy/common/utils.h" +#include "pocketpy/pocketpy.h" +#include #include #include #include #include -void pk_SStream__ctor(pk_SStream* self) { - c11_vector__ctor(&self->data, sizeof(char)); -} +void pk_SStream__ctor(pk_SStream* self) { c11_vector__ctor(&self->data, sizeof(char)); } void pk_SStream__ctor2(pk_SStream* self, int capacity) { c11_vector__ctor(&self->data, sizeof(char)); c11_vector__reserve(&self->data, capacity); } -void pk_SStream__dtor(pk_SStream* self) { - c11_vector__dtor(&self->data); -} +void pk_SStream__dtor(pk_SStream* self) { c11_vector__dtor(&self->data); } -void pk_SStream__write_char(pk_SStream* self, char c) { - c11_vector__push(char, &self->data, c); -} +void pk_SStream__write_char(pk_SStream* self, char c) { c11_vector__push(char, &self->data, c); } void pk_SStream__write_int(pk_SStream* self, int i) { - char buf[12]; // sign + 10 digits + null terminator + char buf[12]; // sign + 10 digits + null terminator snprintf(buf, sizeof(buf), "%d", i); pk_SStream__write_cstr(self, buf); } @@ -34,16 +30,16 @@ void pk_SStream__write_i64(pk_SStream* self, int64_t val) { // sign + 21 digits + null terminator // str(-2**64).__len__() == 21 c11_vector__reserve(&self->data, self->data.count + 23); - if(val == 0){ + if(val == 0) { pk_SStream__write_char(self, '0'); return; } - if(val < 0){ + if(val < 0) { pk_SStream__write_char(self, '-'); val = -val; } int start = self->data.count; - while(val){ + while(val) { c11_vector__push(char, &self->data, '0' + val % 10); val /= 10; } @@ -51,11 +47,7 @@ void pk_SStream__write_i64(pk_SStream* self, int64_t val) { c11_vector__reverse(char, &self->data, start, end); } -void pk_SStream__write_float(pk_SStream* self, float val, int precision){ - pk_SStream__write_double(self, val, precision); -} - -void pk_SStream__write_double(pk_SStream* self, double val, int precision){ +void pk_SStream__write_f64(pk_SStream* self, double val, int precision) { if(isinf(val)) { pk_SStream__write_cstr(self, val > 0 ? "inf" : "-inf"); return; @@ -75,8 +67,11 @@ void pk_SStream__write_double(pk_SStream* self, double val, int precision){ } pk_SStream__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; } + for(int i = 1; i < size; i++) { + if(!isdigit(b[i])) { + all_is_digit = false; + break; + } } if(all_is_digit) pk_SStream__write_cstr(self, ".0"); } @@ -124,53 +119,103 @@ void pk_SStream__write_ptr(pk_SStream* self, void* p) { } } -void pk_SStream__write_any(pk_SStream* self, const char* fmt, const pk_AnyStr* args, int n){ - int i = 0; - while(*fmt){ - if(*fmt == '{' && fmt[1] == '}'){ - assert(i < n); - switch(args[i].type){ - case 1: pk_SStream__write_int(self, args[i]._int); break; - case 2: pk_SStream__write_i64(self, args[i]._i64); break; - case 3: pk_SStream__write_float(self, args[i]._float, -1); break; - case 4: pk_SStream__write_double(self, args[i]._double, -1); break; - case 5: pk_SStream__write_char(self, args[i]._char); break; - case 6: pk_SStream__write_Str(self, args[i]._str); break; - case 7: pk_SStream__write_sv(self, args[i]._sv); break; - case 8: pk_SStream__write_cstr(self, args[i]._cstr); break; - case 9: pk_SStream__write_ptr(self, args[i]._ptr); break; - default: assert(0); break; - } - fmt += 2; - i++; - }else{ - pk_SStream__write_char(self, *fmt); - fmt++; - } - } -} - py_Str pk_SStream__submit(pk_SStream* self) { c11_vector__push(char, &self->data, '\0'); c11_array a = c11_vector__submit(&self->data); // TODO: optimize c11__isascii - py_Str retval = { - .size = a.count - 1, - .is_ascii = c11__isascii((char*)a.data, a.count), - .is_sso = false, - ._ptr = (char*)a.data - }; + py_Str retval = {.size = a.count - 1, + .is_ascii = c11__isascii((char*)a.data, a.count), + .is_sso = false, + ._ptr = (char*)a.data}; return retval; } -const char* pk_format_any(const char* fmt, const pk_AnyStr* args, int n){ +void pk_vsprintf(pk_SStream* ss, const char* fmt, va_list args) { + while(fmt) { + char c = *fmt; + if(c != '%') { + pk_SStream__write_char(ss, c); + fmt++; + continue; + } + + fmt++; + c = *fmt; + + switch(c) { + case 'd': { + int i = va_arg(args, int); + pk_SStream__write_int(ss, i); + break; + } + case 'i': { + int64_t i = va_arg(args, int64_t); + pk_SStream__write_i64(ss, i); + break; + } + case 'f': { + double d = va_arg(args, double); + pk_SStream__write_f64(ss, d, -1); + break; + } + case 's': { + const char* s = va_arg(args, const char*); + pk_SStream__write_cstr(ss, s); + break; + } + case 'S': { + const py_Str* s = va_arg(args, const py_Str*); + pk_SStream__write_Str(ss, s); + break; + } + case 'c': { + char c = va_arg(args, int); + pk_SStream__write_char(ss, c); + break; + } + case 'p': { + void* p = va_arg(args, void*); + pk_SStream__write_ptr(ss, p); + break; + } + case 't': { + py_Type t = va_arg(args, int); + pk_SStream__write_cstr(ss, py_tpname(t)); + break; + } + case 'n': { + py_Name n = va_arg(args, int); + pk_SStream__write_cstr(ss, py_name2str(n)); + break; + } + case '%': pk_SStream__write_char(ss, '%'); break; + default: + pk_SStream__write_char(ss, c); + assert(false); // invalid format + break; + } + fmt++; + } +} + +void pk_sprintf(pk_SStream* ss, const char* fmt, ...) { + va_list args; + va_start(args, fmt); + pk_vsprintf(ss, fmt, args); + va_end(args); +} + +const char* py_fmt(const char* fmt, ...) { PK_THREAD_LOCAL pk_SStream ss; - if(ss.data.elem_size == 0){ - pk_SStream__ctor2(&ss, 128); - }else{ + if(ss.data.elem_size == 0) { + pk_SStream__ctor2(&ss, 256); + } else { c11_vector__clear(&ss.data); } - pk_SStream__write_any(&ss, fmt, args, n); + va_list args; + va_start(args, fmt); + pk_vsprintf(&ss, fmt, args); + va_end(args); pk_SStream__write_char(&ss, '\0'); return (const char*)ss.data.data; } diff --git a/src/compiler/lexer.c b/src/compiler/lexer.c index 0fa80106..1c8f2d46 100644 --- a/src/compiler/lexer.c +++ b/src/compiler/lexer.c @@ -823,7 +823,7 @@ Error* pk_Lexer__process_and_dump(pk_SourceData_ src, py_Str* out) { break; case TokenValue_F64: pk_SStream__write_char(&ss, 'F'); - pk_SStream__write_float(&ss, token->value._f64, -1); + pk_SStream__write_f64(&ss, token->value._f64, -1); break; case TokenValue_STR: { pk_SStream__write_char(&ss, 'S'); diff --git a/src/public/vm.c b/src/public/vm.c index 19316d27..41910e28 100644 --- a/src/public/vm.c +++ b/src/public/vm.c @@ -87,6 +87,12 @@ py_Ref py_tpobject(py_Type type) { return &c11__at(pk_TypeInfo, &vm->types, type)->self; } +const char* py_tpname(py_Type type) { + pk_VM* vm = pk_current_vm; + py_Name name = c11__at(pk_TypeInfo, &vm->types, type)->name; + return py_name2str(name); +} + bool py_callmagic(py_Name name, int argc, py_Ref argv) { assert(argc >= 1); assert(py_ismagicname(name)); @@ -94,4 +100,4 @@ bool py_callmagic(py_Name name, int argc, py_Ref argv) { if(!tmp) return TypeError(name); if(tmp->type == tp_nativefunc) return tmp->_cfunc(argc, argv); return py_call(tmp, argc, argv); -} \ No newline at end of file +}