Skip to content

Commit eaf1b6f

Browse files
committed
fix: Standardize string and array formats in SDK
- Document canonical string format: [i32 length][utf8_bytes...] - Add ZrtlStringPtr typedef and accessor macros (ZRTL_STRING_LENGTH, ZRTL_STRING_DATA) - Add string helper functions: zrtl_string_new, zrtl_string_from_bytes, zrtl_string_empty, zrtl_string_copy, zrtl_string_print, zrtl_string_equals - Add ZrtlStringView for SDK convenience (non-owning reference) - Document canonical array format: [i32 capacity][i32 length][elements...] - Add ZrtlArrayPtr typedef and accessor macros - Add array helper functions: zrtl_array_new_i32, zrtl_array_push_i32, zrtl_array_get_i32 - Move memory helpers (zrtl_alloc/free/realloc) earlier to fix forward reference - Remove old ZrtlString/ZrtlArray struct definitions that conflicted with inline format
1 parent 31e64f2 commit eaf1b6f

1 file changed

Lines changed: 234 additions & 60 deletions

File tree

sdk/zrtl.h

Lines changed: 234 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -227,6 +227,28 @@ typedef uint32_t ZrtlTypeTag;
227227
/* Destructor function type for boxed values */
228228
typedef void (*ZrtlDropFn)(void* data);
229229

