diff --git a/C/watl.v0.llvm.lottes.c b/C/watl.v0.llvm.lottes.c index 5cf397e..f895782 100644 --- a/C/watl.v0.llvm.lottes.c +++ b/C/watl.v0.llvm.lottes.c @@ -184,6 +184,11 @@ I_ void pause(void){__asm__ volatile("pause":::"memory");} typedef unsigned char def_tset(UTF8); typedef def_struct(Str8) { U8 ptr; U8 len; }; typedef Str8 def_tset(Slice_UTF8); typedef def_struct(Slice_Str8) { U8 ptr; U8 len; }; +#define def_field_str8(member) def_field(Str8,member) +enum { + def_field_str8(ptr), + def_field_str8(len), +}; #define lit(string_literal) (Str8){ u8_(string_literal), size_of(string_literal) - 1 } #pragma endregion Strings @@ -479,12 +484,13 @@ I_ void farena_reset__u (U8 arena); I_ void farena_rewind__u(U8 arena, U8 sp_slot); I_ void farena_save__u (U8 arena, U8 sp); -I_ FArena farena_make (Slice_Mem mem); -I_ void farena_init (FArena_R arena, Slice_Mem byte); -I_ Slice_Mem farena__push (FArena_R arena, U8 amount, U8 type_width, Opts_farena*R_ opts); -I_ void farena_reset (FArena_R arena); -I_ void farena_rewind(FArena_R arena, AllocatorSP save_point); -I_ AllocatorSP farena_save (FArena arena); +S_ U8 farena_make__u (U8 mem_slice); +I_ FArena farena_make (Slice_Mem mem); +I_ void farena_init (FArena_R arena, Slice_Mem byte); +S_ Slice_Mem farena__push (FArena_R arena, U8 amount, U8 type_width, Opts_farena*R_ opts); +I_ void farena_reset (FArena_R arena); +I_ void farena_rewind (FArena_R arena, AllocatorSP save_point); +I_ AllocatorSP farena_save (FArena arena); S_ void farena_allocator_proc(U8 data, U8 requested_size, U8 alignment, U8 old_ptr, U8 old_len, U4 op, /*AllocatorProc_Out*/U8 out); #define ainfo_farena(arena) (AllocatorInfo){ .proc = farena_allocator_proc, .data = u8_(& arena) } @@ -790,12 +796,242 @@ I_ U8 kt1cx_set (KT1CX_Byte kt, U8 key, Slice_Mem value, AllocatorInfo bac #pragma endregion KT1CX #pragma region String Operations +I_ B4 char_is_upper(U1 c); +I_ U1 char_to_lower(U1 c); +I_ U1 integer_symbols(U1 value); + +I_ char* str8_to_cstr_capped(Str8 content, Slice_Mem mem); +I_ Str8 str8_from_u32(AllocatorInfo ainfo, U4 num, U4 radix, U4 min_digits, U4 digit_group_separator); + +#define Str8Cache_CELL_DEPTH 4 + +typedef def_KT1CX_Slot(Str8); +typedef def_KT1CX_Cell(Str8, Str8Cache_CELL_DEPTH); +typedef def_Slice(KT1CX_Cell_Str8); +typedef def_KT1CX(Str8); +enum { + def_field(KT1CX_Str8,table), + + def_field(KT1CX_Slot_Str8,value), + def_field(KT1CX_Slot_Str8,key), + def_field(KT1CX_Slot_Str8,occupied), +}; + +typedef def_struct(Str8Cache) { + AllocatorInfo str_reserve; + AllocatorInfo cell_reserve; + AllocatorInfo tbl_backing; + KT1CX_Str8 kt; +}; +typedef def_struct(Opts_str8cache_init) { + AllocatorInfo str_reserve; + AllocatorInfo cell_reserve; + AllocatorInfo tbl_backing; + U8 cell_pool_size; + U8 table_size; +}; +enum { + def_field(Str8Cache,str_reserve), + def_field(Str8Cache,cell_reserve), + def_field(Str8Cache,tbl_backing), + def_field(Str8Cache,kt), + + def_field(Opts_str8cache_init,str_reserve), + def_field(Opts_str8cache_init,cell_reserve), + def_field(Opts_str8cache_init,tbl_backing), + def_field(Opts_str8cache_init,cell_pool_size), + def_field(Opts_str8cache_init,table_size), +}; + +S_ void str8cache__fill_byte_meta__u(U8 meta); +S_ void str8cache__fill_info_meta__u(U8 meta, U8 cell_pool_size, U8 table_size); + +S_ U8 str8_to_cstr_capped__u(U8 str_slice, U8 mem_slice); +S_ void str8_from_u32__u(U8 result, U8 ainfo_proc, U8 ainfo_data, U4 num, U4 radix, U4 min_digits, U4 digit_group_separator); +S_ void str8__fmt_ktl__u(U8 result, U8 ainfo_proc, U8 ainfo_data, U8 buffer_slice, U8 table_slice, U8 fmt_slice); +S_ void str8__fmt_backed__u(U8 result, U8 tbl_backing_proc, U8 tbl_backing_data, U8 buf_backing_proc, U8 buf_backing_data, U8 fmt_slice, U8 entries_slice); +S_ void str8__fmt__u(U8 result, U8 fmt_slice, U8 entries_slice); + +I_ Str8 str8__fmt_ktl(AllocatorInfo ainfo, Slice_Mem*R_ buffer, KTL_Str8 table, Str8 fmt_template); +I_ Str8 str8__fmt_backed(AllocatorInfo tbl_backing, AllocatorInfo buf_backing, Str8 fmt_template, Slice_A2_Str8*R_ entries); +I_ Str8 str8__fmt(Str8 fmt_template, Slice_A2_Str8*R_ entries); + +S_ void str8cache__init__u(U8 cache, U8 opts); +S_ void str8cache_clear__u(U8 kt); +S_ U8 str8cache_get__u(U8 kt, U8 key); +S_ U8 str8cache_set__u(U8 kt, U8 key, U8 value_str, U8 str_reserve, U8 backing_cells); +S_ void cache_str8__u(U8 result, U8 cache, U8 str); + +I_ void str8cache__init(Str8Cache_R cache, Opts_str8cache_init*R_ opts); +I_ Str8Cache str8cache__make(Opts_str8cache_init*R_ opts); +I_ void str8cache_clear(KT1CX_Str8 kt); +I_ Str8* str8cache_get (KT1CX_Str8 kt, U8 key); +I_ Str8* str8cache_set (KT1CX_Str8 kt, U8 key, Str8 value, AllocatorInfo str_reserve, AllocatorInfo backing_cells); +I_ Str8 cache_str8 (Str8Cache_R cache, Str8 str); + +typedef def_struct(Str8Gen) { + AllocatorInfo backing; + UTF8* ptr; + U8 len; + U8 cap; +}; +enum { + def_field(Str8Gen,backing), + def_field(Str8Gen,ptr), + def_field(Str8Gen,len), + def_field(Str8Gen,cap), +}; + +S_ void str8gen_init__u(U8 gen, U8 backing); +S_ void str8gen_append_str8__u(U8 gen, U8 str); +S_ void str8gen__append_fmt__u(U8 gen, U8 fmt_slice, U8 entries_slice); + +I_ void str8gen_init(Str8Gen_R gen, AllocatorInfo backing); +I_ Str8Gen str8gen_make( AllocatorInfo backing); +#define str8gen_slice_mem(gen) slice_mem_s(gen) + +I_ Str8 str8_from_str8gen(Str8Gen gen); +I_ void str8gen_append_str8(Str8Gen_R gen, Str8 str); +I_ void str8gen__append_fmt(Str8Gen_R gen, Str8 fmt_template, Slice_A2_Str8*R_ entries); +#define str8gen_append_fmt(gen, fmt_template, ...) str8gen__append_fmt(gen, lit(fmt_template), slice_arg_from_array(A2_Str8, __VA_ARGS__)) #pragma endregion String Operations #pragma region File System +#define FILE_PATH_SCRATCH_CAP kilo(64) +typedef def_struct(FileOpInfo) { + Slice_Mem content; +}; +typedef def_struct(Opts_read_file_contents) { + AllocatorInfo backing; + B4 zero_backing; + A4_B1 _PAD_; +}; +enum { + def_field(FileOpInfo,content), + def_field(Opts_read_file_contents,backing), + def_field(Opts_read_file_contents,zero_backing), +}; + +S_ void file_read_contents__u(U8 path_ptr, U8 path_len, U8 backing_proc, U8 backing_data, B4 zero_backing, U8 result); +I_ FileOpInfo file__read_contents(Str8 path, Opts_read_file_contents*R_ opts); +#define file_read_contents(path, ...) file__read_contents(path, opt_args(Opts_read_file_contents, __VA_ARGS__)) + +S_ void file_write_str8__u(U8 path_ptr, U8 path_len, U8 content_ptr, U8 content_len); +I_ void file_write_str8(Str8 path, Str8 content); #pragma endregion FIle System #pragma region WATL +#define WATL_Tok_Space ' ' +#define WATL_Tok_Tab '\t' +#define WATL_Tok_CarriageReturn '\r' +#define WATL_Tok_LineFeed '\n' +#define WATL_Tok_Text 0x0FFFFFFF + +typedef Str8 def_tset(WATL_Tok); +typedef def_Slice(WATL_Tok); + +typedef def_enum(U4, WATL_LexStatus) { + WATL_LexStatus_MemFail_SliceConstraintFail = (1 << 0), +}; +typedef def_struct(WATL_Pos) { + U4 line; + U4 column; +}; +typedef def_struct(WATL_LexMsg) { + WATL_LexMsg* next; + Str8 content; + WATL_Tok* tok; + WATL_Pos pos; +}; +typedef def_struct(WATL_LexInfo) { + WATL_LexMsg* msgs; + Slice_WATL_Tok toks; + WATL_LexStatus signal; + A4_B1 _PAD_; +}; +typedef def_struct(Opts_watl_lex) { + AllocatorInfo ainfo_msgs; + AllocatorInfo ainfo_toks; + B1 failon_unsupported_codepoints; + B1 failon_pos_untrackable; + B1 failon_slice_constraint_fail; + A4_B1 _PAD_; +}; + +typedef WATL_Tok WATL_Node; +typedef def_ptr_set(WATL_Node); +typedef def_Slice(WATL_Node); +typedef Slice_WATL_Node def_tset(WATL_Line); +typedef def_Slice(WATL_Line); +typedef def_struct(WATL_ParseMsg) { + WATL_ParseMsg* next; + Str8 content; + WATL_Line* line; + WATL_Tok* tok; + WATL_Pos pos; +}; +typedef def_enum(U4, WATL_ParseStatus) { + WATL_ParseStatus_MemFail_SliceConstraintFail = (1 << 0), +}; +typedef def_struct(WATL_ParseInfo) { + Slice_WATL_Line lines; + WATL_ParseMsg* msgs; + WATL_ParseStatus signal; + A4_B1 _PAD_; +}; +typedef def_struct(Opts_watl_parse) { + AllocatorInfo ainfo_msgs; + AllocatorInfo ainfo_nodes; + AllocatorInfo ainfo_lines; + Str8Cache* str_cache; + B4 failon_slice_constraint_fail; + A4_B1 _PAD_; +}; +enum { + def_field(WATL_Pos,line), + def_field(WATL_Pos,column), + + def_field(WATL_LexMsg,next), + def_field(WATL_LexMsg,content), + def_field(WATL_LexMsg,tok), + def_field(WATL_LexMsg,pos), + + def_field(WATL_LexInfo,msgs), + def_field(WATL_LexInfo,toks), + def_field(WATL_LexInfo,signal), + + def_field(Opts_watl_lex,ainfo_msgs), + def_field(Opts_watl_lex,ainfo_toks), + def_field(Opts_watl_lex,failon_unsupported_codepoints), + def_field(Opts_watl_lex,failon_pos_untrackable), + def_field(Opts_watl_lex,failon_slice_constraint_fail), + + def_field(WATL_ParseMsg,next), + def_field(WATL_ParseMsg,content), + def_field(WATL_ParseMsg,line), + def_field(WATL_ParseMsg,tok), + def_field(WATL_ParseMsg,pos), + + def_field(WATL_ParseInfo,lines), + def_field(WATL_ParseInfo,msgs), + def_field(WATL_ParseInfo,signal), + + def_field(Opts_watl_parse,ainfo_msgs), + def_field(Opts_watl_parse,ainfo_nodes), + def_field(Opts_watl_parse,ainfo_lines), + def_field(Opts_watl_parse,str_cache), + def_field(Opts_watl_parse,failon_slice_constraint_fail), +}; + +S_ void watl_lex__u (U8 info, U8 source, U8 opts); +S_ void watl_parse__u(U8 info, U8 tokens, U8 opts); +S_ void watl_dump_listing__u(U8 result, U8 buffer_ainfo, U8 lines); + +I_ void api_watl_lex(WATL_LexInfo_R info, Str8 source, Opts_watl_lex*R_ opts); +I_ WATL_LexInfo watl__lex ( Str8 source, Opts_watl_lex*R_ opts); +I_ void api_watl_parse(WATL_ParseInfo_R info, Slice_WATL_Tok tokens, Opts_watl_parse*R_ opts); +I_ WATL_ParseInfo watl__parse(Slice_WATL_Tok tokens, Opts_watl_parse*R_ opts); +I_ Str8 watl_dump_listing(AllocatorInfo buffer, Slice_WATL_Line lines); #pragma endregion WATL #pragma endregion Header @@ -1473,7 +1709,7 @@ S_ inline void kt1cx_clear__u(U8 kt, U8 m) { U8 slot_cursor = cell_cursor; for (; slot_cursor < slots_end; slot_cursor += slot_size) { process_slots: - mem_zero(slot_cursor, u8_r(slot_cursor + Slice_len)[0]); + mem_zero(slot_cursor, slot_size); } U8 next = slot_cursor + u8_r(m + KT1CX_ByteMeta_cell_next_offset)[0]; if (next != null) { @@ -1489,7 +1725,7 @@ I_ U8 kt1cx_slot_id__u(U8 kt, U8 key) { S_ inline U8 kt1cx_get__u(U8 kt, U8 key, U8 m) { U8 hash_index = kt1cx_slot_id__u(kt, key); U8 cell_offset = hash_index * u8_r(m + KT1CX_ByteMeta_cell_size)[0]; - U8 cell_cursor = kt + cell_offset; + U8 cell_cursor = u8_r(kt + Slice_ptr)[0] + cell_offset; { U8 slot_size = u8_r(m + KT1CX_ByteMeta_slot_size)[0]; U8 slot_cursor = cell_cursor; @@ -1512,16 +1748,911 @@ S_ inline U8 kt1cx_get__u(U8 kt, U8 key, U8 m) { } } S_ inline U8 kt1cx_set__u(U8 kt, U8 key, U8 v_ptr, U8 v_len, U8 backing_cells, U8 m) { - return 0; + (void)v_ptr; + (void)v_len; + assert(kt != null); + assert(m != null); + U8 table_len = u8_r(kt + Slice_len)[0]; + U8 table_ptr = u8_r(kt + Slice_ptr)[0]; + if (table_len == 0 || table_ptr == 0) { return null; } + + U8 cell_size = u8_r(m + KT1CX_ByteMeta_cell_size)[0]; + U8 cell_depth = u8_r(m + KT1CX_ByteMeta_cell_depth)[0]; + U8 slot_size = u8_r(m + KT1CX_ByteMeta_slot_size)[0]; + U8 slot_key_offset = u8_r(m + KT1CX_ByteMeta_slot_key_offset)[0]; + U8 cell_next_offset = u8_r(m + KT1CX_ByteMeta_cell_next_offset)[0]; + U8 slot_span = cell_depth * slot_size; + + U8 hash_index = key % table_len; + U8 cell_cursor = table_ptr + hash_index * cell_size; + +process_cell: + { + U8 slot_cursor = cell_cursor; + U8 slots_end = cell_cursor + slot_span; + for (; slot_cursor != slots_end; slot_cursor += slot_size) { + process_slots: + U8 slot_key_addr = slot_cursor + slot_key_offset; + U8 slot_occ_addr = slot_cursor + KT1CX_Byte_Slot_occupied; + if (!u8_r(slot_occ_addr)[0]) { + u8_r(slot_occ_addr)[0] = 1; + u8_r(slot_key_addr)[0] = key; + return slot_cursor; + } + if (u8_r(slot_key_addr)[0] == key) { + return slot_cursor; + } + } + + U8 next_addr = cell_cursor + cell_next_offset; + U8 next_cell = u8_r(next_addr)[0]; + if (next_cell != null) { + slot_cursor = next_cell; + cell_cursor = next_cell; + goto process_slots; + } + + uvar(Slice_Mem, new_cell); + mem__alloc__u( + u8_(new_cell), + u8_r(backing_cells + AllocatorInfo_proc)[0], + u8_r(backing_cells + AllocatorInfo_data)[0], + cell_size, + 0, + false); + U8 new_cell_ptr = u8_r(new_cell + Slice_ptr)[0]; + if (new_cell_ptr == 0) { return null; } + mem_zero(new_cell_ptr, cell_size); + + u8_r(next_addr)[0] = new_cell_ptr; + cell_cursor = new_cell_ptr; + goto process_cell; + } } + +I_ void kt1cx_init(KT1CX_Info info, KT1CX_InfoMeta meta, KT1CX_Byte*R_ result) { + assert(result != nullptr); + kt1cx_init__u(u8_(& info.backing_table), u8_(& info.backing_cells), u8_(& meta), u8_(& result->table)); +} + +I_ void kt1cx_clear(KT1CX_Byte kt, KT1CX_ByteMeta meta) { + kt1cx_clear__u(u8_(& kt.table), u8_(& meta)); +} + +I_ U8 kt1cx_slot_id(KT1CX_Byte kt, U8 key, KT1CX_ByteMeta meta) { + (void)meta; + return kt1cx_slot_id__u(u8_(& kt.table), key); +} + +I_ U8 kt1cx_get(KT1CX_Byte kt, U8 key, KT1CX_ByteMeta meta) { + return kt1cx_get__u(u8_(& kt.table), key, u8_(& meta)); +} + +I_ U8 kt1cx_set(KT1CX_Byte kt, U8 key, Slice_Mem value, AllocatorInfo backing_cells, KT1CX_ByteMeta meta) { + return kt1cx_set__u(u8_(& kt.table), key, value.ptr, value.len, u8_(& backing_cells), u8_(& meta)); +} +#pragma endregion Key Table + +#pragma region String Operations +I_ B4 char_is_upper(U1 c) { return ('A' <= c && c <= 'Z'); } +I_ U1 char_to_lower(U1 c) { if (char_is_upper(c)) { c += ('a' - 'A'); } return c; } +I_ U1 integer_symbols(U1 value) { + LP_ U1 lookup_table[16] = { '0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F' }; + return lookup_table[value & 0xF]; +} + +S_ U8 str8_to_cstr_capped__u(U8 str_slice, U8 mem_slice) { + assert(str_slice != null); + assert(mem_slice != null); + U8 src_ptr = u8_r(str_slice + Str8_ptr)[0]; + U8 src_len = u8_r(str_slice + Str8_len)[0]; + U8 dst_ptr = u8_r(mem_slice + Slice_ptr)[0]; + U8 dst_len = u8_r(mem_slice + Slice_len)[0]; + assert(dst_ptr != null); + assert(dst_len > 0); + U8 max_copy = dst_len - 1; + U8 copy_len = min(src_len, max_copy); + mem_copy(dst_ptr, src_ptr, copy_len); + u1_r(dst_ptr)[copy_len] = 0; + return dst_ptr; +} + +I_ char* str8_to_cstr_capped(Str8 content, Slice_Mem mem) { + return cast(char*, str8_to_cstr_capped__u(u8_(& content), u8_(& mem))); +} + +S_ void str8_from_u32__u(U8 result, U8 ainfo_proc, U8 ainfo_data, U4 num, U4 radix, U4 min_digits, U4 digit_group_separator) { + assert(result != null); + assert(ainfo_proc != null); + U8 prefix_ptr = 0; + U8 prefix_len = 0; + switch (radix) { + case 16: { Str8 temp = lit("0x"); prefix_ptr = temp.ptr; prefix_len = temp.len; } break; + case 8: { Str8 temp = lit("0o"); prefix_ptr = temp.ptr; prefix_len = temp.len; } break; + case 2: { Str8 temp = lit("0b"); prefix_ptr = temp.ptr; prefix_len = temp.len; } break; + default: break; + } + U4 digit_group_size = (radix == 2 || radix == 8 || radix == 16) ? 4 : 3; + U4 needed_digits = 1; + for (U4 reduce = num; reduce /= radix; ) { ++ needed_digits; } + U4 needed_leading_zeros = (min_digits > needed_digits) ? min_digits - needed_digits : 0; + U4 needed_separators = 0; + if (digit_group_separator != 0) { + U4 digit_total = needed_digits + needed_leading_zeros; + needed_separators = digit_total / digit_group_size; + if (needed_separators && (digit_total % digit_group_size) == 0) { + -- needed_separators; + } + } + U8 total_len = prefix_len + needed_leading_zeros + needed_separators + needed_digits; + uvar(Slice_Mem, allocation); + mem__alloc__u(u8_(allocation), ainfo_proc, ainfo_data, total_len, 0, 1); + U8 out_ptr = u8_r(u8_(allocation) + Slice_ptr)[0]; + assert(out_ptr != null); + u8_r(result + Str8_ptr)[0] = out_ptr; + u8_r(result + Str8_len)[0] = total_len; + + U8 digits_until_separator = digit_group_size; + U4 num_reduce = num; + for (U4 idx = 0; idx < needed_digits; ++idx) { + U8 write_pos = out_ptr + total_len - idx - 1; + if (digit_group_separator && digits_until_separator == 0) { + u1_r(write_pos)[0] = cast(U1, digit_group_separator); + digits_until_separator = digit_group_size; + ++ write_pos; + } else { + u1_r(write_pos)[0] = char_to_lower(integer_symbols(cast(U1, num_reduce % radix))); + num_reduce /= radix; + if (num_reduce == 0) { break; } + } + if (digits_until_separator) { -- digits_until_separator; } + } + for (U4 leading = 0; leading < needed_leading_zeros; ++leading) { + u1_r(out_ptr + prefix_len + leading)[0] = '0'; + } + if (prefix_len) { + mem_copy(out_ptr, prefix_ptr, prefix_len); + } +} + +I_ Str8 str8_from_u32(AllocatorInfo ainfo, U4 num, U4 radix, U4 min_digits, U4 digit_group_separator) { + Str8 out = {0}; + str8_from_u32__u(u8_(& out), u8_(ainfo.proc), ainfo.data, num, radix, min_digits, digit_group_separator); + return out; +} + +S_ void str8__fmt_ktl__u(U8 result, U8 ainfo_proc, U8 ainfo_data, U8 buffer_slice, U8 table_slice, U8 fmt_slice) { + assert(result != null); + assert(buffer_slice != null); + assert(table_slice != null); + assert(fmt_slice != null); + + U8 buffer_ptr = u8_r(buffer_slice + Slice_ptr)[0]; + U8 buffer_len = u8_r(buffer_slice + Slice_len)[0]; + assert(buffer_ptr != null); + assert(buffer_len != 0); + + U8 table_ptr = u8_r(table_slice + Slice_ptr)[0]; + U8 table_len = u8_r(table_slice + Slice_len)[0]; + assert(table_ptr != null); + + U8 fmt_ptr = u8_r(fmt_slice + Str8_ptr)[0]; + U8 fmt_len = u8_r(fmt_slice + Str8_len)[0]; + assert(fmt_ptr != null); + + if (ainfo_proc != null) { + AllocatorQueryInfo query = {0}; + allocator_query__u(ainfo_proc, ainfo_data, u8_(& query)); + assert((query.features & AllocatorQuery_Grow) != 0); + } + + U8 cursor_buffer = buffer_ptr; + U8 buffer_remaining = buffer_len; + U8 cursor_fmt = fmt_ptr; + U8 fmt_end = fmt_ptr + fmt_len; + U8 left_fmt = fmt_len; + U8 slot_size = size_of(KTL_Slot_Str8); + + while (left_fmt && buffer_remaining) { + U8 copy_offset = 0; + while ((cursor_fmt + copy_offset) < fmt_end && u1_r(cursor_fmt + copy_offset)[0] != '<') { + ++ copy_offset; + } + if (copy_offset) { + mem_copy(cursor_buffer, cursor_fmt, copy_offset); + buffer_remaining -= copy_offset; + left_fmt -= copy_offset; + cursor_buffer += copy_offset; + cursor_fmt += copy_offset; + if (left_fmt == 0) { break; } + } + + if ((cursor_fmt < fmt_end) && u1_r(cursor_fmt)[0] == '<') { + U8 token_cursor = cursor_fmt + 1; + U8 token_len = 0; + B4 fmt_overflow = false; + for (;;) { + U8 current = token_cursor + token_len; + fmt_overflow = current >= fmt_end; + if (fmt_overflow) { break; } + if (u1_r(current)[0] == '>') { break; } + ++ token_len; + } + if (fmt_overflow) { continue; } + + U8 key = 0; + hash64_fnv1a__u(u8_(& key), token_cursor, token_len, 0); + U8 value_ptr = null; + U8 value_len = 0; + U8 slot_cursor = table_ptr; + for (U8 slot_index = 0; slot_index < table_len; ++slot_index, slot_cursor += slot_size) { + if (u8_r(slot_cursor + KTL_Slot_key)[0] == key) { + U8 value_slice = slot_cursor + KTL_Slot_value; + value_ptr = u8_r(value_slice + Str8_ptr)[0]; + value_len = u8_r(value_slice + Str8_len)[0]; + break; + } + } + + if (value_ptr != null) { + if (ainfo_proc != null && (buffer_remaining - token_len) <= 0) { + uvar(Slice_Mem, grown); + mem__grow__u(u8_(grown), ainfo_proc, ainfo_data, buffer_ptr, buffer_len, buffer_len + token_len, 0, false, true); + U8 grown_ptr = u8_r(u8_(grown) + Slice_ptr)[0]; + U8 grown_len = u8_r(u8_(grown) + Slice_len)[0]; + U8 used = cursor_buffer - buffer_ptr; + buffer_ptr = grown_ptr; + buffer_len = grown_len; + cursor_buffer = buffer_ptr + used; + buffer_remaining = buffer_len - used; + u8_r(buffer_slice + Slice_ptr)[0] = buffer_ptr; + u8_r(buffer_slice + Slice_len)[0] = buffer_len; + } + assert((buffer_remaining - token_len) > 0); + mem_copy(cursor_buffer, value_ptr, value_len); + cursor_buffer += value_len; + buffer_remaining -= value_len; + cursor_fmt = token_cursor + token_len + 1; + left_fmt -= token_len + 2; + continue; + } + + u1_r(cursor_buffer)[0] = u1_r(cursor_fmt)[0]; + ++ cursor_buffer; + ++ cursor_fmt; + -- buffer_remaining; + -- left_fmt; + continue; + } + } + + u8_r(buffer_slice + Slice_ptr)[0] = buffer_ptr; + u8_r(buffer_slice + Slice_len)[0] = buffer_len; + u8_r(result + Str8_ptr)[0] = buffer_ptr; + u8_r(result + Str8_len)[0] = buffer_len - buffer_remaining; +} + +I_ Str8 str8__fmt_ktl(AllocatorInfo ainfo, Slice_Mem*R_ buffer, KTL_Str8 table, Str8 fmt_template) { + assert(buffer != nullptr); + Str8 formatted = {0}; + str8__fmt_ktl__u( + u8_(& formatted), + u8_(ainfo.proc), + ainfo.data, + u8_(buffer), + u8_(& table), + u8_(& fmt_template) + ); + return formatted; +} + +S_ void str8__fmt_backed__u(U8 result, U8 tbl_backing_proc, U8 tbl_backing_data, U8 buf_backing_proc, U8 buf_backing_data, U8 fmt_slice, U8 entries_slice) { + assert(result != null); + KTL_Str8 kt = {0}; + ktl_populate_slice_a2_str8(u8_(& kt), tbl_backing_proc, tbl_backing_data, entries_slice); + uvar(Slice_Mem, buffer); + mem__alloc__u(u8_(buffer), buf_backing_proc, buf_backing_data, kilo(64), 0, 1); + str8__fmt_ktl__u(result, buf_backing_proc, buf_backing_data, u8_(buffer), u8_(& kt), fmt_slice); +} + +I_ Str8 str8__fmt_backed(AllocatorInfo tbl_backing, AllocatorInfo buf_backing, Str8 fmt_template, Slice_A2_Str8*R_ entries) { + Str8 output = {0}; + str8__fmt_backed__u( + u8_(& output), + u8_(tbl_backing.proc), + tbl_backing.data, + u8_(buf_backing.proc), + buf_backing.data, + u8_(& fmt_template), + u8_(entries) + ); + return output; +} + +S_ void str8__fmt__u(U8 result, U8 fmt_slice, U8 entries_slice) { + assert(result != null); + LP_ B1 tbl_mem[kilo(32)]; + LP_ B1 buf_mem[kilo(64)]; + LP_ B1 tbl_arena_mem[size_of(FArena)]; + farena_init__u(u8_(tbl_arena_mem), u8_(tbl_mem), size_of(tbl_mem)); + AllocatorInfo tbl_info = { .proc = farena_allocator_proc, .data = u8_(tbl_arena_mem) }; + KTL_Str8 kt = {0}; + ktl_populate_slice_a2_str8(u8_(& kt), u8_(tbl_info.proc), tbl_info.data, entries_slice); + Slice_Mem buffer = slice_fmem(buf_mem); + str8__fmt_ktl__u(result, 0, 0, u8_(& buffer), u8_(& kt), fmt_slice); +} + +I_ Str8 str8__fmt(Str8 fmt_template, Slice_A2_Str8*R_ entries) { + Str8 output = {0}; + str8__fmt__u(u8_(& output), u8_(& fmt_template), u8_(entries)); + return output; +} + +S_ void str8cache__fill_byte_meta__u(U8 meta) { + assert(meta != null); + u8_r(meta + KT1CX_ByteMeta_slot_size)[0] = size_of(KT1CX_Slot_Str8); + u8_r(meta + KT1CX_ByteMeta_slot_key_offset)[0] = offset_of(KT1CX_Slot_Str8, key); + u8_r(meta + KT1CX_ByteMeta_cell_next_offset)[0] = offset_of(KT1CX_Cell_Str8, next); + u8_r(meta + KT1CX_ByteMeta_cell_depth)[0] = Str8Cache_CELL_DEPTH; + u8_r(meta + KT1CX_ByteMeta_cell_size)[0] = size_of(KT1CX_Cell_Str8); + u8_r(meta + KT1CX_ByteMeta_type_width)[0] = size_of(Str8); + Str8 type_name = lit(stringify(Str8)); + u8_r(meta + KT1CX_ByteMeta_type_name + Str8_ptr)[0] = type_name.ptr; + u8_r(meta + KT1CX_ByteMeta_type_name + Str8_len)[0] = type_name.len; +} + +S_ void str8cache__fill_info_meta__u(U8 meta, U8 cell_pool_size, U8 table_size) { + assert(meta != null); + u8_r(meta + KT1CX_InfoMeta_cell_pool_size)[0] = cell_pool_size; + u8_r(meta + KT1CX_InfoMeta_table_size)[0] = table_size; + u8_r(meta + KT1CX_InfoMeta_slot_size)[0] = size_of(KT1CX_Slot_Str8); + u8_r(meta + KT1CX_InfoMeta_slot_key_offset)[0] = offset_of(KT1CX_Slot_Str8, key); + u8_r(meta + KT1CX_InfoMeta_cell_next_offset)[0] = offset_of(KT1CX_Cell_Str8, next); + u8_r(meta + KT1CX_InfoMeta_cell_depth)[0] = Str8Cache_CELL_DEPTH; + u8_r(meta + KT1CX_InfoMeta_cell_size)[0] = size_of(KT1CX_Cell_Str8); + u8_r(meta + KT1CX_InfoMeta_type_width)[0] = size_of(Str8); + Str8 type_name = lit(stringify(Str8)); + u8_r(meta + KT1CX_InfoMeta_type_name + Str8_ptr)[0] = type_name.ptr; + u8_r(meta + KT1CX_InfoMeta_type_name + Str8_len)[0] = type_name.len; +} + +S_ void str8cache__init__u(U8 cache, U8 opts) { + assert(cache != null); + assert(opts != null); + U8 str_reserve = cache + Str8Cache_str_reserve; + U8 cell_reserve = cache + Str8Cache_cell_reserve; + U8 tbl_backing = cache + Str8Cache_tbl_backing; + + U8 in_str_reserve = opts + Opts_str8cache_init_str_reserve; + U8 in_cell_reserve = opts + Opts_str8cache_init_cell_reserve; + U8 in_tbl_backing = opts + Opts_str8cache_init_tbl_backing; + + assert(u8_r(in_str_reserve + AllocatorInfo_proc)[0] != null); + assert(u8_r(in_cell_reserve + AllocatorInfo_proc)[0] != null); + assert(u8_r(in_tbl_backing + AllocatorInfo_proc)[0] != null); + + mem_copy(str_reserve, in_str_reserve, size_of(AllocatorInfo)); + mem_copy(cell_reserve, in_cell_reserve, size_of(AllocatorInfo)); + mem_copy(tbl_backing, in_tbl_backing, size_of(AllocatorInfo)); + + U8 cell_pool_size = u8_r(opts + Opts_str8cache_init_cell_pool_size)[0]; + U8 table_size = u8_r(opts + Opts_str8cache_init_table_size)[0]; + if (cell_pool_size == 0) { cell_pool_size = kilo(1); } + if (table_size == 0) { table_size = kilo(1); } + + uvar(KT1CX_InfoMeta, meta) = {0}; + str8cache__fill_info_meta__u(u8_(meta), cell_pool_size, table_size); + kt1cx_init__u(tbl_backing, cell_reserve, u8_(meta), cache + Str8Cache_kt + KT1CX_Str8_table); +} + +I_ void str8cache__init(Str8Cache_R cache, Opts_str8cache_init*R_ opts) { + assert(cache != nullptr); + assert(opts != nullptr); + assert(opts->str_reserve.proc != nullptr); + assert(opts->cell_reserve.proc != nullptr); + assert(opts->tbl_backing.proc != nullptr); + str8cache__init__u(u8_(cache), u8_(opts)); +} + +I_ Str8Cache str8cache__make(Opts_str8cache_init*R_ opts) { Str8Cache cache; str8cache__init(& cache, opts); return cache; } + +S_ void str8cache_clear__u(U8 kt) { + uvar(KT1CX_ByteMeta, meta) = {0}; + str8cache__fill_byte_meta__u(u8_(meta)); + kt1cx_clear__u(kt, u8_(meta)); +} + +S_ U8 str8cache_get__u(U8 kt, U8 key) { + uvar(KT1CX_ByteMeta, meta) = {0}; + str8cache__fill_byte_meta__u(u8_(meta)); + return kt1cx_get__u(kt, key, u8_(meta)); +} + +S_ U8 str8cache_set__u(U8 kt, U8 key, U8 value_str, U8 str_reserve, U8 backing_cells) { + assert(value_str != null); + U8 value_ptr = u8_r(value_str + Str8_ptr)[0]; + U8 value_len = u8_r(value_str + Str8_len)[0]; + assert(value_ptr != null); + uvar(KT1CX_ByteMeta, meta) = {0}; + str8cache__fill_byte_meta__u(u8_(meta)); + U8 entry = kt1cx_set__u(kt, key, value_ptr, value_len, backing_cells, u8_(meta)); + if (entry == null) { return null; } + U8 stored = entry + KT1CX_Slot_Str8_value; + U8 stored_ptr = u8_r(stored + Str8_ptr)[0]; + U8 stored_len = u8_r(stored + Str8_len)[0]; + U8 reserve_proc = u8_r(str_reserve + AllocatorInfo_proc)[0]; + U8 reserve_data = u8_r(str_reserve + AllocatorInfo_data)[0]; + assert(reserve_proc != null); + if (stored_ptr == 0 || stored_len < value_len) { + uvar(Slice_Mem, allocation); + mem__alloc__u(u8_(allocation), reserve_proc, reserve_data, value_len, 0, 1); + stored_ptr = u8_r(u8_(allocation) + Slice_ptr)[0]; + stored_len = u8_r(u8_(allocation) + Slice_len)[0]; + u8_r(stored + Str8_ptr)[0] = stored_ptr; + u8_r(stored + Str8_len)[0] = stored_len; + } + mem_copy(stored_ptr, value_ptr, value_len); + u8_r(stored + Str8_len)[0] = value_len; + return stored; +} + +S_ void cache_str8__u(U8 result, U8 cache, U8 str) { + assert(result != null); + assert(cache != null); + assert(str != null); + U8 hash = 0; + U8 str_ptr = u8_r(str + Str8_ptr)[0]; + U8 str_len = u8_r(str + Str8_len)[0]; + hash64_fnv1a__u(u8_(& hash), str_ptr, str_len, 0); + U8 entry = str8cache_set__u( + cache + Str8Cache_kt + KT1CX_Str8_table, + hash, + str, + cache + Str8Cache_str_reserve, + cache + Str8Cache_cell_reserve + ); + if (entry == null) { + u8_r(result + Str8_ptr)[0] = 0; + u8_r(result + Str8_len)[0] = 0; + return; + } + u8_r(result + Str8_ptr)[0] = u8_r(entry + Str8_ptr)[0]; + u8_r(result + Str8_len)[0] = u8_r(entry + Str8_len)[0]; +} + +I_ void str8cache_clear(KT1CX_Str8 kt) { + kt1cx_assert(kt); + str8cache_clear__u(u8_(& kt.table)); +} + +I_ Str8* str8cache_get(KT1CX_Str8 kt, U8 key) { + kt1cx_assert(kt); + return cast(Str8*, str8cache_get__u(u8_(& kt.table), key)); +} + +I_ Str8* str8cache_set(KT1CX_Str8 kt, U8 key, Str8 value, AllocatorInfo str_reserve, AllocatorInfo backing_cells) { + kt1cx_assert(kt); + slice_assert(value); + assert(str_reserve.proc != nullptr); + assert(backing_cells.proc != nullptr); + U8 entry = str8cache_set__u( + u8_(& kt.table), + key, + u8_(& value), + u8_(& str_reserve), + u8_(& backing_cells) + ); + assert(entry != null); + return cast(Str8*, entry); +} + +I_ Str8 cache_str8(Str8Cache_R cache, Str8 str) { + Str8 result = {0}; + assert(cache != nullptr); + slice_assert(str); + cache_str8__u(u8_(& result), u8_(cache), u8_(& str)); + return result; +} + +S_ void str8gen_init__u(U8 gen, U8 backing) { + assert(gen != null); + assert(backing != null); + assert(u8_r(backing + AllocatorInfo_proc)[0] != null); + mem_copy(gen + Str8Gen_backing, backing, size_of(AllocatorInfo)); + U8 backing_proc = u8_r(backing + AllocatorInfo_proc)[0]; + U8 backing_data = u8_r(backing + AllocatorInfo_data)[0]; + uvar(Slice_Mem, buffer); + mem__alloc__u(u8_(buffer), backing_proc, backing_data, kilo(4), 0, 1); + u8_r(gen + Str8Gen_ptr)[0] = u8_r(u8_(buffer) + Slice_ptr)[0]; + u8_r(gen + Str8Gen_len)[0] = 0; + u8_r(gen + Str8Gen_cap)[0] = u8_r(u8_(buffer) + Slice_len)[0]; +} + +I_ void str8gen_init(Str8Gen_R gen, AllocatorInfo backing) { + assert(gen != nullptr); + str8gen_init__u(u8_(gen), u8_(& backing)); +} + +I_ Str8Gen str8gen_make(AllocatorInfo backing) { Str8Gen gen; str8gen_init(& gen, backing); return gen; } + +I_ Str8 str8_from_str8gen(Str8Gen gen) { return (Str8){ u8_(gen.ptr), gen.len }; } + +S_ void str8gen_append_str8__u(U8 gen, U8 str_slice) { + assert(gen != null); + assert(str_slice != null); + U8 str_ptr = u8_r(str_slice + Str8_ptr)[0]; + U8 str_len = u8_r(str_slice + Str8_len)[0]; + U8 gen_ptr = u8_r(gen + Str8Gen_ptr)[0]; + U8 gen_len = u8_r(gen + Str8Gen_len)[0]; + U8 gen_cap = u8_r(gen + Str8Gen_cap)[0]; + U8 needed = gen_len + str_len; + U8 backing_proc = u8_r(gen + Str8Gen_backing + AllocatorInfo_proc)[0]; + U8 backing_data = u8_r(gen + Str8Gen_backing + AllocatorInfo_data)[0]; + assert(backing_proc != null); + if (needed > gen_cap) { + uvar(Slice_Mem, grown); + mem__grow__u(u8_(grown), backing_proc, backing_data, gen_ptr, gen_cap, needed, 0, 1, true); + gen_ptr = u8_r(u8_(grown) + Slice_ptr)[0]; + gen_cap = u8_r(u8_(grown) + Slice_len)[0]; + u8_r(gen + Str8Gen_ptr)[0] = gen_ptr; + u8_r(gen + Str8Gen_cap)[0] = gen_cap; + } + mem_copy(gen_ptr + gen_len, str_ptr, str_len); + u8_r(gen + Str8Gen_len)[0] = needed; +} + +I_ void str8gen_append_str8(Str8Gen_R gen, Str8 str) { + str8gen_append_str8__u(u8_(gen), u8_(& str)); +} + +S_ void str8gen__append_fmt__u(U8 gen, U8 fmt_slice, U8 entries_slice) { + assert(gen != null); + assert(fmt_slice != null); + assert(entries_slice != null); + Str8 formatted = {0}; + str8__fmt__u(u8_(& formatted), fmt_slice, entries_slice); + str8gen_append_str8__u(gen, u8_(& formatted)); +} + +I_ void str8gen__append_fmt(Str8Gen_R gen, Str8 fmt_template, Slice_A2_Str8*R_ entries) { + str8gen__append_fmt__u(u8_(gen), u8_(& fmt_template), u8_(entries)); +} +#pragma endregion String Operations #pragma endregion Key Table #pragma region String Operations #pragma endregion String Operations #pragma region File System +#define MS_CREATE_ALWAYS 2 +#define MS_OPEN_EXISTING 3 +#define MS_GENERIC_READ (0x80000000L) +#define MS_GENERIC_WRITE (0x40000000L) +#define MS_FILE_SHARE_READ 0x00000001 +#define MS_FILE_SHARE_WRITE 0x00000002 +#define MS_FILE_ATTRIBUTE_NORMAL 0x00000080 +#define MS_INVALID_FILE_SIZE ((MS_DWORD)0xFFFFFFFF) +W_ MS_HANDLE ms_create_file_a( + MS_LPCSTR lpFileName, + MS_DWORD dwDesiredAccess, + MS_DWORD dwShareMode, + MS_LPSECURITY_ATTRIBUTES lpSecurityAttributes, + MS_DWORD dwCreationDisposition, + MS_DWORD dwFlagsAndAttributes, + MS_HANDLE hTemplateFile) __asm__("CreateFileA"); +W_ MS_BOOL ms_read_file( + MS_HANDLE hFile, + MS_LPVOID lpBuffer, + MS_DWORD nNumberOfBytesToRead, + MS_LPDWORD lpNumberOfBytesRead, + MS_LPOVERLAPPED lpOverlapped) __asm__("ReadFile"); +W_ MS_BOOL ms_write_file( + MS_HANDLE hFile, + MS_LPCVOID lpBuffer, + MS_DWORD nNumberOfBytesToWrite, + MS_LPDWORD lpNumberOfBytesWritten, + MS_LPOVERLAPPED lpOverlapped) __asm__("WriteFile"); +W_ MS_BOOL ms_get_file_size_ex(MS_HANDLE hFile, MS_LARGE_INTEGER* lpFileSize) __asm__("GetFileSizeEx"); +W_ MS_DWORD ms_get_last_error(void) __asm__("GetLastError"); + +S_ void file_read_contents__u(U8 path_ptr, U8 path_len, U8 backing_proc, U8 backing_data, B4 zero_backing, U8 result) { + assert(result != null); + slice_clear(result + FileOpInfo_content); + assert(backing_proc != null); + if (path_ptr == null || path_len == 0) { + assert(false && "Invalid path"); + return; + } + + LP_ B1 scratch[FILE_PATH_SCRATCH_CAP]; + U8 scratch_ptr = u8_(scratch); + U8 scratch_cap = FILE_PATH_SCRATCH_CAP; + U8 max_copy = scratch_cap ? scratch_cap - 1 : 0; + U8 copy_len = path_len < max_copy ? path_len : max_copy; + mem_copy(scratch_ptr, path_ptr, copy_len); + u1_r(scratch_ptr)[copy_len] = 0; + + MS_HANDLE id_file = ms_create_file_a( + cast(MS_LPCSTR, scratch_ptr), + MS_GENERIC_READ, + MS_FILE_SHARE_READ, + null, + MS_OPEN_EXISTING, + MS_FILE_ATTRIBUTE_NORMAL, + null + ); + if (id_file == MS_INVALID_HANDLE_VALUE) { + MS_DWORD error_code = ms_get_last_error(); + assert(error_code != 0); + return; + } + + MS_LARGE_INTEGER file_size = {0}; + if (! ms_get_file_size_ex(id_file, & file_size)) { + ms_close_handle(id_file); + return; + } + U8 desired_size = cast(U8, file_size.QuadPart); + uvar(Slice_Mem, buffer); + mem__alloc__u(u8_(buffer), backing_proc, backing_data, desired_size, 0, /*no_zero*/1); + U8 buffer_ptr = u8_r(u8_(buffer) + Slice_ptr)[0]; + U8 buffer_len = u8_r(u8_(buffer) + Slice_len)[0]; + if (buffer_ptr == 0 || buffer_len < file_size.QuadPart) { + ms_close_handle(id_file); + return; + } + if (zero_backing) { + mem_zero(buffer_ptr, buffer_len); + } + + MS_DWORD amount_read = 0; + MS_BOOL read_result = ms_read_file( + id_file, + cast(MS_LPVOID, buffer_ptr), + cast(MS_DWORD, desired_size), + u8_(& amount_read), + null + ); + ms_close_handle(id_file); + if (!read_result || amount_read != cast(MS_DWORD, desired_size)) { + return; + } + slice_assign_comp(result + FileOpInfo_content, buffer_ptr, desired_size); +} + +I_ FileOpInfo file__read_contents(Str8 path, Opts_read_file_contents*R_ opts) { + assert(opts != nullptr); + assert(opts->backing.proc != nullptr); + FileOpInfo info = {0}; + file_read_contents__u(path.ptr, path.len, u8_(opts->backing.proc), opts->backing.data, opts->zero_backing, u8_(& info)); + return info; +} + +S_ void file_write_str8__u(U8 path_ptr, U8 path_len, U8 content_ptr, U8 content_len) { + if (path_ptr == null || path_len == 0) { + assert(false && "Invalid path"); + return; + } + if (content_ptr == null) { + assert(false && "Invalid content"); + return; + } + + LP_ B1 scratch[FILE_PATH_SCRATCH_CAP] = {0}; + U8 scratch_ptr = u8_(scratch); + U8 scratch_cap = FILE_PATH_SCRATCH_CAP; + U8 max_copy = scratch_cap ? scratch_cap - 1 : 0; + U8 copy_len = path_len < max_copy ? path_len : max_copy; + mem_copy(scratch_ptr, path_ptr, copy_len); + u1_r(scratch_ptr)[copy_len] = 0; + + MS_HANDLE id_file = ms_create_file_a( + cast(MS_LPCSTR, scratch_ptr), + MS_GENERIC_WRITE, + MS_FILE_SHARE_READ, + null, + MS_CREATE_ALWAYS, + MS_FILE_ATTRIBUTE_NORMAL, + null + ); + if (id_file == MS_INVALID_HANDLE_VALUE) { + MS_DWORD error_code = ms_get_last_error(); + assert(error_code != 0); + return; + } + MS_DWORD bytes_written = 0; + MS_BOOL status = ms_write_file( + id_file, + cast(MS_LPCVOID, content_ptr), + cast(MS_DWORD, content_len), + u8_(& bytes_written), + null + ); + ms_close_handle(id_file); + assert(status != 0); + assert(bytes_written == content_len); +} + +I_ void file_write_str8(Str8 path, Str8 content) { + file_write_str8__u(path.ptr, path.len, content.ptr, content.len); +} #pragma endregion File System +#pragma region WATL +#define WATL_ALLOC_STRUCT(dest, proc, data, type, zero) \ + do { \ + uvar(Slice_Mem, _alloc_slice); \ + mem__alloc__u(u8_(_alloc_slice), proc, data, size_of(type), alignof(type), zero); \ + dest = u8_r(u8_(_alloc_slice) + Slice_ptr)[0]; \ + } while (0) + +S_ void watl_lex__u(U8 info, U8 source, U8 opts) { + if (info == null || source == null || opts == null) { return; } + U8 src_ptr = u8_r(source + Str8_ptr)[0]; + U8 src_len = u8_r(source + Str8_len)[0]; + if (src_len == 0) { return; } + + U8 ainfo_msgs = opts + Opts_watl_lex_ainfo_msgs; + U8 ainfo_toks = opts + Opts_watl_lex_ainfo_toks; + U8 msgs_proc = u8_r(ainfo_msgs + AllocatorInfo_proc)[0]; assert(msgs_proc != null); + U8 msgs_data = u8_r(ainfo_msgs + AllocatorInfo_data)[0]; + U8 toks_proc = u8_r(ainfo_toks + AllocatorInfo_proc)[0]; assert(toks_proc != null); + U8 toks_data = u8_r(ainfo_toks + AllocatorInfo_data)[0]; + U8 fail_slice = u1_r(opts + Opts_watl_lex_failon_slice_constraint_fail)[0]; + + u8_r(info + WATL_LexInfo_msgs)[0] = 0; + u8_r(info + WATL_LexInfo_toks + Slice_ptr)[0] = 0; + u8_r(info + WATL_LexInfo_toks + Slice_len)[0] = 0; + u4_r(info + WATL_LexInfo_signal)[0] = 0; + + U8 msg_last = 0; + U8 first_tok = 0; + U8 tok = 0; + U8 tok_count = 0; + B4 was_formatting = true; + + U8 cursor = src_ptr; + U8 end = src_ptr + src_len; + U1 prev_code = 0; + +#define WATL_ALLOC_TOK(dest) WATL_ALLOC_STRUCT(dest, toks_proc, toks_data, WATL_Tok, 1) +#define WATL_ALLOC_LEX_MSG(dest) WATL_ALLOC_STRUCT(dest, msgs_proc, msgs_data, WATL_LexMsg, 0) + + while (cursor < end) { + U1 code = u1_r(cursor)[0]; + switch (code) { + case WATL_Tok_Space: + case WATL_Tok_Tab: { + if (tok == 0 || prev_code != code) { + U8 new_tok = 0; + WATL_ALLOC_TOK(new_tok); + if (tok != 0 && new_tok != tok + size_of(WATL_Tok)) { goto slice_constraint_fail; } + tok = new_tok; + if (first_tok == 0) { first_tok = tok; } + u8_r(tok + Str8_ptr)[0] = cursor; + u8_r(tok + Str8_len)[0] = 0; + was_formatting = true; + ++ tok_count; + } + cursor += 1; + u8_r(tok + Str8_len)[0] += 1; + } break; + + case WATL_Tok_LineFeed: { + U8 new_tok = 0; + WATL_ALLOC_TOK(new_tok); + if (tok != 0 && new_tok != tok + size_of(WATL_Tok)) { goto slice_constraint_fail; } + tok = new_tok; + if (first_tok == 0) { first_tok = tok; } + u8_r(tok + Str8_ptr)[0] = cursor; + u8_r(tok + Str8_len)[0] = 1; + cursor += 1; + was_formatting = true; + ++ tok_count; + } break; + + case WATL_Tok_CarriageReturn: { + U8 new_tok = 0; + WATL_ALLOC_TOK(new_tok); + if (tok != 0 && new_tok != tok + size_of(WATL_Tok)) { goto slice_constraint_fail; } + tok = new_tok; + if (first_tok == 0) { first_tok = tok; } + U8 advance = ((cursor + 1) < end && u1_r(cursor + 1)[0] == WATL_Tok_LineFeed) ? 2 : 1; + u8_r(tok + Str8_ptr)[0] = cursor; + u8_r(tok + Str8_len)[0] = advance; + cursor += advance; + was_formatting = true; + ++ tok_count; + } break; + + default: { + if (was_formatting || tok == 0) { + U8 new_tok = 0; + WATL_ALLOC_TOK(new_tok); + if (tok != 0 && new_tok != tok + size_of(WATL_Tok)) { goto slice_constraint_fail; } + tok = new_tok; + if (first_tok == 0) { first_tok = tok; } + u8_r(tok + Str8_ptr)[0] = cursor; + u8_r(tok + Str8_len)[0] = 0; + was_formatting = false; + ++ tok_count; + } + cursor += 1; + u8_r(tok + Str8_len)[0] += 1; + } break; + } + prev_code = code; + } + + if (first_tok == 0) { return; } + u8_r(info + WATL_LexInfo_toks + Slice_ptr)[0] = first_tok; + u8_r(info + WATL_LexInfo_toks + Slice_len)[0] = tok_count; + return; + +slice_constraint_fail: { + u4_r(info + WATL_LexInfo_signal)[0] |= WATL_LexStatus_MemFail_SliceConstraintFail; + U8 msg = 0; + WATL_ALLOC_LEX_MSG(msg); + u8_r(msg + WATL_LexMsg_next)[0] = 0; + Str8 msg_content = lit("Token slice allocation was not contiguous"); + u8_r(msg + WATL_LexMsg_content + Str8_ptr)[0] = msg_content.ptr; + u8_r(msg + WATL_LexMsg_content + Str8_len)[0] = msg_content.len; + u8_r(msg + WATL_LexMsg_tok)[0] = tok; + u4_r(msg + WATL_LexMsg_pos + WATL_Pos_line)[0] = cast(U4, -1); + u4_r(msg + WATL_LexMsg_pos + WATL_Pos_column)[0] = cast(U4, -1); + if (u8_r(info + WATL_LexInfo_msgs)[0] == 0) { + u8_r(info + WATL_LexInfo_msgs)[0] = msg; + } else { + u8_r(msg_last + WATL_LexMsg_next)[0] = msg; + } + msg_last = msg; + assert(fail_slice == false); + return; +} +#undef WATL_ALLOC_TOK +#undef WATL_ALLOC_LEX_MSG +#undef WATL_ALLOC_STRUCT +} + +I_ void api_watl_lex(WATL_LexInfo_R info, Str8 source, Opts_watl_lex*R_ opts) { + assert(info != nullptr); + assert(opts != nullptr); + watl_lex__u(u8_(info), u8_(& source), u8_(opts)); +} + +I_ WATL_LexInfo watl__lex(Str8 source, Opts_watl_lex*R_ opts) { + WATL_LexInfo info = {0}; + api_watl_lex(& info, source, opts); + return info; +} + +S_ void watl_parse__u(U8 info, U8 tokens, U8 opts) { + (void)info; (void)tokens; (void)opts; +} + +I_ void api_watl_parse(WATL_ParseInfo_R info, Slice_WATL_Tok tokens, Opts_watl_parse*R_ opts) { + assert(info != nullptr); + assert(opts != nullptr); + watl_parse__u(u8_(info), u8_(& tokens), u8_(opts)); +} + +I_ WATL_ParseInfo watl__parse(Slice_WATL_Tok tokens, Opts_watl_parse*R_ opts) { + WATL_ParseInfo info = {0}; + api_watl_parse(& info, tokens, opts); + return info; +} + +S_ void watl_dump_listing__u(U8 result, U8 buffer_ainfo, U8 lines) { + (void)result; (void)buffer_ainfo; (void)lines; +} + +I_ Str8 watl_dump_listing(AllocatorInfo buffer, Slice_WATL_Line lines) { + Str8 out = {0}; + watl_dump_listing__u(u8_(& out), u8_(& buffer), u8_(& lines)); + return out; +} +#pragma endregion WATL + #pragma region Debug #if defined(BUILD_DEBUG) // #include diff --git a/C/watl.v0.msvc.c b/C/watl.v0.msvc.c index c8b9530..de1b20f 100644 --- a/C/watl.v0.msvc.c +++ b/C/watl.v0.msvc.c @@ -930,7 +930,7 @@ void farena_allocator_proc(AllocatorProc_In in, AllocatorProc_Out* out) #define MS_ANYSIZE_ARRAY 1 #define MS_MEM_COMMIT 0x00001000 #define MS_MEM_RESERVE 0x00002000 -#define MS_MEM_RELEASE 0x00008000 +#define MS_MEM_RELEASE 0x00002000 #define MS_MEM_LARGE_PAGES 0x20000000 #define MS_PAGE_READWRITE 0x04 #define MS_TOKEN_ADJUST_PRIVILEGES (0x0020) @@ -1023,7 +1023,7 @@ internal inline B32 os__vmem_commit(void* vm, SSIZE size, Opts_vmem* opts) { B32 result = (VirtualAlloc(vm, size, MS_MEM_COMMIT, MS_PAGE_READWRITE) != 0); return result; } -internal inline void os_vmem_release(void* vm, SSIZE size) { VirtualFree(vm, 0, MS_MEM_RELEASE); } +internal inline void os_vmem_release(void* vm, SSIZE size) { VirtualFree(vm, 0, MS_MEM_RESERVE); } #pragma endregion OS #pragma region VArena (Virutal Address Space Arena)