blueloveTH 1 год назад
Родитель
Сommit
6befe661b7
6 измененных файлов с 155 добавлено и 131 удалено
  1. 3 53
      include/pocketpy/common/sstream.h
  2. 16 4
      include/pocketpy/pocketpy.h
  3. 26 15
      src/common/sourcedata.c
  4. 102 57
      src/common/sstream.c
  5. 1 1
      src/compiler/lexer.c
  6. 7 1
      src/public/vm.c

+ 3 - 53
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
 }

+ 16 - 4
include/pocketpy/pocketpy.h

@@ -2,6 +2,7 @@
 
 #include <stdint.h>
 #include <stdbool.h>
+#include <stdarg.h>
 
 /************* 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

+ 26 - 15
src/common/sourcedata.c

@@ -5,10 +5,10 @@
 #include <string.h>
 
 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<self->_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 ");

+ 102 - 57
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 <stdarg.h>
 #include <stdio.h>
 #include <assert.h>
 #include <ctype.h>
 #include <math.h>
 
-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;
 }

+ 1 - 1
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');

+ 7 - 1
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);
-}
+}