230+
/* ============================================================
231+
* Memory management helpers (defined early - used by other helpers)
232+
* ============================================================ */
233+
234+
/* Allocate memory (use platform malloc) */
235+
static inline void* zrtl_alloc(size_t size) {
236+
extern void* malloc(size_t);
237+
return malloc(size);
238+
}
239+
240+
/* Free memory (use platform free) */
241+
static inline void zrtl_free(void* ptr) {
242+
extern void free(void*);
243+
free(ptr);
244+
}
245+
246+
/* Reallocate memory */
247+
static inline void* zrtl_realloc(void* ptr, size_t size) {
248+
extern void* realloc(void*, size_t);
249+
return realloc(ptr, size);
250+
}
251+
230252
/* Dynamic boxed value */
231253
typedef struct {
232254
ZrtlTypeTag tag; /* Type tag identifying the type */
@@ -573,18 +595,186 @@ typedef uint16_t (*ZrtlRegisterTypeFn)(const ZrtlTypeInfo* info);
573595
* Common type definitions for runtime functions
574596
* ============================================================ */
575597

576-
/* Zyntax string type (UTF-8, length-prefixed) */
577-
typedef struct {
578-
int32_t length; /* Length in bytes (not including null terminator) */
579-
char* data; /* UTF-8 encoded string data */
580-
} ZrtlString;
598+
/* ============================================================
599+
* ZrtlString - Canonical String Format
600+
* ============================================================
601+
*
602+
* IMPORTANT: Zyntax uses a length-prefixed inline string format.
603+
* This is NOT a struct with a pointer - it's a contiguous memory block:
604+
*
605+
* Memory layout: [length: i32][utf8_bytes...]
606+
* - First 4 bytes: length as little-endian i32 (byte count, NOT char count)
607+
* - Remaining bytes: UTF-8 encoded string data
608+
* - NO null terminator (use length to determine end)
609+
*
610+
* Example: "Hello" is stored as:
611+
* [0x05, 0x00, 0x00, 0x00, 'H', 'e', 'l', 'l', 'o']
612+
* ^--- length = 5 ---^ ^--- UTF-8 bytes ---^
613+
*
614+
* In C, strings are passed as `int32_t*` pointing to the length field.
615+
* Use the helper macros below to access string data.
616+
*/
617+
618+
/* String pointer type - points to the length header */
619+
typedef int32_t* ZrtlStringPtr;
620+
typedef const int32_t* ZrtlStringConstPtr;
621+
622+
/* Get string length from a ZrtlStringPtr */
623+
#define ZRTL_STRING_LENGTH(str_ptr) (*(str_ptr))
624+
625+
/* Get pointer to UTF-8 bytes from a ZrtlStringPtr */
626+
#define ZRTL_STRING_DATA(str_ptr) ((const char*)((str_ptr) + 1))
627+
628+
/* Get mutable pointer to UTF-8 bytes */
629+
#define ZRTL_STRING_DATA_MUT(str_ptr) ((char*)((str_ptr) + 1))
630+
631+
/* Calculate total allocation size for a string of given byte length */
632+
#define ZRTL_STRING_ALLOC_SIZE(byte_len) (sizeof(int32_t) + (byte_len))
633+
634+
/* Create a new string from C string (null-terminated) */
635+
static inline ZrtlStringPtr zrtl_string_new(const char* cstr) {
636+
extern size_t strlen(const char*);
637+
extern void* memcpy(void*, const void*, size_t);
638+
639+
if (!cstr) return NULL;
640+
641+
int32_t len = (int32_t)strlen(cstr);
642+
ZrtlStringPtr ptr = (ZrtlStringPtr)zrtl_alloc(ZRTL_STRING_ALLOC_SIZE(len));
643+
if (!ptr) return NULL;
644+
645+
*ptr = len;
646+
memcpy(ZRTL_STRING_DATA_MUT(ptr), cstr, len);
647+
return ptr;
648+
}
649+
650+
/* Create a new string from bytes with known length */
651+
static inline ZrtlStringPtr zrtl_string_from_bytes(const char* bytes, int32_t len) {
652+
extern void* memcpy(void*, const void*, size_t);
653+
654+
if (len < 0) return NULL;
655+
656+
ZrtlStringPtr ptr = (ZrtlStringPtr)zrtl_alloc(ZRTL_STRING_ALLOC_SIZE(len));
657+
if (!ptr) return NULL;
658+
659+
*ptr = len;
660+
if (bytes && len > 0) {
661+
memcpy(ZRTL_STRING_DATA_MUT(ptr), bytes, len);
662+
}
663+
return ptr;
664+
}
665+
666+
/* Create an empty string */
667+
static inline ZrtlStringPtr zrtl_string_empty(void) {
668+
ZrtlStringPtr ptr = (ZrtlStringPtr)zrtl_alloc(sizeof(int32_t));
669+
if (ptr) *ptr = 0;
670+
return ptr;
671+
}
672+
673+
/* Free a ZrtlString */
674+
static inline void zrtl_string_free(ZrtlStringPtr str) {
675+
if (str) zrtl_free(str);
676+
}
677+
678+
/* Copy a ZrtlString */
679+
static inline ZrtlStringPtr zrtl_string_copy(ZrtlStringConstPtr str) {
680+
extern void* memcpy(void*, const void*, size_t);
681+
682+
if (!str) return zrtl_string_empty();
683+
684+
int32_t len = ZRTL_STRING_LENGTH(str);
685+
size_t total_size = ZRTL_STRING_ALLOC_SIZE(len);
686+
ZrtlStringPtr copy = (ZrtlStringPtr)zrtl_alloc(total_size);
687+
if (!copy) return NULL;
581688

582-
/* Zyntax array type */
689+
memcpy(copy, str, total_size);
690+
return copy;
691+
}
692+
693+
/* Print a ZrtlString to stdout */
694+
static inline void zrtl_string_print(ZrtlStringConstPtr str) {
695+
extern int putchar(int);
696+
697+
if (!str) return;
698+
699+
int32_t len = ZRTL_STRING_LENGTH(str);
700+
const char* data = ZRTL_STRING_DATA(str);
701+
702+
for (int32_t i = 0; i < len; i++) {
703+
putchar((unsigned char)data[i]);
704+
}
705+
}
706+
707+
/* Compare two ZrtlStrings for equality */
708+
static inline int zrtl_string_equals(ZrtlStringConstPtr a, ZrtlStringConstPtr b) {
709+
extern int memcmp(const void*, const void*, size_t);
710+
711+
if (a == b) return 1;
712+
if (!a || !b) return 0;
713+
714+
int32_t len_a = ZRTL_STRING_LENGTH(a);
715+
int32_t len_b = ZRTL_STRING_LENGTH(b);
716+
717+
if (len_a != len_b) return 0;
718+
719+
return memcmp(ZRTL_STRING_DATA(a), ZRTL_STRING_DATA(b), len_a) == 0;
720+
}
721+
722+
/* ============================================================
723+
* ZrtlStringView - Non-owning String Reference (for SDK use)
724+
* ============================================================
725+
*
726+
* For SDK code that needs to work with string data without
727+
* dealing with the inline format, use ZrtlStringView.
728+
* This is NOT the format used by the compiler - only for SDK convenience.
729+
*/
583730
typedef struct {
584-
int32_t length; /* Number of elements */
585-
int32_t capacity; /* Allocated capacity */
586-
void* data; /* Pointer to element data */
587-
} ZrtlArray;
731+
const char* data; /* Pointer to UTF-8 bytes */
732+
int32_t length; /* Length in bytes */
733+
} ZrtlStringView;
734+
735+
/* Create a view from a ZrtlStringPtr */
736+
static inline ZrtlStringView zrtl_string_view(ZrtlStringConstPtr str) {
737+
ZrtlStringView view = { NULL, 0 };
738+
if (str) {
739+
view.length = ZRTL_STRING_LENGTH(str);
740+
view.data = ZRTL_STRING_DATA(str);
741+
}
742+
return view;
743+
}
744+
745+
/* ============================================================
746+
* ZrtlArray - Canonical Array Format
747+
* ============================================================
748+
*
749+
* Arrays use a similar inline format for the header:
750+
*
751+
* Memory layout: [capacity: i32][length: i32][elem0, elem1, ...]
752+
* - First 4 bytes: allocated capacity
753+
* - Next 4 bytes: current length (number of elements)
754+
* - Remaining: element data
755+
*
756+
* Arrays are passed as `int32_t*` pointing to the capacity field.
757+
*/
758+
759+
/* Array pointer type - points to the capacity header */
760+
typedef int32_t* ZrtlArrayPtr;
761+
typedef const int32_t* ZrtlArrayConstPtr;
762+
763+
/* Get array capacity */
764+
#define ZRTL_ARRAY_CAPACITY(arr_ptr) ((arr_ptr)[0])
765+
766+
/* Get array length */
767+
#define ZRTL_ARRAY_LENGTH(arr_ptr) ((arr_ptr)[1])
768+
769+
/* Get pointer to array elements (typed) */
770+
#define ZRTL_ARRAY_DATA(arr_ptr, elem_type) ((elem_type*)((arr_ptr) + 2))
771+
772+
/* Header size in i32 units */
773+
#define ZRTL_ARRAY_HEADER_SIZE 2
774+
775+
/* Calculate allocation size for array */
776+
#define ZRTL_ARRAY_ALLOC_SIZE(capacity, elem_size) \
777+
(sizeof(int32_t) * ZRTL_ARRAY_HEADER_SIZE + (capacity) * (elem_size))
588778

