Files
armorpaint/base/sources/libs/minic.h
T
2026-08-25 00:08:54 +02:00

215 lines
8.4 KiB
C

#pragma once
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#define MINIC_MEM_SIZE (8 * 1024 * 1024)
#define MINIC_MAX_PARAMS 20
#define MINIC_MAX_VARS 128 // locals per scope
#define MINIC_MAX_VARTYPES 128 // struct-typed locals per scope
#define MINIC_MAX_EXTFUNS 1024
#define MINIC_MAX_SIG 64
#define MINIC_MAX_ENUM_CONSTS 512
#define MINIC_MAX_INT_TYPEDEFS 128
#define MINIC_MAX_STRUCT_FIELDS 32
#define MINIC_MAX_STRUCTS 64
#define MINIC_MAX_GLOBALS 64
#define MINIC_MAX_NAME 64
typedef unsigned char minic_u8;
typedef enum {
MINIC_T_INT = 0,
MINIC_T_FLOAT = 1,
MINIC_T_PTR = 2, // void *, always holds a real host pointer
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 value (no indirection)
} minic_type_t;
typedef struct {
minic_type_t type;
minic_type_t deref_type; // pointed-to type (for MINIC_T_PTR)
union {
int i; // MINIC_T_INT
float f; // MINIC_T_FLOAT
void *p; // MINIC_T_PTR
};
} minic_val_t;
// Struct descriptor. When native is true, offsets/types describe a real C layout;
// otherwise instances are stored as an array of boxed minic_val_t (script layout)
typedef struct {
char name[MINIC_MAX_NAME];
int size; // sizeof the native C struct, 0 if unknown
bool native; // field offsets/types describe a native C layout
int field_count;
char fields[MINIC_MAX_STRUCT_FIELDS][MINIC_MAX_NAME];
int offsets[MINIC_MAX_STRUCT_FIELDS]; // byte offset in the native C struct
minic_type_t types[MINIC_MAX_STRUCT_FIELDS]; // storage type of each field
minic_type_t deref_types[MINIC_MAX_STRUCT_FIELDS]; // pointed-to type for PTR fields
char field_structs[MINIC_MAX_STRUCT_FIELDS][MINIC_MAX_NAME]; // struct type name for struct-typed fields, or ""
} minic_struct_t;
extern minic_struct_t minic_structs[MINIC_MAX_STRUCTS];
extern int minic_struct_count;
typedef struct minic_ctx_s minic_ctx_t;
typedef minic_val_t (*minic_native_fn_t)(minic_val_t *args, int argc);
typedef struct {
char name[MINIC_MAX_NAME];
char sig[MINIC_MAX_SIG]; // documentation only
minic_native_fn_t fn;
} minic_ext_func_t;
// Script evaluation
minic_ctx_t *minic_eval(const char *src);
minic_ctx_t *minic_eval_named(const char *src, const char *filename);
void minic_ctx_free(minic_ctx_t *ctx);
float minic_ctx_result(minic_ctx_t *ctx);
minic_val_t minic_ctx_call_fn(minic_ctx_t *ctx, void *fn_ptr, minic_val_t *args, int argc);
// Call a minic function from native C. fn_ptr is a minic func passed from a script,
// valid as long as the owning minic_ctx_t has not been freed
minic_val_t minic_call_fn(void *fn_ptr, minic_val_t *args, int argc);
void *minic_alloc(int size); // allocate in the active context's arena
bool minic_in_arena(void *p); // true if p points into the active arena (script value) vs native C memory
// Host api registration (idempotent, safe to re-run)
void minic_register(const char *name, const char *sig, minic_native_fn_t fn); // sig like "f(p,i)" using i/f/p/b/c/v
void minic_register_native(const char *name, minic_native_fn_t fn); // no sig, for variadic natives
void minic_struct_begin(const char *name, int size);
void minic_struct_field(const char *field, int offset, minic_type_t type, minic_type_t deref_type, const char *struct_type);
void minic_register_struct(const char *name, const char **fields, int field_count); // script-layout struct (boxed fields)
void minic_register_enum(const char *typedef_name, const char **names, const int *values, int count); // values NULL = 0,1,2...
void minic_enum_const_add(const char *name, int value);
void minic_int_typedef_add(const char *name);
void minic_register_global(const char *name, const void *ptr, minic_type_t type);
void minic_register_builtins(void);
float minic_arg_f(minic_val_t *args, int argc, int i);
int minic_arg_i(minic_val_t *args, int argc, int i);
void *minic_arg_p(minic_val_t *args, int argc, int i);
// Registry enumeration (used for editor autocomplete and api.h generation)
int minic_ext_func_count_get(void);
const char *minic_ext_func_name_at(int i);
const char *minic_ext_func_sig_at(int i);
int minic_global_count_get(void);
const char *minic_global_name_at(int i);
minic_type_t minic_global_type_at(int i);
int minic_enum_const_count_get(void);
const char *minic_enum_const_name_at(int i);
int minic_enum_const_value_at(int i);
// Registry lookups (used by the interpreter)
minic_ext_func_t *minic_ext_func_get(const char *name);
minic_val_t minic_dispatch(minic_ext_func_t *ef, minic_val_t *args, int argc);
int minic_enum_const_get(const char *name); // -1 if unknown
bool minic_is_int_typedef(const char *name);
bool minic_global_get(const char *name, minic_val_t *out); // false if unknown
// Native struct registration helpers:
// MINIC_STRUCT(my_t); MINIC_I(count); MINIC_S(name); MINIC_O(child, other_t); MINIC_END();
#define MINIC_STRUCT(T) \
{ \
typedef T minic_st_t; \
minic_struct_begin(#T, (int)sizeof(minic_st_t))
#define MINIC_FIELD(f, t, dt, s) minic_struct_field(#f, (int)offsetof(minic_st_t, f), t, dt, s)
#define MINIC_I(f) MINIC_FIELD(f, MINIC_T_INT, MINIC_T_INT, NULL) // int
#define MINIC_F(f) MINIC_FIELD(f, MINIC_T_FLOAT, MINIC_T_FLOAT, NULL) // float
#define MINIC_B(f) MINIC_FIELD(f, MINIC_T_BOOL, MINIC_T_BOOL, NULL) // bool
#define MINIC_S(f) MINIC_FIELD(f, MINIC_T_PTR, MINIC_T_CHAR, NULL) // char * string
#define MINIC_P(f) MINIC_FIELD(f, MINIC_T_PTR, MINIC_T_PTR, NULL) // untyped pointer
#define MINIC_O(f, T2) MINIC_FIELD(f, MINIC_T_PTR, MINIC_T_PTR, #T2) // pointer to struct T2
#define MINIC_E(f, T2) MINIC_FIELD(f, MINIC_T_EMBED, MINIC_T_PTR, #T2) // embedded struct T2
#define MINIC_END() }
// Enum registration helper (sequential values starting at 0):
// MINIC_ENUM("my_enum_t", "MY_A", "MY_B", "MY_C");
#define MINIC_ENUM(T, ...) \
do { \
static const char *_minic_names[] = {__VA_ARGS__}; \
minic_register_enum(T, _minic_names, NULL, (int)(sizeof(_minic_names) / sizeof(_minic_names[0]))); \
} while (0)
static inline minic_val_t minic_val_int(int v) {
minic_val_t r = {0};
r.type = MINIC_T_INT;
r.deref_type = MINIC_T_INT;
r.i = v;
return r;
}
static inline minic_val_t minic_val_float(float v) {
minic_val_t r = {0};
r.type = MINIC_T_FLOAT;
r.deref_type = MINIC_T_FLOAT;
r.f = v;
return r;
}
static inline minic_val_t minic_val_ptr(void *v) {
minic_val_t r;
r.type = MINIC_T_PTR;
r.deref_type = MINIC_T_PTR;
r.p = v;
return r;
}
static inline minic_val_t minic_val_typed_ptr(void *v, minic_type_t deref_type) {
minic_val_t r;
r.type = MINIC_T_PTR;
r.deref_type = deref_type;
r.p = v;
return r;
}
static inline minic_val_t minic_val_void(void) {
return minic_val_int(0);
}
static inline double minic_val_to_d(minic_val_t v) {
switch (v.type) {
case MINIC_T_INT:
case MINIC_T_BOOL:
case MINIC_T_CHAR:
return (double)v.i;
case MINIC_T_FLOAT:
return (double)v.f;
case MINIC_T_PTR:
return (double)(uintptr_t)v.p;
default:
return 0.0;
}
}
static inline void *minic_val_to_ptr(minic_val_t v) {
return (v.type == MINIC_T_PTR) ? v.p : (void *)(uintptr_t)(uint64_t)minic_val_to_d(v);
}
static inline int minic_val_is_true(minic_val_t v) {
return minic_val_to_d(v) != 0.0;
}
static inline minic_val_t minic_val_coerce(double d, minic_type_t t) {
switch (t) {
case MINIC_T_FLOAT:
return minic_val_float((float)d);
case MINIC_T_PTR:
return minic_val_ptr((void *)(uintptr_t)(uint64_t)d);
default:
return minic_val_int((int)d);
}
}
static inline minic_val_t minic_val_cast(minic_val_t v, minic_type_t t) {
if (v.type == t)
return v;
return minic_val_coerce(minic_val_to_d(v), t);
}
void minic_tests();