From ec3d2a23dad91b8cb4884ed1ec8cf507155e79f2 Mon Sep 17 00:00:00 2001 From: luboslenco Date: Tue, 5 May 2026 08:56:14 +0200 Subject: [PATCH] libs: minic fixes --- base/sources/libs/minic.c | 64 +++++++++++++++++++-------------- base/sources/libs/minic.h | 1 + base/sources/libs/minic_api.c | 22 +++++++++--- base/sources/libs/minic_tests.c | 13 +++++++ 4 files changed, 69 insertions(+), 31 deletions(-) diff --git a/base/sources/libs/minic.c b/base/sources/libs/minic.c index deffbe1a..11d52bb6 100644 --- a/base/sources/libs/minic.c +++ b/base/sources/libs/minic.c @@ -6,6 +6,7 @@ #include #include #include +#include #include // ████████╗ ██████╗ ██╗ ██╗███████╗███╗ ██╗ @@ -690,8 +691,13 @@ static int minic_current_line(minic_env_t *e) { return line; } -static void minic_error(minic_env_t *e, const char *msg) { +static void minic_error(minic_env_t *e, const char *fmt, ...) { if (!e->error) { + char msg[256]; + va_list args; + va_start(args, fmt); + vsnprintf(msg, sizeof(msg), fmt, args); + va_end(args); fprintf(stderr, "%s:%d: error: %s (got %s)\n", e->filename, minic_current_line(e), msg, minic_tok_name(e->lex.cur.type)); e->error = true; e->returning = true; @@ -700,9 +706,7 @@ static void minic_error(minic_env_t *e, const char *msg) { static void minic_expect(minic_env_t *e, minic_tok_type_t expected) { if (e->lex.cur.type != expected) { - char msg[128]; - snprintf(msg, sizeof(msg), "expected %s", minic_tok_name(expected)); - minic_error(e, msg); + minic_error(e, "expected %s", minic_tok_name(expected)); return; } minic_lex_next(&e->lex); @@ -940,8 +944,7 @@ static int minic_struct_field_idx(minic_struct_def_t *def, const char *field) { static minic_val_t minic_struct_field_get_base(minic_env_t *e, void *base, minic_struct_def_t *def, const char *field) { int idx = minic_struct_field_idx(def, field); if (idx < 0) { - fprintf(stderr, "%s:%d: error: struct '%s' has no field '%s'\n", e->filename, minic_current_line(e), def->name, field); - e->error = e->returning = true; + minic_error(e, "struct '%s' has no field '%s'", def->name, field); return minic_val_int(0); } bool in_arena = (base != NULL && (minic_u8 *)base >= minic_active_mem && (minic_u8 *)base < minic_active_mem + MINIC_MEM_SIZE); @@ -950,6 +953,8 @@ static minic_val_t minic_struct_field_get_base(minic_env_t *e, void *base, minic switch (def->field_native_types[idx]) { case MINIC_T_PTR: return minic_val_typed_ptr(*(void **)p, def->field_deref_types[idx]); + case MINIC_T_EMBED: + return minic_val_typed_ptr(p, def->field_deref_types[idx]); case MINIC_T_FLOAT: return minic_val_float(*(float *)p); default: @@ -964,8 +969,7 @@ static minic_val_t minic_struct_field_get_base(minic_env_t *e, void *base, minic static void minic_struct_field_set_base(minic_env_t *e, void *base, minic_struct_def_t *def, const char *field, minic_val_t val) { int idx = minic_struct_field_idx(def, field); if (idx < 0) { - fprintf(stderr, "%s:%d: error: struct '%s' has no field '%s'\n", e->filename, minic_current_line(e), def->name, field); - e->error = e->returning = true; + minic_error(e, "struct '%s' has no field '%s'", def->name, field); return; } bool in_arena = (base != NULL && (minic_u8 *)base >= minic_active_mem && (minic_u8 *)base < minic_active_mem + MINIC_MEM_SIZE); @@ -975,6 +979,8 @@ static void minic_struct_field_set_base(minic_env_t *e, void *base, minic_struct case MINIC_T_PTR: *(void **)p = minic_val_to_ptr(val); break; + case MINIC_T_EMBED: + break; // embedded structs are mutated through their own field accessors case MINIC_T_FLOAT: *(float *)p = (float)minic_val_to_d(val); break; @@ -1105,7 +1111,23 @@ static minic_val_t minic_parse_primary(minic_env_t *e) { else { addr = minic_var_addr(e, aname); } + // Handle &var->field or &var.field: follow member-access chain + minic_struct_def_t *def = minic_var_struct(e, aname); minic_lex_next(&e->lex); // Consume ident + while (def != NULL && (e->lex.cur.type == TOK_ARROW || e->lex.cur.type == TOK_DOT)) { + minic_lex_next(&e->lex); // Consume '->' or '.' + char field[64]; + strncpy(field, e->lex.cur.text, 63); + minic_lex_next(&e->lex); // Consume field name + void *base = minic_val_to_ptr(addr); + addr = minic_struct_field_get_base(e, base, def, field); + // Advance def to the field's struct type for further chaining + int fidx = minic_struct_field_idx(def, field); + if (fidx >= 0 && def->field_struct_names[fidx][0] != '\0') + def = minic_struct_get(e, def->field_struct_names[fidx]); + else + def = NULL; + } return addr; } if (e->lex.cur.type == TOK_STAR) { @@ -1204,9 +1226,7 @@ static minic_val_t minic_parse_primary(minic_env_t *e) { if (ext != NULL) { return minic_dispatch(ext, args, argc); } - fprintf(stderr, "%s:%d: error: unknown function '%s'\n", e->filename, minic_current_line(e), name); - e->error = true; - e->returning = true; + minic_error(e, "unknown function '%s'", name); return minic_val_int(0); } @@ -1217,8 +1237,7 @@ static minic_val_t minic_parse_primary(minic_env_t *e) { minic_lex_next(&e->lex); minic_struct_def_t *def = minic_var_struct(e, name); if (def == NULL) { - fprintf(stderr, "%s:%d: error: '%s' is not a struct\n", e->filename, minic_current_line(e), name); - e->error = e->returning = true; + minic_error(e, "'%s' is not a struct", name); return minic_val_int(0); } return minic_struct_field_get(e, name, def, field); @@ -1231,8 +1250,7 @@ static minic_val_t minic_parse_primary(minic_env_t *e) { minic_lex_next(&e->lex); minic_struct_def_t *def = minic_var_struct(e, name); if (def == NULL) { - fprintf(stderr, "%s:%d: error: '%s' is not a struct pointer\n", e->filename, minic_current_line(e), name); - e->error = e->returning = true; + minic_error(e, "'%s' is not a struct pointer", name); return minic_val_int(0); } minic_val_t base_val = minic_var_get(e, name); @@ -1421,8 +1439,7 @@ static void minic_parse_stmt(minic_env_t *e) { minic_struct_def_t *def = minic_struct_get(e, sname); if (def == NULL) { - fprintf(stderr, "%s:%d: error: unknown struct '%s'\n", e->filename, minic_current_line(e), sname); - e->error = e->returning = true; + minic_error(e, "unknown struct '%s'", sname); return; } minic_vartype_set(e, vname, sname); @@ -1588,8 +1605,7 @@ static void minic_parse_stmt(minic_env_t *e) { minic_lex_next(&e->lex); minic_struct_def_t *def = minic_var_struct(e, name); if (def == NULL) { - fprintf(stderr, "%s:%d: error: '%s' is not a struct%s\n", e->filename, minic_current_line(e), name, is_arrow ? " pointer" : ""); - e->error = e->returning = true; + minic_error(e, "'%s' is not a struct%s", name, is_arrow ? " pointer" : ""); return; } void *base; @@ -1652,9 +1668,7 @@ static void minic_parse_stmt(minic_env_t *e) { minic_dispatch(ext, args, argc); } else { - fprintf(stderr, "%s:%d: error: unknown function '%s'\n", e->filename, minic_current_line(e), name); - e->error = true; - e->returning = true; + minic_error(e, "unknown function '%s'", name); } } minic_expect(e, TOK_SEMICOLON); @@ -1963,11 +1977,7 @@ static void minic_parse_stmt(minic_env_t *e) { return; } - { - char msg[128]; - snprintf(msg, sizeof(msg), "unexpected token at start of statement"); - minic_error(e, msg); - } + minic_error(e, "unexpected token at start of statement"); } static void minic_parse_block(minic_env_t *e) { diff --git a/base/sources/libs/minic.h b/base/sources/libs/minic.h index 5f622b55..3ba00716 100644 --- a/base/sources/libs/minic.h +++ b/base/sources/libs/minic.h @@ -21,6 +21,7 @@ typedef enum { MINIC_T_BOOL = 3, // used in extern-call ABI, stored as INT in vals MINIC_T_CHAR = 4, // used in extern-call ABI, stored as INT in vals MINIC_T_VOID = 5, // void return only; stored as INT/0 in vals + MINIC_T_EMBED = 6, // embedded struct field; field address is the pointer (no indirection) } minic_type_t; typedef struct { diff --git a/base/sources/libs/minic_api.c b/base/sources/libs/minic_api.c index f0a7997e..89013f0d 100644 --- a/base/sources/libs/minic_api.c +++ b/base/sources/libs/minic_api.c @@ -644,6 +644,7 @@ extern char *project_filepath; extern context_t *g_context; extern config_t *g_config; extern project_t *g_project; +extern mesh_object_t_array_t *project_paint_objects; char *project_filepath_get() { return project_filepath; } @@ -659,6 +660,16 @@ config_t *script_get_config() { project_t *script_get_project() { return g_project; } + +object_t *script_get_object(char *s) { + for (int i = 0; i < project_paint_objects->length; ++i) { + if (string_equals(project_paint_objects->buffer[i]->base->name, s)) { + return project_paint_objects->buffer[i]->base; + } + } + return NULL; +} + void context_set_viewport_shader(void *viewport_shader); void context_set_viewport_mode(int mode); void context_set_camera_controls(int i); @@ -1204,17 +1215,19 @@ void minic_register_builtins() { minic_struct_field_set_type("mesh_object_t", "material", "material_data_t"); // transform_t - static const char *transform_fields[] = {"scale_world", "dirty", "object", "radius"}; + static const char *transform_fields[] = {"loc", "scale_world", "dirty", "object", "radius"}; static const int transform_offsets[] = { + (int)offsetof(transform_t, loc), (int)offsetof(transform_t, scale_world), (int)offsetof(transform_t, dirty), (int)offsetof(transform_t, object), (int)offsetof(transform_t, radius), }; - static const minic_type_t transform_types[] = {MINIC_T_FLOAT, MINIC_T_INT, MINIC_T_PTR, MINIC_T_FLOAT}; - static const minic_type_t transform_deref_types[] = {MINIC_T_FLOAT, MINIC_T_INT, MINIC_T_PTR, MINIC_T_FLOAT}; - minic_register_struct_native("transform_t", transform_fields, transform_offsets, transform_types, transform_deref_types, 4); + static const minic_type_t transform_types[] = {MINIC_T_EMBED, MINIC_T_FLOAT, MINIC_T_INT, MINIC_T_PTR, MINIC_T_FLOAT}; + static const minic_type_t transform_deref_types[] = {MINIC_T_PTR, MINIC_T_FLOAT, MINIC_T_INT, MINIC_T_PTR, MINIC_T_FLOAT}; + minic_register_struct_native("transform_t", transform_fields, transform_offsets, transform_types, transform_deref_types, 5); minic_struct_set_size("transform_t", (int)sizeof(transform_t)); + minic_struct_field_set_type("transform_t", "loc", "vec4_t"); minic_struct_field_set_type("transform_t", "object", "object_t"); // camera_object_t @@ -2034,6 +2047,7 @@ void minic_register_builtins() { R(script_get_context, "p()"); R(script_get_config, "p()"); R(script_get_project, "p()"); + R(script_get_object, "p(p)"); R(context_set_viewport_shader, "v(p)"); R(context_set_viewport_mode, "v(i)"); R(context_set_camera_controls, "v(i)"); diff --git a/base/sources/libs/minic_tests.c b/base/sources/libs/minic_tests.c index 3ae4eefd..2339c6a0 100644 --- a/base/sources/libs/minic_tests.c +++ b/base/sources/libs/minic_tests.c @@ -177,6 +177,18 @@ const char *test11 = " \n\ } \n\ "; +const char *test12 = " \n\ + float main() { \n\ + object_t *o = scene_get_child(\"Scene\"); \n\ + transform_t *t = o->transform; \n\ + vec4_t *v = &t->loc; \n\ + v->x = 3.0; \n\ + v->y = 2.0; \n\ + if (t->loc.x == 3.0 && v->y == 2.0) { return 0.0; } \n\ + return 1.0; \n\ + } \n\ +"; + #define MINIC_TEST(n, src) \ do { \ minic_ctx_t *_c = minic_eval(src); \ @@ -203,6 +215,7 @@ void minic_tests() { MINIC_TEST(9, test9); MINIC_TEST(10, test10); MINIC_TEST(11, test11); + MINIC_TEST(12, test12); } #endif