589779
/* Zyntax optional type */
590780
typedef struct {
@@ -605,73 +795,57 @@ typedef struct {
605795
#define ZRTL_TYPE_END /* End type definition */
606796

607797
/* ============================================================
608-
* Memory management helpers
798+
* Array creation helpers
609799
* ============================================================ */
610800

611-
/* Allocate memory (use platform malloc) */
612-
static inline void* zrtl_alloc(size_t size) {
613-
extern void* malloc(size_t);
614-
return malloc(size);
615-
}
801+
/* Create a new array with given capacity (for i32 elements) */
802+
static inline ZrtlArrayPtr zrtl_array_new_i32(int32_t initial_capacity) {
803+
int32_t cap = initial_capacity > 0 ? initial_capacity : 8;
804+
size_t size = ZRTL_ARRAY_ALLOC_SIZE(cap, sizeof(int32_t));
805+
ZrtlArrayPtr ptr = (ZrtlArrayPtr)zrtl_alloc(size);
806+
if (!ptr) return NULL;
616807

617-
/* Free memory (use platform free) */
618-
static inline void zrtl_free(void* ptr) {
619-
extern void free(void*);
620-
free(ptr);
808+
ZRTL_ARRAY_CAPACITY(ptr) = cap;
809+
ZRTL_ARRAY_LENGTH(ptr) = 0;
810+
return ptr;
621811
}
622812

623-
/* Reallocate memory */
624-
static inline void* zrtl_realloc(void* ptr, size_t size) {
625-
extern void* realloc(void*, size_t);
626-
return realloc(ptr, size);
813+
/* Free an array */
814+
static inline void zrtl_array_free(ZrtlArrayPtr arr) {
815+
if (arr) zrtl_free(arr);
627816
}
628817

629-
/* ============================================================
630-
* String helpers
631-
* ============================================================ */
818+
/* Push an i32 element to array (may reallocate, returns new ptr) */
819+
static inline ZrtlArrayPtr zrtl_array_push_i32(ZrtlArrayPtr arr, int32_t value) {
820+
if (!arr) return NULL;
632821

633-
/* Create a ZrtlString from a C string */
634-
static inline ZrtlString zrtl_string_from_cstr(const char* cstr) {
635-
extern size_t strlen(const char*);
636-
extern void* memcpy(void*, const void*, size_t);
822+
int32_t cap = ZRTL_ARRAY_CAPACITY(arr);
823+
int32_t len = ZRTL_ARRAY_LENGTH(arr);
637824

638-
ZrtlString str;
639-
str.length = (int32_t)strlen(cstr);
640-
str.data = (char*)zrtl_alloc(str.length + 1);
641-
memcpy(str.data, cstr, str.length + 1);
642-
return str;
643-
}
825+
/* Check if we need to grow */
826+
if (len + ZRTL_ARRAY_HEADER_SIZE >= cap) {
827+
int32_t new_cap = cap * 2;
828+
size_t new_size = ZRTL_ARRAY_ALLOC_SIZE(new_cap, sizeof(int32_t));
829+
ZrtlArrayPtr new_arr = (ZrtlArrayPtr)zrtl_realloc(arr, new_size);
830+
if (!new_arr) return NULL;
644831

645-
/* Free a ZrtlString */
646-
static inline void zrtl_string_free(ZrtlString* str) {
647-
if (str->data) {
648-
zrtl_free(str->data);
649-
str->data = NULL;
650-
str->length = 0;
832+
arr = new_arr;
833+
ZRTL_ARRAY_CAPACITY(arr) = new_cap;
651834
}
652-
}
653835

654-
/* ============================================================
655-
* Array helpers
656-
* ============================================================ */
836+
/* Add element */
837+
ZRTL_ARRAY_DATA(arr, int32_t)[len] = value;
838+
ZRTL_ARRAY_LENGTH(arr) = len + 1;
657839

658-
/* Create a new array with given element size */
659-
static inline ZrtlArray zrtl_array_new(size_t element_size, int32_t initial_capacity) {
660-
ZrtlArray arr;
661-
arr.length = 0;
662-
arr.capacity = initial_capacity > 0 ? initial_capacity : 8;
663-
arr.data = zrtl_alloc(element_size * arr.capacity);
664840
return arr;
665841
}
666842

667-
/* Free an array */
668-
static inline void zrtl_array_free(ZrtlArray* arr) {
669-
if (arr->data) {
670-
zrtl_free(arr->data);
671-
arr->data = NULL;
672-
arr->length = 0;
673-
arr->capacity = 0;
843+
/* Get element from array */
844+
static inline int32_t zrtl_array_get_i32(ZrtlArrayConstPtr arr, int32_t index) {
845+
if (!arr || index < 0 || index >= ZRTL_ARRAY_LENGTH(arr)) {
846+
return 0;
674847
}
848+
return ZRTL_ARRAY_DATA(arr, int32_t)[index];
675849
}
676850

677851
#ifdef __cplusplus

0 commit comments

Comments
 (0)