diff --git a/include/vm.h b/include/vm.h index 71abbe6..b1bca0c 100644 --- a/include/vm.h +++ b/include/vm.h @@ -113,6 +113,8 @@ bool library_function_exists(int libno, int fno); void init_libraries(void); void exit_libraries(void); +struct string *string_format(struct string *fmt, union vm_value arg, enum ain_data_type type); + void vm_stack_trace(void); _Noreturn void _vm_error(const char *fmt, ...); _Noreturn void vm_exit(int code); diff --git a/src/format.c b/src/format.c index 686a8c0..052dc6c 100644 --- a/src/format.c +++ b/src/format.c @@ -17,6 +17,7 @@ #include #include #include "system4.h" +#include "system4/ain.h" #include "system4/string.h" #include "vm.h" #include "vm/heap.h" @@ -53,35 +54,43 @@ static int read_number(const char **_fmt) return n; } -static void parse_fmt_spec(const char **_fmt, struct fmt_spec *spec) +static bool parse_fmt_spec(const char **_fmt, struct fmt_spec *spec, enum ain_data_type target) { - const char *fmt = *_fmt; + bool r = false; + const char *fmt = (*_fmt) + 1; memset(spec, 0, sizeof(struct fmt_spec)); spec->precision = 6; while (*fmt) { switch (*fmt) { case 'd': spec->type = FMT_INT; + r = target == AIN_INT; goto end; case 'D': spec->type = FMT_INT; spec->zenkaku = true; + r = target == AIN_INT; goto end; case 'f': spec->type = FMT_FLOAT; + r = target == AIN_FLOAT; goto end; case 'F': spec->type = FMT_FLOAT; spec->zenkaku = true; + r = target == AIN_FLOAT; goto end; case 's': spec->type = FMT_STRING; + r = target == AIN_STRING; goto end; case 'c': spec->type = FMT_CHAR; + r = target == AIN_INT; goto end; case 'b': spec->type = FMT_BOOL; + r = target == AIN_INT; goto end; case '0': spec->zero_pad = true; @@ -109,7 +118,9 @@ static void parse_fmt_spec(const char **_fmt, struct fmt_spec *spec) warn: WARNING("Invalid format specifier: %s", *_fmt); end: - *_fmt = ++fmt; + if (r) + *_fmt = ++fmt; + return r; } static void append_fmt(struct string **s, struct fmt_spec *spec, union vm_value arg) @@ -128,7 +139,7 @@ static void append_fmt(struct string **s, struct fmt_spec *spec, union vm_value string_append_cstr(s, buf, len); break; case FMT_STRING: - string_append(s, heap[arg.i].s); + string_append(s, heap_get_string(arg.i)); heap_unref(arg.i); break; case FMT_CHAR: @@ -143,15 +154,17 @@ static void append_fmt(struct string **s, struct fmt_spec *spec, union vm_value } } -struct string *string_format(struct string *fmt, union vm_value arg) +struct string *string_format(struct string *fmt, union vm_value arg, enum ain_data_type type) { struct string *out = string_ref(&EMPTY_STRING); for (const char *s = fmt->text; *s; s++) { - if (*s == '%') { - struct fmt_spec spec; - string_append_cstr(&out, fmt->text, s - fmt->text); - s++; - parse_fmt_spec(&s, &spec); + if (*s != '%') + continue; + + size_t size = s - fmt->text; + struct fmt_spec spec; + if (parse_fmt_spec(&s, &spec, type)) { + string_append_cstr(&out, fmt->text, size); append_fmt(&out, &spec, arg); string_append_cstr(&out, s, strlen(s)); break; diff --git a/src/parts/parts.c b/src/parts/parts.c index 3e7e5eb..de9b7a7 100644 --- a/src/parts/parts.c +++ b/src/parts/parts.c @@ -960,7 +960,7 @@ bool PE_SetLoopCG_by_index(int parts_no, int cg_no, int nr_frames, int frame_tim static struct cg *load_loop_cg_by_name(int no, void *data) { int unused_no; - struct string *cg_name = string_format((struct string*)data, (union vm_value){.i=no}); + struct string *cg_name = string_format((struct string*)data, (union vm_value){.i=no}, AIN_INT); struct cg *cg = asset_cg_load_by_name(cg_name->text, &unused_no); free_string(cg_name); return cg; diff --git a/src/vm.c b/src/vm.c index 94e2619..78131ef 100644 --- a/src/vm.c +++ b/src/vm.c @@ -1499,11 +1499,11 @@ static enum opcode execute_instruction(enum opcode opcode) break; } case S_MOD: { - stack_pop(); // ??? + int type = stack_pop().i; union vm_value val = stack_pop(); int fmt = stack_pop().i; int dst = heap_alloc_slot(VM_STRING); - heap[dst].s = string_format(heap[fmt].s, val); + heap[dst].s = string_format(heap[fmt].s, val, type + 8); heap_unref(fmt); stack_push(dst); break; diff --git a/subprojects/libsys4 b/subprojects/libsys4 index 863bd9d..95ce167 160000 --- a/subprojects/libsys4 +++ b/subprojects/libsys4 @@ -1 +1 @@ -Subproject commit 863bd9d332d74fc843b0b5f8b26f774db1ab8d7b +Subproject commit 95ce167a93fcc3348431583d2f7f0b3637b12f79 diff --git a/test/Source/strings.jaf b/test/Source/strings.jaf index b7aef4e..98c2904 100755 --- a/test/Source/strings.jaf +++ b/test/Source/strings.jaf @@ -73,6 +73,7 @@ void test_strings(void) test_string("abc%4Ddef % 42", "abc%4Ddef" % 42, "abc@@‚S‚Qdef"); test_string("abc%04Ddef % 42", "abc%04Ddef" % 42, "abc‚O‚O‚S‚Qdef"); test_string("\"%d %d\" % 42 % 43", "%d %d" % 42 % 43, "42 43"); + test_string("%s %d % 42", "%s %d" % 42, "%s 42"); // float test_string("abc%fdef % 12.3", "abc%fdef" % 12.3, "abc12.300000def"); test_string("abc%.2fdef % 12.3", "abc%.2fdef" % 12.3, "abc12.30def");