diff --git a/include/vm.h b/include/vm.h index 0f63f63..3849142 100644 --- a/include/vm.h +++ b/include/vm.h @@ -114,7 +114,16 @@ 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); +// NOTE: This can probably be merged with ain_data_type, since the values are +// disjoint. +enum string_format_type { + STRFMT_INT = 2, + STRFMT_FLOAT = 3, + STRFMT_STRING = 4, + STRFMT_BOOL = 48, + STRFMT_LONG_INT = 56, +}; +struct string *string_format(struct string *fmt, union vm_value arg, enum string_format_type type); void vm_stack_trace(void); _Noreturn void _vm_error(const char *fmt, ...); diff --git a/src/format.c b/src/format.c index 052dc6c..b167073 100644 --- a/src/format.c +++ b/src/format.c @@ -37,10 +37,17 @@ struct fmt_spec { enum fmt_type type; int precision; int padding; - bool zero_pad; + bool zero_pad; bool zenkaku; }; +static inline bool is_integer_type(enum string_format_type t) +{ + return t == STRFMT_INT + || t == STRFMT_BOOL + || t == STRFMT_LONG_INT; +} + static int read_number(const char **_fmt) { int n = 0; @@ -54,7 +61,7 @@ static int read_number(const char **_fmt) return n; } -static bool parse_fmt_spec(const char **_fmt, struct fmt_spec *spec, enum ain_data_type target) +static bool parse_fmt_spec(const char **_fmt, struct fmt_spec *spec, enum string_format_type target) { bool r = false; const char *fmt = (*_fmt) + 1; @@ -64,33 +71,33 @@ static bool parse_fmt_spec(const char **_fmt, struct fmt_spec *spec, enum ain_da switch (*fmt) { case 'd': spec->type = FMT_INT; - r = target == AIN_INT; + r = is_integer_type(target); goto end; case 'D': spec->type = FMT_INT; spec->zenkaku = true; - r = target == AIN_INT; + r = is_integer_type(target); goto end; case 'f': spec->type = FMT_FLOAT; - r = target == AIN_FLOAT; + r = target == STRFMT_FLOAT; goto end; case 'F': spec->type = FMT_FLOAT; spec->zenkaku = true; - r = target == AIN_FLOAT; + r = target == STRFMT_FLOAT; goto end; case 's': spec->type = FMT_STRING; - r = target == AIN_STRING; + r = target == STRFMT_STRING; goto end; case 'c': spec->type = FMT_CHAR; - r = target == AIN_INT; + r = is_integer_type(target); goto end; case 'b': spec->type = FMT_BOOL; - r = target == AIN_INT; + r = is_integer_type(target); goto end; case '0': spec->zero_pad = true; @@ -154,9 +161,8 @@ 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, enum ain_data_type type) +struct string *string_format(struct string *fmt, union vm_value arg, enum string_format_type type) { - struct string *out = string_ref(&EMPTY_STRING); for (const char *s = fmt->text; *s; s++) { if (*s != '%') continue; @@ -164,11 +170,12 @@ struct string *string_format(struct string *fmt, union vm_value arg, enum ain_da size_t size = s - fmt->text; struct fmt_spec spec; if (parse_fmt_spec(&s, &spec, type)) { + struct string *out = string_ref(&EMPTY_STRING); string_append_cstr(&out, fmt->text, size); append_fmt(&out, &spec, arg); string_append_cstr(&out, s, strlen(s)); - break; + return out; } } - return out; + return string_ref(fmt); } diff --git a/src/hll/DrawDungeon.c b/src/hll/DrawDungeon.c index 20c3a4c..2c4a5e1 100644 --- a/src/hll/DrawDungeon.c +++ b/src/hll/DrawDungeon.c @@ -413,7 +413,7 @@ static void DrawDungeon14_SetRasterScroll(int surface, int type) { struct dungeon_context *ctx = dungeon_get_context(surface); if (!ctx || !ctx->renderer) - return true; + return; return dungeon_renderer_set_raster_scroll(ctx->renderer, type); } @@ -421,7 +421,7 @@ static void DrawDungeon14_SetRasterAmp(int surface, float amp) { struct dungeon_context *ctx = dungeon_get_context(surface); if (!ctx || !ctx->renderer) - return true; + return; return dungeon_renderer_set_raster_amp(ctx->renderer, amp); } diff --git a/src/parts/parts.c b/src/parts/parts.c index 6c4a0a4..ad9ad26 100644 --- a/src/parts/parts.c +++ b/src/parts/parts.c @@ -1008,7 +1008,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}, AIN_INT); + struct string *cg_name = string_format((struct string*)data, (union vm_value){.i=no}, STRFMT_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 807e9b8..5498784 100644 --- a/src/vm.c +++ b/src/vm.c @@ -1532,7 +1532,7 @@ static enum opcode execute_instruction(enum opcode opcode) 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, type + 8); + heap[dst].s = string_format(heap[fmt].s, val, type); heap_unref(fmt); stack_push(dst); break; diff --git a/test/Source/strings.jaf b/test/Source/strings.jaf index 98c2904..144220a 100755 --- a/test/Source/strings.jaf +++ b/test/Source/strings.jaf @@ -5,6 +5,7 @@ void test_strings(void) int i; float f; string s; + bool b; test_bool("\"a\" == \"a\"", "a" == "a", true); test_bool("\"a\" != \"b\"", "a" == "b", false); test_bool("\"a\" < \"b\"", "a" < "b", true); @@ -86,8 +87,10 @@ void test_strings(void) // char test_string("abc%cdef % '‚ '", "abc%cdef" % '‚ ', "abc‚ def"); // bool - test_string("abc%bdef % 1", "abc%bdef" % 1, "abctruedef"); - test_string("abc%bdef % 0", "abc%bdef" % 0, "abcfalsedef"); + test_string("abc%bdef % 1", "abc%bdef" % (b = 1), "abctruedef"); + test_string("abc%bdef % 0", "abc%bdef" % (b = 0), "abcfalsedef"); + // type mismatch + test_string("%s % 42", "%s" % 42, "%s"); // I_STRING test_bool("(42).String()", (i = 42, i.String() == "42"), true);