This commit is contained in:
2026-02-21 12:11:39 -05:00
parent b5e038f909
commit fcc4d4a515
7 changed files with 2648 additions and 136 deletions

View File

@@ -60,8 +60,9 @@ Here is a breakdown of the next steps to advance the `attempt_1` implementation
* The tape and annotations are currently lost when the program closes. * The tape and annotations are currently lost when the program closes.
* Move away from purely transient `VirtualAlloc` buffers to a memory-mapped file approach (or a manual Save/Load equivalent in WinAPI) to allow the "executable as source" to persist between sessions. * Move away from purely transient `VirtualAlloc` buffers to a memory-mapped file approach (or a manual Save/Load equivalent in WinAPI) to allow the "executable as source" to persist between sessions.
4. **Refine Visual Editor Interactions:** 4. ~~**Refine Visual Editor Interactions:**~~ (Completed via `microui` integration)
* Implement a proper internal text-editing cursor within the `STag_Data` and `STag_Format` (annotation) tokens, rather than relying on backspace-truncation and appendage. * Implement a proper internal text-editing cursor within the `STag_Data` and `STag_Format` (annotation) tokens, rather than relying on backspace-truncation and appendage.
* Migrated to `microui` for immediate mode GUI floating panels, auto-layout token sizing (for a natural text look), and window resizing.
5. **Continuous Validation & Complex Control Flow:** 5. **Continuous Validation & Complex Control Flow:**
* Expand the primitive set to allow for more complex, AST-less control flow (e.g., handling Lambdas or specific Basic Block jumps). * Expand the primitive set to allow for more complex, AST-less control flow (e.g., handling Lambdas or specific Basic Block jumps).

View File

@@ -676,6 +676,11 @@ WinAPI void* ms_create_font_a(
U4 iPitchAndFamily, U4 iPitchAndFamily,
char const* pszFaceName char const* pszFaceName
) asm("CreateFontA"); ) asm("CreateFontA");
WinAPI void* ms_create_compatible_dc(void* hdc) asm("CreateCompatibleDC");
WinAPI void* ms_create_compatible_bitmap(void* hdc, S4 cx, S4 cy) asm("CreateCompatibleBitmap");
WinAPI B4 ms_bit_blt(void* hdcDest, S4 x, S4 y, S4 w, S4 h, void* hdcSrc, S4 xSrc, S4 ySrc, U4 rop) asm("BitBlt");
WinAPI B4 ms_delete_dc(void* hdc) asm("DeleteDC");
WinAPI B4 ms_get_client_rect(void* hwnd, MS_RECT* lpRect) asm("GetClientRect");
WinAPI void* ms_select_object(void* hdc, void* h) asm("SelectObject"); WinAPI void* ms_select_object(void* hdc, void* h) asm("SelectObject");
WinAPI S4 ms_rectangle(void* hdc, S4 left, S4 top, S4 right, S4 bottom) asm("Rectangle"); WinAPI S4 ms_rectangle(void* hdc, S4 left, S4 top, S4 right, S4 bottom) asm("Rectangle");
WinAPI S4 ms_set_bk_mode(void* hdc, S4 mode) asm("SetBkMode"); WinAPI S4 ms_set_bk_mode(void* hdc, S4 mode) asm("SetBkMode");
@@ -685,9 +690,21 @@ WinAPI S4 ms_delete_object(void* ho) asm("
#define MS_MEM_COMMIT 0x00001000 #define MS_MEM_COMMIT 0x00001000
#define MS_MEM_RESERVE 0x00002000 #define MS_MEM_RESERVE 0x00002000
#define MS_PAGE_READWRITE 0x04 #define MS_PAGE_READWRITE 0x04
#define MS_SRCCOPY 0x00CC0020
#define MS_WM_DESTROY 0x0002 #define MS_WM_DESTROY 0x0002
#define MS_WM_SIZE 0x0005
#define MS_WM_PAINT 0x000F #define MS_WM_PAINT 0x000F
#define MS_WM_ERASEBKGND 0x0014
#define MS_WM_KEYDOWN 0x0100 #define MS_WM_KEYDOWN 0x0100
#define MS_WM_KEYUP 0x0101
#define MS_WM_MOUSEMOVE 0x0200
#define MS_WM_LBUTTONDOWN 0x0201
#define MS_WM_LBUTTONUP 0x0202
#define MS_WM_RBUTTONDOWN 0x0204
#define MS_WM_RBUTTONUP 0x0205
#define MS_WM_MBUTTONDOWN 0x0207
#define MS_WM_MBUTTONUP 0x0208
#define MS_WM_MOUSEWHEEL 0x020A
#define MS_WS_OVERLAPPEDWINDOW 0x00CF0000 #define MS_WS_OVERLAPPEDWINDOW 0x00CF0000
#define MS_WS_VISIBLE 0x10000000 #define MS_WS_VISIBLE 0x10000000
#define MS_VK_LEFT 0x25 #define MS_VK_LEFT 0x25

View File

@@ -465,13 +465,76 @@ IA_ void compile_and_run_tape(void)
debug_log(str8("JIT finished. RAX: <rax>, RDX: <rdx>"), ktl_str8_from_arr(post_jit_log_table)); debug_log(str8("JIT finished. RAX: <rax>, RDX: <rdx>"), ktl_str8_from_arr(post_jit_log_table));
} }
#undef r
#undef v
#undef expect
#include "microui.c"
#undef expect
#define expect(x,y) __builtin_expect(x, y) // so compiler knows the common path
#define r restrict
#define v volatile
global mu_Context mu_ctx;
internal int text_width_cb(mu_Font font, const char *str, int len) {
if (len == -1) { len = 0; while (str[len]) len++; }
return len * 11; // Approx 11px per char for Consolas 20
}
internal int text_height_cb(mu_Font font) {
return 20; // Consolas 20 height
}
internal void gdi_draw_rect(void* hdc, mu_Rect rect, mu_Color color) {
U1 red = ((U1*)&color)[0];
U1 green = ((U1*)&color)[1];
U1 blue = ((U1*)&color)[2];
void* hBrush = ms_create_solid_brush((red) | (green << 8) | (blue << 16));
void* hOldBrush = ms_select_object(hdc, hBrush);
ms_rectangle(hdc, rect.x - 1, rect.y - 1, rect.x + rect.w + 1, rect.y + rect.h + 1);
ms_select_object(hdc, hOldBrush);
ms_delete_object(hBrush);
}
internal void render_microui(void* hdc) {
mu_Command *cmd = NULL;
while (mu_next_command(&mu_ctx, &cmd)) {
switch (cmd->type) {
case MU_COMMAND_TEXT: {
U1 red = ((U1*)&cmd->text.color)[0];
U1 green = ((U1*)&cmd->text.color)[1];
U1 blue = ((U1*)&cmd->text.color)[2];
ms_set_text_color(hdc, (red) | (green << 8) | (blue << 16));
int len = 0; while (cmd->text.str[len]) len++;
ms_text_out_a(hdc, cmd->text.pos.x, cmd->text.pos.y, cmd->text.str, len);
break;
}
case MU_COMMAND_RECT: {
gdi_draw_rect(hdc, cmd->rect.rect, cmd->rect.color);
break;
}
case MU_COMMAND_ICON: {
gdi_draw_rect(hdc, cmd->icon.rect, cmd->icon.color);
break;
}
case MU_COMMAND_CLIP: {
break;
}
}
}
}
S8 win_proc(void* hwnd, U4 msg, U8 wparam, S8 lparam) S8 win_proc(void* hwnd, U4 msg, U8 wparam, S8 lparam)
{ {
U8 tape_count = tape_arena.used / sizeof(U4); U8 tape_count = tape_arena.used / sizeof(U4);
U4*r tape_ptr = u4_r(tape_arena.start); U4*r tape_ptr = u4_r(tape_arena.start);
switch (msg) { switch (msg) {
case MS_WM_CHAR: { case MS_WM_CHAR: {
if (editor_mode != MODE_EDIT) return 0; char buf[2] = { (char)wparam, 0 };
mu_input_text(&mu_ctx, buf);
if (editor_mode != MODE_EDIT) { ms_invalidate_rect(hwnd, nullptr, true); return 0; }
U4 t = tape_ptr[cursor_idx]; U4 t = tape_ptr[cursor_idx];
U4 tag = unpack_tag(t); U4 tag = unpack_tag(t);
@@ -479,7 +542,7 @@ S8 win_proc(void* hwnd, U4 msg, U8 wparam, S8 lparam)
U1 c = u1_(wparam); U1 c = u1_(wparam);
B4 should_skip = c < 32 || (c == 'e' && mode_switch_now); B4 should_skip = c < 32 || (c == 'e' && mode_switch_now);
if (should_skip) { mode_switch_now = false; return 0; } if (should_skip) { mode_switch_now = false; ms_invalidate_rect(hwnd, nullptr, true); return 0; }
if (tag == STag_Data) { if (tag == STag_Data) {
U4 digit = 16; U4 digit = 16;
@@ -512,7 +575,34 @@ S8 win_proc(void* hwnd, U4 msg, U8 wparam, S8 lparam)
ms_invalidate_rect(hwnd, nullptr, true); ms_invalidate_rect(hwnd, nullptr, true);
return 0; return 0;
} }
case MS_WM_MOUSEMOVE: {
mu_input_mousemove(&mu_ctx, lparam & 0xFFFF, (lparam >> 16) & 0xFFFF);
ms_invalidate_rect(hwnd, nullptr, true);
return 0;
}
case MS_WM_LBUTTONDOWN: {
mu_input_mousedown(&mu_ctx, lparam & 0xFFFF, (lparam >> 16) & 0xFFFF, MU_MOUSE_LEFT);
ms_invalidate_rect(hwnd, nullptr, true);
return 0;
}
case MS_WM_LBUTTONUP: {
mu_input_mouseup(&mu_ctx, lparam & 0xFFFF, (lparam >> 16) & 0xFFFF, MU_MOUSE_LEFT);
ms_invalidate_rect(hwnd, nullptr, true);
return 0;
}
case MS_WM_MOUSEWHEEL: {
mu_input_scroll(&mu_ctx, 0, ((S4)(wparam >> 16)) / -30);
ms_invalidate_rect(hwnd, nullptr, true);
return 0;
}
case MS_WM_KEYDOWN: { case MS_WM_KEYDOWN: {
int key = 0;
if (wparam == MS_VK_BACK) key = MU_KEY_BACKSPACE;
if (wparam == MS_VK_RETURN) key = MU_KEY_RETURN;
if (wparam == 0x10) key = MU_KEY_SHIFT;
if (wparam == 0x11) key = MU_KEY_CTRL;
if (wparam == 0x12) key = MU_KEY_ALT;
if (key) mu_input_keydown(&mu_ctx, key);
if (wparam == 0x45 && editor_mode == MODE_NAV) { if (wparam == 0x45 && editor_mode == MODE_NAV) {
editor_mode = MODE_EDIT; editor_mode = MODE_EDIT;
@@ -650,115 +740,122 @@ S8 win_proc(void* hwnd, U4 msg, U8 wparam, S8 lparam)
ms_invalidate_rect(hwnd, nullptr, true); ms_invalidate_rect(hwnd, nullptr, true);
return 0; return 0;
} }
case MS_WM_KEYUP: {
int key = 0;
if (wparam == MS_VK_BACK) key = MU_KEY_BACKSPACE;
if (wparam == MS_VK_RETURN) key = MU_KEY_RETURN;
if (wparam == 0x10) key = MU_KEY_SHIFT;
if (wparam == 0x11) key = MU_KEY_CTRL;
if (wparam == 0x12) key = MU_KEY_ALT;
if (key) mu_input_keyup(&mu_ctx, key);
ms_invalidate_rect(hwnd, nullptr, true);
return 0;
}
case MS_WM_SIZE: {
ms_invalidate_rect(hwnd, nullptr, true);
return 0;
}
case MS_WM_ERASEBKGND: {
return 1;
}
case MS_WM_PAINT: { case MS_WM_PAINT: {
MS_PAINTSTRUCT ps; mu_begin(&mu_ctx);
void* hdc = ms_begin_paint(hwnd, & ps);
void* hFont = ms_create_font_a(20, 0, 0, 0, 400, 0, 0, 0, 0, 0, 0, 0, 0, "Consolas");
void* hOldFont = ms_select_object(hdc, hFont);
ms_set_bk_mode(hdc, 1); if (mu_begin_window(&mu_ctx, "ColorForth Source Tape", mu_rect(10, 10, 900, 480))) {
U4*r tape_ptr = u4_r(tape_arena.start);
U8*r anno_ptr = u8_r(anno_arena.start);
void* hBgBrush = ms_create_solid_brush(0x00222222); S4 start_x = 5, start_y = 5, spacing_x = 6, spacing_y = 26;
ms_select_object(hdc, hBgBrush); S4 x = start_x, y = start_y;
ms_rectangle(hdc, -1, -1, 3000, 3000);
void* hBrushEdit = ms_create_solid_brush(0x008E563B); for (U8 i = 0; i < tape_count; i++) {
void* hBrushNav = ms_create_solid_brush(0x00262F3B); U4 t = tape_ptr[i];
U4 tag = unpack_tag(t);
U4 val = unpack_val(t);
U8 anno = anno_ptr[i];
S4 start_x = 40, start_y = 60, spacing_x = 110, spacing_y = 35; if (tag == STag_Format && val == 0xA) {
S4 x = start_x, y = start_y; x = start_x;
y += spacing_y;
continue;
}
U4*r tape_ptr = u4_r(tape_arena.start); U4 color_u32 = tag_colors[tag];
U8*r anno_ptr = u8_r(anno_arena.start); const char* prefix = tag_prefixes[tag];
for (U8 i = 0; i < tape_count; i++) char val_str[9];
{ if (tag == STag_Data) {
if (x >= start_x + (TOKENS_PER_ROW * spacing_x)) { u64_to_hex(val, val_str, 6);
x = start_x; y += spacing_y; val_str[6] = '\0';
} }
S4 render_y = y - scroll_y_offset; else
if (i == cursor_idx && render_y >= 30 && render_y < 500) { {
ms_select_object(hdc, editor_mode == MODE_EDIT ? hBrushEdit : hBrushNav); char* a_str = (char*) & anno;
ms_rectangle(hdc, x - 5, render_y - 2, x + 95, render_y + 22); for(int c=0; c<8; c++) {
} val_str[c] = a_str[c] ? a_str[c] : ' ';
if (render_y >= 30 && render_y < 500) }
{ val_str[8] = '\0';
U4 t = tape_ptr[i]; }
U4 tag = unpack_tag(t); char out_buf[12];
U4 val = unpack_val(t); out_buf[0] = prefix[0];
U8 anno = anno_ptr[i]; out_buf[1] = ' ';
if (tag == STag_Format && val == 0xA) { mem_copy(u8_(out_buf + 2), u8_(val_str), 8);
ms_set_text_color(hdc, 0x00444444); out_buf[10] = '\0';
ms_text_out_a(hdc, x, render_y, " \\n ", 6);
x = start_x;
y += spacing_y;
}
else
{
U4 color = tag_colors[tag];
const char* prefix = tag_prefixes[tag];
ms_set_text_color(hdc, color); int btn_w = 20 + text_width_cb(NULL, out_buf, 10);
if (editor_mode == MODE_EDIT && i == cursor_idx) {
ms_set_text_color(hdc, 0x001E1E1E);
}
char val_str[9]; // auto-wrap
if (tag == STag_Data) { mu_Container* current_window = mu_get_current_container(&mu_ctx);
u64_to_hex(val, val_str, 6); if (x + btn_w > current_window->body.w - 15) {
val_str[6] = '\0'; x = start_x;
} y += spacing_y;
else }
{
char* a_str = (char*) & anno;
for(int c=0; c<8; c++) {
val_str[c] = a_str[c] ? a_str[c] : ' ';
}
val_str[8] = '\0';
}
char out_buf[12];
out_buf[0] = prefix[0];
out_buf[1] = ' ';
mem_copy(u8_(out_buf + 2), u8_(val_str), 8);
out_buf[10] = '\0';
ms_text_out_a(hdc, x, render_y, out_buf, 10); mu_ctx.style->colors[MU_COLOR_BUTTON] = mu_color(color_u32 & 0xFF, (color_u32 >> 8) & 0xFF, (color_u32 >> 16) & 0xFF, 255);
x += spacing_x;
}
}
else if (unpack_tag(tape_ptr[i]) == STag_Format && unpack_val(tape_ptr[i]) == 0xA) {
x = start_x;
y += spacing_y;
}
else {
x += spacing_x;
}
}
void* hHudBrush = ms_create_solid_brush(0x00141E23); if (i == cursor_idx && editor_mode == MODE_EDIT) {
ms_select_object(hdc, hHudBrush); mu_ctx.style->colors[MU_COLOR_TEXT] = mu_color(0,0,0,255);
ms_rectangle(hdc, -1, 500, 3000, 3000); mu_ctx.style->colors[MU_COLOR_BUTTON] = mu_color(0x8E, 0x56, 0x3B, 255);
ms_rectangle(hdc, -1, -1, 3000, 40); } else if (i == cursor_idx && editor_mode == MODE_NAV) {
mu_ctx.style->colors[MU_COLOR_BUTTON] = mu_color(0x26, 0x2F, 0x3B, 255);
}
ms_set_text_color(hdc, 0x00AAAAAA); mu_layout_set_next(&mu_ctx, mu_rect(x, y, btn_w, 22), 1);
ms_text_out_a(hdc, 40, 10, "x86-64 Machine Code Emitter | 2-Reg Stack | [F5] Toggle Run Mode | [PgUp/PgDn] Scroll", 85);
ms_set_text_color(hdc, 0x00FFFFFF); if (mu_button(&mu_ctx, out_buf)) {
char jit_str[64] = "Mode: Incremental | JIT Size: 0x000 bytes"; cursor_idx = i;
editor_mode = MODE_NAV;
}
x += btn_w + spacing_x;
mu_ctx.style->colors[MU_COLOR_BUTTON] = mu_color(75, 75, 75, 255);
mu_ctx.style->colors[MU_COLOR_TEXT] = mu_color(230, 230, 230, 255);
}
// Dummy element to ensure scrolling bounds are correct
mu_layout_set_next(&mu_ctx, mu_rect(start_x, y + spacing_y, 10, 10), 1);
mu_draw_rect(&mu_ctx, mu_layout_next(&mu_ctx), mu_color(0,0,0,0));
mu_end_window(&mu_ctx);
}
if (mu_begin_window(&mu_ctx, "HUD / Memory", mu_rect(10, 500, 900, 200))) {
char jit_str[64] = "Mode: Incremental | JIT Size: 0x000 bytes";
if (run_full) mem_copy(u8_(jit_str + 6), u8_("Full "), 11); if (run_full) mem_copy(u8_(jit_str + 6), u8_("Full "), 11);
u64_to_hex(code_arena.used, jit_str + 32, 3); u64_to_hex(code_arena.used, jit_str + 32, 3);
ms_text_out_a(hdc, 40, 520, jit_str, 41); mu_layout_row(&mu_ctx, 1, (int[]){-1}, 0);
mu_text(&mu_ctx, "x86-64 Machine Code Emitter | 2-Reg Stack | [F5] Toggle Run Mode | [PgUp/PgDn] Scroll");
mu_text(&mu_ctx, jit_str);
char state_str[64] = "RAX: 00000000 | RDX: 00000000"; char state_str[64] = "RAX: 00000000 | RDX: 00000000";
u64_to_hex(vm_rax, state_str + 5, 8); u64_to_hex(vm_rax, state_str + 5, 8);
u64_to_hex(vm_rdx, state_str + 21, 8); u64_to_hex(vm_rdx, state_str + 21, 8);
ms_set_text_color(hdc, 0x0094BAA1); mu_text(&mu_ctx, state_str);
ms_text_out_a(hdc, 40, 550, state_str, 29);
if (tape_count > 0 && cursor_idx < tape_count) { if (tape_count > 0 && cursor_idx < tape_count) {
U4 cur_tag = unpack_tag(tape_ptr[cursor_idx]); U4 cur_tag = unpack_tag(tape_ptr[cursor_idx]);
const char* tag_name = tag_names [cur_tag]; const char* tag_name = tag_names [cur_tag];
U4 cur_color = tag_colors[cur_tag];
char semantics_str[64] = "Current Tag: "; char semantics_str[64] = "Current Tag: ";
U4 name_len = 0; U4 name_len = 0;
while (tag_name[name_len]) { while (tag_name[name_len]) {
@@ -766,47 +863,48 @@ S8 win_proc(void* hwnd, U4 msg, U8 wparam, S8 lparam)
name_len ++; name_len ++;
} }
semantics_str[13 + name_len] = '\0'; semantics_str[13 + name_len] = '\0';
ms_set_text_color(hdc, cur_color); mu_text(&mu_ctx, semantics_str);
ms_text_out_a(hdc, 40, 580, semantics_str, 13 + name_len);
}
ms_set_text_color(hdc, 0x00C8C8C8);
ms_text_out_a(hdc, 400, 520, "Global Memory (Contiguous Array):", 33);
for (int i=0; i < 4; i ++) {
char glob_str[32] = "[0]: 00000000";
glob_str[1] = '0' + i;
u64_to_hex(vm_globals[i], glob_str + 5, 8);
ms_set_text_color(hdc, 0x00D6A454);
ms_text_out_a(hdc, 400, 550 + (i * 25), glob_str, 13);
}
ms_set_text_color(hdc, 0x00C8C8C8);
ms_text_out_a(hdc, 750, 520, "Print Log:", 10);
for (int i = 0; i<log_count && i < 4; i ++) {
char log_str[32] = "00000000";
u64_to_hex(log_buffer[i], log_str, 8);
ms_set_text_color(hdc, 0x0094BAA1);
ms_text_out_a(hdc, 750, 550 + (i * 25), log_str, 8);
}
ms_set_text_color(hdc, 0x00C8C8C8);
ms_text_out_a(hdc, 40, 650, "Debug Log:", 10);
for (U4 i = 0; i < gdi_log_count; i++) {
U4 len = 0;
while(gdi_log_buffer[i][len] != '\0' && len < GDI_LOG_MAX_LINE_LEN) {
len++;
}
ms_set_text_color(hdc, 0x00AAAAAA);
ms_text_out_a(hdc, 40, 670 + (i * 20), gdi_log_buffer[i], len);
} }
mu_end_window(&mu_ctx);
}
ms_select_object(hdc, hOldFont); mu_end(&mu_ctx);
ms_delete_object(hBgBrush);
ms_delete_object(hBrushEdit); MS_PAINTSTRUCT ps;
ms_delete_object(hBrushNav); void* hdc = ms_begin_paint(hwnd, & ps);
ms_delete_object(hHudBrush);
ms_end_paint(hwnd, & ps); MS_RECT rect;
return 0; ms_get_client_rect(hwnd, &rect);
S4 width = rect.right - rect.left;
S4 height = rect.bottom - rect.top;
void* memDC = ms_create_compatible_dc(hdc);
void* memBitmap = ms_create_compatible_bitmap(hdc, width, height);
void* oldBitmap = ms_select_object(memDC, memBitmap);
void* hFont = ms_create_font_a(20, 0, 0, 0, 400, 0, 0, 0, 0, 0, 0, 0, 0, "Consolas");
void* hOldFont = ms_select_object(memDC, hFont);
ms_set_bk_mode(memDC, 1);
void* hBgBrush = ms_create_solid_brush(0x00222222);
ms_select_object(memDC, hBgBrush);
ms_rectangle(memDC, -1, -1, width + 2, height + 2);
render_microui(memDC);
ms_bit_blt(hdc, 0, 0, width, height, memDC, 0, 0, MS_SRCCOPY);
ms_select_object(memDC, hOldFont);
ms_delete_object(hBgBrush);
ms_delete_object(hFont);
ms_select_object(memDC, oldBitmap);
ms_delete_object(memBitmap);
ms_delete_dc(memDC);
ms_end_paint(hwnd, & ps);
return 0;
} }
case MS_WM_DESTROY: { ms_post_quit_message(0); return 0; } case MS_WM_DESTROY: { ms_post_quit_message(0); return 0; }
} }
@@ -823,6 +921,10 @@ int main(void) {
farena_init(& anno_arena, anno_mem); farena_init(& anno_arena, anno_mem);
farena_init(& code_arena, code_mem); farena_init(& code_arena, code_mem);
mu_init(&mu_ctx);
mu_ctx.text_width = text_width_cb;
mu_ctx.text_height = text_height_cb;
scatter(pack_token(STag_Comment, 0), "INIT "); scatter(pack_token(STag_Comment, 0), "INIT ");
scatter(pack_token(STag_Data, 5), 0); scatter(pack_token(STag_Data, 5), 0);
scatter(pack_token(STag_Data, 0), 0); scatter(pack_token(STag_Data, 0), 0);

888
attempt_1/main.c.bak Normal file
View File

@@ -0,0 +1,888 @@
#include "duffle.amd64.win32.h"
// --- Semantic Tags (Using X-Macros & Enum_) ---
#define Tag_Entries() \
X(Define, "Define", 0x0018AEFF, ":") \
X(Call, "Call", 0x00D6A454, "~") \
X(Data, "Data", 0x0094BAA1, "$") \
X(Imm, "Imm", 0x004AA4C2, "^") \
X(Comment, "Comment", 0x00AAAAAA, ".") \
X(Format, "Format", 0x003A2F3B, " ")
typedef Enum_(U4, STag) {
#define X(n, s, c, p) tmpl(STag, n),
Tag_Entries()
#undef X
STag_Count,
};
global U4 tag_colors[] = {
#define X(n, s, c, p) c,
Tag_Entries()
#undef X
};
global const char* tag_prefixes[] = {
#define X(n, s, c, p) p,
Tag_Entries()
#undef X
};
global const char* tag_names[] = {
#define X(n, s, c, p) s,
Tag_Entries()
#undef X
};
#define pack_token(tag, val) ((u4_(tag) << 28) | (u4_(val) & 0x0FFFFFFF))
#define unpack_tag(token) ( ((token) >> 28) & 0x0F)
#define unpack_val(token) ( (token) & 0x0FFFFFFF)
#define TOKENS_PER_ROW 8
#define MODE_NAV 0
#define MODE_EDIT 1
global FArena tape_arena;
global FArena anno_arena;
global U8 cursor_idx = 0;
global U4 editor_mode = MODE_NAV;
global B4 mode_switch_now = false;
global FArena code_arena;
global U8 vm_rax = 0;
global U8 vm_rdx = 0;
global U8 vm_globals[16] = {0};
global B4 run_full = false;
global U8 log_buffer[16] = {0};
global U4 log_count = 0;
global S4 scroll_y_offset = 0;
// New GDI log
#define GDI_LOG_MAX_LINES 10
#define GDI_LOG_MAX_LINE_LEN 128
global char gdi_log_buffer[GDI_LOG_MAX_LINES][GDI_LOG_MAX_LINE_LEN] = {0};
global U4 gdi_log_count = 0;
internal void debug_log(Str8 fmt, KTL_Str8 table) {
// A static buffer for our log lines.
LP_ UTF8 console_log_buffer[1024];
mem_zero(u8_(console_log_buffer), 1024);
// Format the string.
Str8 result = str8_fmt_ktl_buf(slice_ut_arr(console_log_buffer), table, fmt);
// Also write to our GDI log buffer
if (gdi_log_count < GDI_LOG_MAX_LINES) {
U4 len_to_copy = result.len < GDI_LOG_MAX_LINE_LEN - 1 ? result.len : GDI_LOG_MAX_LINE_LEN - 1;
mem_copy(u8_(gdi_log_buffer[gdi_log_count]), u8_(result.ptr), len_to_copy);
gdi_log_buffer[gdi_log_count][len_to_copy] = '\0';
gdi_log_count++;
}
// Get stdout handle.
MS_Handle stdout_handle = ms_get_std_handle(MS_STD_OUTPUT);
// Write the formatted string.
ms_write_console(stdout_handle, result.ptr, (U4)result.len, nullptr, 0);
// Write a newline.
ms_write_console(stdout_handle, (UTF8 const*r)"\n", 1, nullptr, 0);
}
U8 ms_builtin_print(U8 val, U8 rdx_val, U8 r8_val, U8 r9_val) {
char hex1[9], hex2[9], hex3[9], hex4[9];
u64_to_hex(val, hex1, 8); hex1[8] = '\0';
u64_to_hex(rdx_val, hex2, 8); hex2[8] = '\0';
u64_to_hex(r8_val, hex3, 8); hex3[8] = '\0';
u64_to_hex(r9_val, hex4, 8); hex4[8] = '\0';
KTL_Slot_Str8 log_table[] = {
{ ktl_str8_key("v1"), str8(hex1) },
{ ktl_str8_key("v2"), str8(hex2) },
{ ktl_str8_key("v3"), str8(hex3) },
{ ktl_str8_key("v4"), str8(hex4) },
};
debug_log(str8("FFI PRINT -> RCX:<v1> RDX:<v2> R8:<v3> R9:<v4>"), ktl_str8_from_arr(log_table));
if (log_count < 16) log_buffer[log_count++] = val;
return val;
}
// Visual Linker & O(1) Dictionary
global U4 tape_to_code_offset[65536] = {0};
// --- WinAPI Persistence ---
#define MS_GENERIC_READ 0x80000000
#define MS_GENERIC_WRITE 0x40000000
#define MS_CREATE_ALWAYS 2
#define MS_OPEN_EXISTING 3
#define MS_FILE_ATTRIBUTE_NORMAL 0x80
#define MS_VK_F1 0x70
#define MS_VK_F2 0x71
WinAPI void* ms_create_file_a(char const* lpFileName, U4 dwDesiredAccess, U4 dwShareMode, void* lpSecurityAttributes, U4 dwCreationDisposition, U4 dwFlagsAndAttributes, void* hTemplateFile) asm("CreateFileA");
WinAPI B4 ms_write_file(void* hFile, void const* lpBuffer, U4 nNumberOfBytesToWrite, U4* lpNumberOfBytesWritten, void* lpOverlapped) asm("WriteFile");
WinAPI B4 ms_read_file(void* hFile, void* lpBuffer, U4 nNumberOfBytesToRead, U4* lpNumberOfBytesRead, void* lpOverlapped) asm("ReadFile");
WinAPI B4 ms_close_handle(void* hObject) asm("CloseHandle");
#define PRIM_SWAP 1
#define PRIM_MULT 2
#define PRIM_ADD 3
#define PRIM_FETCH 4
#define PRIM_DEC 5
#define PRIM_STORE 6
#define PRIM_RET_Z 7
#define PRIM_RET 8
#define PRIM_PRINT 9
#define PRIM_RET_S 10
#define PRIM_DUP 11
#define PRIM_DROP 12
#define PRIM_SUB 13
global const char* prim_names[] = {
"",
"SWAP ",
"MULT ",
"ADD ",
"FETCH ",
"DEC ",
"STORE ",
"RET_IF_Z",
"RETURN ",
"PRINT ",
"RET_IF_S",
"DUP ",
"DROP ",
"SUB "
};
internal U4 resolve_name_to_index(const char* ref_name);
internal void relink_tape(void);
IA_ void compile_and_run_tape(void);
internal void save_cartridge(void) {
void* hFile = ms_create_file_a("cartridge.bin", MS_GENERIC_WRITE, 0, nullptr, MS_CREATE_ALWAYS, MS_FILE_ATTRIBUTE_NORMAL, nullptr);
if (hFile != (void*)-1) {
U4 written = 0;
ms_write_file(hFile, & tape_arena.used, 8, & written, nullptr);
ms_write_file(hFile, & anno_arena.used, 8, & written, nullptr);
ms_write_file(hFile, & cursor_idx, 8, & written, nullptr);
ms_write_file(hFile, (void*)tape_arena.start, (U4)tape_arena.used, & written, nullptr);
ms_write_file(hFile, (void*)anno_arena.start, (U4)anno_arena.used, & written, nullptr);
ms_close_handle(hFile);
}
}
internal void load_cartridge(void) {
void* hFile = ms_create_file_a("cartridge.bin", MS_GENERIC_READ, 0, nullptr, MS_OPEN_EXISTING, MS_FILE_ATTRIBUTE_NORMAL, nullptr);
if (hFile != (void*)-1) {
U4 read = 0;
ms_read_file(hFile, & tape_arena.used, 8, & read, nullptr);
ms_read_file(hFile, & anno_arena.used, 8, & read, nullptr);
ms_read_file(hFile, & cursor_idx, 8, & read, nullptr);
ms_read_file(hFile, (void*)tape_arena.start, (U4)tape_arena.used, & read, nullptr);
ms_read_file(hFile, (void*)anno_arena.start, (U4)anno_arena.used, & read, nullptr);
ms_close_handle(hFile);
relink_tape();
compile_and_run_tape();
}
}
IA_ void scatter(U4 token, const char* anno_str) {
if (tape_arena.used + sizeof(U4) <= tape_arena.capacity && anno_arena.used + sizeof(U8) <= anno_arena.capacity) {
U4 tag = unpack_tag(token);
U4 val = unpack_val(token);
if (anno_str && (tag == STag_Call || tag == STag_Imm)) {
val = resolve_name_to_index(anno_str);
}
U4*r ptr = u4_r(tape_arena.start + tape_arena.used);
ptr[0] = pack_token(tag, val);
tape_arena.used += sizeof(U4);
U8*r aptr = u8_r(anno_arena.start + anno_arena.used);
aptr[0] = 0;
if (anno_str) {
char* dest = (char*)aptr;
int i = 0; while(i < 8 && anno_str[i]) { dest[i] = anno_str[i]; i ++; }
}
anno_arena.used += sizeof(U8);
}
}
internal void emit8(U1 b) {
if (code_arena.used + 1 <= code_arena.capacity) {
u1_r(code_arena.start + code_arena.used)[0] = b;
code_arena.used += 1;
}
}
internal void emit32(U4 val) {
if (code_arena.used + 4 <= code_arena.capacity) {
u4_r(code_arena.start + code_arena.used)[0] = val;
code_arena.used += 4;
}
}
internal void pad32(void) {
while ((code_arena.used % 4) != 0) emit8(0x90);
}
internal U4 resolve_name_to_index(const char* ref_name) {
U8 tape_count = tape_arena.used / sizeof(U4);
U4*r tape_ptr = u4_r(tape_arena.start);
U8*r anno_ptr = u8_r(anno_arena.start);
U8 prim_count = array_len(prim_names);
for (int p = 1; p < prim_count; p++) {
int match = 1;
for (int c = 0; c < 8; c++) {
char c1 = ref_name[c] ? ref_name[c] : ' ';
char c2 = prim_names[p][c] ? prim_names[p][c] : ' ';
if (c1 != c2) { match = 0; break; }
}
if (match) return p + 0x10000;
}
for (U8 j = 0; j < tape_count; j++) {
if (unpack_tag(tape_ptr[j]) == STag_Define) {
char* def_name = (char*)&anno_ptr[j];
int match = 1;
for (int c = 0; c < 8; c++) {
char c1 = ref_name[c] ? ref_name[c] : ' ';
char c2 = def_name[c] ? def_name[c] : ' ';
if (c1 != c2) { match = 0; break; }
}
if (match) return j;
}
}
return 0;
}
internal void relink_tape(void) {
U8 tape_count = tape_arena.used / sizeof(U4);
U4*r tape_ptr = u4_r(tape_arena.start);
U8*r anno_ptr = u8_r(anno_arena.start);
for (U8 i = 0; i < tape_count; i++) {
U4 t = tape_ptr[i];
U4 tag = unpack_tag(t);
if (tag == STag_Call || tag == STag_Imm) {
char* ref_name = (char*)&anno_ptr[i];
U4 new_val = resolve_name_to_index(ref_name);
tape_ptr[i] = pack_token(tag, new_val);
}
}
}
internal void compile_action(U4 val)
{
if (val >= 0x10000) {
U4 p = val - 0x10000;
if (p == PRIM_SWAP) {
emit8(0x48); emit8(0x87); emit8(0xC2);
pad32();
return;
} else if (p == PRIM_MULT) {
emit8(0x48); emit8(0x0F); emit8(0xAF); emit8(0xC2);
pad32();
return;
} else if (p == PRIM_ADD) {
emit8(0x48); emit8(0x01); emit8(0xD0);
pad32();
return;
} else if (p == PRIM_SUB) {
emit8(0x48); emit8(0x29); emit8(0xD0);
pad32();
return;
} else if (p == PRIM_FETCH) {
emit8(0x48); emit8(0x8B); emit8(0x04); emit8(0xC3); // mov rax, [rbx + rax*8]
pad32();
return;
} else if (p == PRIM_DEC) {
emit8(0x48); emit8(0xFF); emit8(0xC8);
pad32();
return;
} else if (p == PRIM_STORE) {
emit8(0x48); emit8(0x89); emit8(0x14); emit8(0xC3); // mov [rbx + rax*8], rdx
pad32();
return;
} else if (p == PRIM_RET_Z) {
emit8(0x48); emit8(0x85); emit8(0xC0);
emit8(0x75); emit8(0x01);
emit8(0xC3);
pad32();
return;
} else if (p == PRIM_RET_S) {
emit8(0x48); emit8(0x85); emit8(0xC0);
emit8(0x79); emit8(0x01);
emit8(0xC3);
pad32();
return;
} else if (p == PRIM_RET) {
emit8(0xC3);
pad32();
return;
} else if (p == PRIM_DUP) {
emit8(0x48); emit8(0x89); emit8(0xC2);
pad32();
return;
} else if (p == PRIM_DROP) {
emit8(0x48); emit8(0x89); emit8(0xD0);
pad32();
return;
} else if (p == PRIM_PRINT) {
// FFI Dance: Save RDX, Align RSP (32 shadow + 8 align = 40)
emit8(0x52); // push rdx
emit8(0x48); emit8(0x83); emit8(0xEC); emit8(0x28); // sub rsp, 40
// Map arguments: RCX=RAX, RDX=RDX(already loaded), R8=Globals[0], R9=Globals[1]
emit8(0x48); emit8(0x89); emit8(0xC1); // mov rcx, rax
emit8(0x4C); emit8(0x8B); emit8(0x03); // mov r8, [rbx]
emit8(0x4C); emit8(0x8B); emit8(0x4B); emit8(0x08); // mov r9, [rbx+8]
// Load func ptr and call
emit8(0x49); emit8(0xBA); // mov r10, ...
U8 addr = u8_(& ms_builtin_print);
emit32(u4_(addr & 0xFFFFFFFF));
emit32(u4_(addr >> 32));
emit8(0x41); emit8(0xFF); emit8(0xD2); // call r10
// Restore
emit8(0x48); emit8(0x83); emit8(0xC4); emit8(0x28); // add rsp, 40
emit8(0x5A); // pop rdx
pad32();
return;
}
}
if (val > 0 && val < 0x10000) {
U4 target = tape_to_code_offset[val];
pad32();
S4 rel32 = s4_(target) - s4_(code_arena.used + 5);
emit8(0xE8);
emit32(u4_(rel32));
pad32();
}
}
IA_ void compile_and_run_tape(void)
{
farena_reset(& code_arena);
log_count = 0;
gdi_log_count = 0;
emit8(0x53); // push rbx (callee-saved; also aligns RSP to 0 mod 16)
emit8(0x48); emit8(0x89); emit8(0xCB); // mov rbx, rcx (stable globals ptr for whole JIT session)
emit8(0x48); emit8(0x8B); emit8(0x43); emit8(0x70); // mov rax, [rbx+0x70]
emit8(0x48); emit8(0x8B); emit8(0x53); emit8(0x78); // mov rdx, [rbx+0x78]
U4*r tape_ptr = u4_r(tape_arena.start);
U8*r anno_ptr = u8_r(anno_arena.start);
B4 in_def = false;
U4 def_jmp_offset = 0;
U8 end_idx = run_full ? (tape_arena.used / sizeof(U4)) : (cursor_idx + 1);
for (U8 i = 0; i < end_idx; i++)
{
U4 tag = unpack_tag(tape_ptr[i]);
U4 val = unpack_val(tape_ptr[i]);
if (tag == STag_Define)
{
if (in_def == false) {
pad32();
emit8(0xE9);
def_jmp_offset = code_arena.used;
emit32(0);
pad32();
in_def = true;
} else {
emit8(0xC3);
pad32();
}
tape_to_code_offset[i] = code_arena.used;
emit8(0x48); emit8(0x87); emit8(0xC2);
pad32();
}
else if (tag == STag_Call || tag == STag_Imm)
{
char* name = (char*)&anno_ptr[i];
char val_hex[9];
u64_to_hex(val, val_hex, 8);
val_hex[8] = '\0';
KTL_Slot_Str8 call_log_table[] = {
{ ktl_str8_key("name"), str8(name) },
{ ktl_str8_key("val"), str8(val_hex) },
};
debug_log(str8("Compiling call: <name> (val: <val>)"), ktl_str8_from_arr(call_log_table));
if (tag == STag_Imm && in_def) {
emit8(0xC3);
pad32();
U4 current = code_arena.used;
u4_r(code_arena.start + def_jmp_offset)[0] = current - (def_jmp_offset + 4);
in_def = false;
}
compile_action(val);
}
else if (tag == STag_Data) {
emit8(0x48); emit8(0x89); emit8(0xC2);
emit8(0x48); emit8(0xC7); emit8(0xC0); emit32(val);
pad32();
}
}
if (in_def) {
emit8(0xC3);
pad32();
U4 current = code_arena.used;
u4_r(code_arena.start + def_jmp_offset)[0] = current - (def_jmp_offset + 4);
}
emit8(0x48); emit8(0x89); emit8(0x43); emit8(0x70); // mov [rbx+0x70], rax
emit8(0x48); emit8(0x89); emit8(0x53); emit8(0x78); // mov [rbx+0x78], rdx
emit8(0x5B); // pop rbx
emit8(0xC3); // ret
typedef void JIT_Func(U8* globals_ptr);
JIT_Func* func = (JIT_Func*)code_arena.start;
func(vm_globals);
vm_rax = vm_globals[14];
vm_rdx = vm_globals[15];
char rax_hex[9];
u64_to_hex(vm_rax, rax_hex, 8);
rax_hex[8] = '\0';
char rdx_hex[9];
u64_to_hex(vm_rdx, rdx_hex, 8);
rdx_hex[8] = '\0';
KTL_Slot_Str8 post_jit_log_table[] = {
{ ktl_str8_key("rax"), str8(rax_hex) },
{ ktl_str8_key("rdx"), str8(rdx_hex) },
};
debug_log(str8("JIT finished. RAX: <rax>, RDX: <rdx>"), ktl_str8_from_arr(post_jit_log_table));
}
S8 win_proc(void* hwnd, U4 msg, U8 wparam, S8 lparam)
{
U8 tape_count = tape_arena.used / sizeof(U4);
U4*r tape_ptr = u4_r(tape_arena.start);
switch (msg) {
case MS_WM_CHAR: {
if (editor_mode != MODE_EDIT) return 0;
U4 t = tape_ptr[cursor_idx];
U4 tag = unpack_tag(t);
U4 val = unpack_val(t);
U1 c = u1_(wparam);
B4 should_skip = c < 32 || (c == 'e' && mode_switch_now);
if (should_skip) { mode_switch_now = false; return 0; }
if (tag == STag_Data) {
U4 digit = 16;
if (c >= '0' && c <= '9') digit = c - '0';
if (c >= 'a' && c <= 'f') digit = c - 'a' + 10;
if (c >= 'A' && c <= 'F') digit = c - 'A' + 10;
if (digit < 16) {
val = ((val << 4) | digit) & 0x0FFFFFFF;
tape_ptr[cursor_idx] = pack_token(tag, val);
}
}
else if (tag != STag_Format) {
U8*r anno_ptr = u8_r(anno_arena.start);
char* anno_str = (char*) & anno_ptr[cursor_idx];
int len = 0;
while (len < 8 && anno_str[len] != '\0' && anno_str[len] != ' ') len ++;
if (len < 8) {
anno_str[len] = (char)c;
for (int i = len + 1; i < 8; i++) anno_str[i] = '\0';
if (tag == STag_Call || tag == STag_Imm || tag == STag_Define) {
U4 new_val = resolve_name_to_index(anno_str);
tape_ptr[cursor_idx] = pack_token(tag, new_val);
if (tag == STag_Define) relink_tape();
}
}
}
vm_rax = 0; vm_rdx = 0; mem_zero(u8_(vm_globals), sizeof(vm_globals));
compile_and_run_tape();
ms_invalidate_rect(hwnd, nullptr, true);
return 0;
}
case MS_WM_KEYDOWN: {
if (wparam == 0x45 && editor_mode == MODE_NAV) {
editor_mode = MODE_EDIT;
mode_switch_now = true;
ms_invalidate_rect(hwnd, nullptr, true);
return 0;
}
if (wparam == 0x1B && editor_mode == MODE_EDIT) {
editor_mode = MODE_NAV;
relink_tape();
ms_invalidate_rect(hwnd, nullptr, true);
return 0;
}
if (editor_mode == MODE_EDIT) {
if (wparam == MS_VK_BACK) {
U4 t = tape_ptr[cursor_idx];
U4 tag = unpack_tag(t);
U4 val = unpack_val(t);
if (tag == STag_Data) {
val = val >> 4;
tape_ptr[cursor_idx] = pack_token(tag, val);
}
else if (tag != STag_Format) {
U8*r anno_ptr = u8_r(anno_arena.start);
char* anno_str = (char*) & anno_ptr[cursor_idx];
int len = 0;
while (len < 8 && anno_str[len] != '\0' && anno_str[len] != ' ') len ++;
if (len > 0) {
anno_str[len - 1] = '\0';
if (tag == STag_Call || tag == STag_Imm || tag == STag_Define) {
U4 new_val = resolve_name_to_index(anno_str);
tape_ptr[cursor_idx] = pack_token(tag, new_val);
if (tag == STag_Define) relink_tape();
}
}
}
vm_rax = 0; vm_rdx = 0; mem_zero(u8_(vm_globals), sizeof(vm_globals));
compile_and_run_tape();
ms_invalidate_rect(hwnd, nullptr, true);
}
return 0;
}
if (wparam == MS_VK_RIGHT && cursor_idx < tape_count - 1) cursor_idx ++;
if (wparam == MS_VK_LEFT && cursor_idx > 0) cursor_idx --;
if (wparam == MS_VK_UP) {
U8 line_start = cursor_idx;
while (line_start > 0 && unpack_tag(tape_ptr[line_start - 1]) != STag_Format) line_start--;
if (line_start > 0) {
U8 col = cursor_idx - line_start;
U8 prev_line_start = line_start - 1;
while (prev_line_start > 0 && unpack_tag(tape_ptr[prev_line_start - 1]) != STag_Format) prev_line_start--;
U8 prev_line_len = (line_start - 1) - prev_line_start;
cursor_idx = prev_line_start + (col < prev_line_len ? col : prev_line_len);
}
}
if (wparam == MS_VK_DOWN) {
U8 line_start = cursor_idx;
while (line_start > 0 && unpack_tag(tape_ptr[line_start - 1]) != STag_Format) line_start --;
U8 col = cursor_idx - line_start;
U8 next_line_start = cursor_idx;
while (next_line_start < tape_count && unpack_tag(tape_ptr[next_line_start]) != STag_Format) next_line_start ++;
if (next_line_start < tape_count) {
next_line_start ++;
U8 next_line_end = next_line_start;
while (next_line_end < tape_count && unpack_tag(tape_ptr[next_line_end]) != STag_Format) next_line_end ++;
U8 next_line_len = next_line_end - next_line_start;
cursor_idx = next_line_start + (col < next_line_len ? col : next_line_len);
}
}
if (wparam == MS_VK_PRIOR) { scroll_y_offset -= 100; if (scroll_y_offset < 0) scroll_y_offset = 0; }
if (wparam == MS_VK_NEXT) { scroll_y_offset += 100; }
if (wparam == MS_VK_F5) { run_full = !run_full; }
if (wparam == MS_VK_F1) { save_cartridge(); }
if (wparam == MS_VK_F2) { load_cartridge(); ms_invalidate_rect(hwnd, nullptr, true); }
if (wparam == MS_VK_TAB) {
U4 t = tape_ptr[cursor_idx];
U4 tag = (unpack_tag(t) + 1) % STag_Count;
tape_ptr[cursor_idx] = pack_token(tag, unpack_val(t));
}
else if (wparam == MS_VK_BACK)
{
U8 delete_idx = cursor_idx;
B4 is_shift = (ms_get_async_key_state(MS_VK_SHIFT) & 0x8000) != 0;
if (is_shift == false) {
if (cursor_idx > 0) {
delete_idx = cursor_idx - 1;
cursor_idx--;
}
else return 0;
}
if (tape_count > 0) {
U8*r anno_ptr = u8_r(anno_arena.start);
for (U8 i = delete_idx; i < tape_count - 1; i ++) {
tape_ptr[i] = tape_ptr[i + 1];
anno_ptr[i] = anno_ptr[i + 1];
}
tape_arena.used -= sizeof(U4);
anno_arena.used -= sizeof(U8);
}
relink_tape();
}
else if (wparam == MS_VK_SPACE || wparam == MS_VK_RETURN) {
B4 is_shift = (ms_get_async_key_state(MS_VK_SHIFT) & 0x8000) != 0;
U8 insert_idx = cursor_idx;
if (is_shift) insert_idx ++;
if (tape_arena.used + sizeof(U4) <= tape_arena.capacity && anno_arena.used + sizeof(U8) <= anno_arena.capacity) {
U8*r anno_ptr = u8_r(anno_arena.start);
for (U8 i = tape_count; i > insert_idx; i --) {
tape_ptr[i] = tape_ptr[i-1];
anno_ptr[i] = anno_ptr[i-1];
}
if (wparam == MS_VK_RETURN) {
tape_ptr[insert_idx] = pack_token(STag_Format, 0xA);
anno_ptr[insert_idx] = 0;
} else {
tape_ptr[insert_idx] = pack_token(STag_Comment, 0);
anno_ptr[insert_idx] = 0;
}
if (is_shift) cursor_idx ++;
tape_arena.used += sizeof(U4);
anno_arena.used += sizeof(U8);
}
}
vm_rax = 0; vm_rdx = 0;
mem_zero(u8_(vm_globals), sizeof(vm_globals));
compile_and_run_tape();
ms_invalidate_rect(hwnd, nullptr, true);
return 0;
}
case MS_WM_PAINT: {
MS_PAINTSTRUCT ps;
void* hdc = ms_begin_paint(hwnd, & ps);
void* hFont = ms_create_font_a(20, 0, 0, 0, 400, 0, 0, 0, 0, 0, 0, 0, 0, "Consolas");
void* hOldFont = ms_select_object(hdc, hFont);
ms_set_bk_mode(hdc, 1);
void* hBgBrush = ms_create_solid_brush(0x00222222);
ms_select_object(hdc, hBgBrush);
ms_rectangle(hdc, -1, -1, 3000, 3000);
void* hBrushEdit = ms_create_solid_brush(0x008E563B);
void* hBrushNav = ms_create_solid_brush(0x00262F3B);
S4 start_x = 40, start_y = 60, spacing_x = 110, spacing_y = 35;
S4 x = start_x, y = start_y;
U4*r tape_ptr = u4_r(tape_arena.start);
U8*r anno_ptr = u8_r(anno_arena.start);
for (U8 i = 0; i < tape_count; i++)
{
if (x >= start_x + (TOKENS_PER_ROW * spacing_x)) {
x = start_x; y += spacing_y;
}
S4 render_y = y - scroll_y_offset;
if (i == cursor_idx && render_y >= 30 && render_y < 500) {
ms_select_object(hdc, editor_mode == MODE_EDIT ? hBrushEdit : hBrushNav);
ms_rectangle(hdc, x - 5, render_y - 2, x + 95, render_y + 22);
}
if (render_y >= 30 && render_y < 500)
{
U4 t = tape_ptr[i];
U4 tag = unpack_tag(t);
U4 val = unpack_val(t);
U8 anno = anno_ptr[i];
if (tag == STag_Format && val == 0xA) {
ms_set_text_color(hdc, 0x00444444);
ms_text_out_a(hdc, x, render_y, " \\n ", 6);
x = start_x;
y += spacing_y;
}
else
{
U4 color = tag_colors[tag];
const char* prefix = tag_prefixes[tag];
ms_set_text_color(hdc, color);
if (editor_mode == MODE_EDIT && i == cursor_idx) {
ms_set_text_color(hdc, 0x001E1E1E);
}
char val_str[9];
if (tag == STag_Data) {
u64_to_hex(val, val_str, 6);
val_str[6] = '\0';
}
else
{
char* a_str = (char*) & anno;
for(int c=0; c<8; c++) {
val_str[c] = a_str[c] ? a_str[c] : ' ';
}
val_str[8] = '\0';
}
char out_buf[12];
out_buf[0] = prefix[0];
out_buf[1] = ' ';
mem_copy(u8_(out_buf + 2), u8_(val_str), 8);
out_buf[10] = '\0';
ms_text_out_a(hdc, x, render_y, out_buf, 10);
x += spacing_x;
}
}
else if (unpack_tag(tape_ptr[i]) == STag_Format && unpack_val(tape_ptr[i]) == 0xA) {
x = start_x;
y += spacing_y;
}
else {
x += spacing_x;
}
}
void* hHudBrush = ms_create_solid_brush(0x00141E23);
ms_select_object(hdc, hHudBrush);
ms_rectangle(hdc, -1, 500, 3000, 3000);
ms_rectangle(hdc, -1, -1, 3000, 40);
ms_set_text_color(hdc, 0x00AAAAAA);
ms_text_out_a(hdc, 40, 10, "x86-64 Machine Code Emitter | 2-Reg Stack | [F5] Toggle Run Mode | [PgUp/PgDn] Scroll", 85);
ms_set_text_color(hdc, 0x00FFFFFF);
char jit_str[64] = "Mode: Incremental | JIT Size: 0x000 bytes";
if (run_full) mem_copy(u8_(jit_str + 6), u8_("Full "), 11);
u64_to_hex(code_arena.used, jit_str + 32, 3);
ms_text_out_a(hdc, 40, 520, jit_str, 41);
char state_str[64] = "RAX: 00000000 | RDX: 00000000";
u64_to_hex(vm_rax, state_str + 5, 8);
u64_to_hex(vm_rdx, state_str + 21, 8);
ms_set_text_color(hdc, 0x0094BAA1);
ms_text_out_a(hdc, 40, 550, state_str, 29);
if (tape_count > 0 && cursor_idx < tape_count) {
U4 cur_tag = unpack_tag(tape_ptr[cursor_idx]);
const char* tag_name = tag_names [cur_tag];
U4 cur_color = tag_colors[cur_tag];
char semantics_str[64] = "Current Tag: ";
U4 name_len = 0;
while (tag_name[name_len]) {
semantics_str[13 + name_len] = tag_name[name_len];
name_len ++;
}
semantics_str[13 + name_len] = '\0';
ms_set_text_color(hdc, cur_color);
ms_text_out_a(hdc, 40, 580, semantics_str, 13 + name_len);
}
ms_set_text_color(hdc, 0x00C8C8C8);
ms_text_out_a(hdc, 400, 520, "Global Memory (Contiguous Array):", 33);
for (int i=0; i < 4; i ++) {
char glob_str[32] = "[0]: 00000000";
glob_str[1] = '0' + i;
u64_to_hex(vm_globals[i], glob_str + 5, 8);
ms_set_text_color(hdc, 0x00D6A454);
ms_text_out_a(hdc, 400, 550 + (i * 25), glob_str, 13);
}
ms_set_text_color(hdc, 0x00C8C8C8);
ms_text_out_a(hdc, 750, 520, "Print Log:", 10);
for (int i = 0; i<log_count && i < 4; i ++) {
char log_str[32] = "00000000";
u64_to_hex(log_buffer[i], log_str, 8);
ms_set_text_color(hdc, 0x0094BAA1);
ms_text_out_a(hdc, 750, 550 + (i * 25), log_str, 8);
}
ms_set_text_color(hdc, 0x00C8C8C8);
ms_text_out_a(hdc, 40, 650, "Debug Log:", 10);
for (U4 i = 0; i < gdi_log_count; i++) {
U4 len = 0;
while(gdi_log_buffer[i][len] != '\0' && len < GDI_LOG_MAX_LINE_LEN) {
len++;
}
ms_set_text_color(hdc, 0x00AAAAAA);
ms_text_out_a(hdc, 40, 670 + (i * 20), gdi_log_buffer[i], len);
}
ms_select_object(hdc, hOldFont);
ms_delete_object(hBgBrush);
ms_delete_object(hBrushEdit);
ms_delete_object(hBrushNav);
ms_delete_object(hHudBrush);
ms_end_paint(hwnd, & ps);
return 0;
}
case MS_WM_DESTROY: { ms_post_quit_message(0); return 0; }
}
return ms_def_window_proc_a(hwnd, msg, wparam, lparam);
}
int main(void) {
Slice tape_mem = slice_ut_(u8_(ms_virtual_alloc(nullptr, 64 * 1024, MS_MEM_COMMIT | MS_MEM_RESERVE, MS_PAGE_READWRITE)), 64 * 1024);
Slice anno_mem = slice_ut_(u8_(ms_virtual_alloc(nullptr, 64 * 1024, MS_MEM_COMMIT | MS_MEM_RESERVE, MS_PAGE_READWRITE)), 64 * 1024);
Slice code_mem = slice_ut_(u8_(ms_virtual_alloc(nullptr, 64 * 1024, MS_MEM_COMMIT | MS_MEM_RESERVE, MS_PAGE_EXECUTE_READWRITE)), 64 * 1024);
if (! tape_mem.ptr || ! anno_mem.ptr || ! code_mem.ptr) ms_exit_process(1);
farena_init(& tape_arena, tape_mem);
farena_init(& anno_arena, anno_mem);
farena_init(& code_arena, code_mem);
scatter(pack_token(STag_Comment, 0), "INIT ");
scatter(pack_token(STag_Data, 5), 0);
scatter(pack_token(STag_Data, 0), 0);
scatter(pack_token(STag_Imm, 0), "STORE ");
scatter(pack_token(STag_Data, 1), 0);
scatter(pack_token(STag_Data, 1), 0);
scatter(pack_token(STag_Imm, 0), "STORE ");
scatter(pack_token(STag_Format, 0xA), 0);
scatter(pack_token(STag_Define, 0), "F_STEP ");
scatter(pack_token(STag_Data, 0), 0);
scatter(pack_token(STag_Call, 0), "FETCH ");
scatter(pack_token(STag_Call, 0), "RET_IF_Z");
scatter(pack_token(STag_Format, 0xA), 0);
scatter(pack_token(STag_Data, 1), 0);
scatter(pack_token(STag_Call, 0), "FETCH ");
scatter(pack_token(STag_Data, 0), 0);
scatter(pack_token(STag_Call, 0), "FETCH ");
scatter(pack_token(STag_Call, 0), "MULT ");
scatter(pack_token(STag_Data, 1), 0);
scatter(pack_token(STag_Call, 0), "STORE ");
scatter(pack_token(STag_Format, 0xA), 0);
scatter(pack_token(STag_Data, 0), 0);
scatter(pack_token(STag_Call, 0), "FETCH ");
scatter(pack_token(STag_Call, 0), "DEC ");
scatter(pack_token(STag_Data, 0), 0);
scatter(pack_token(STag_Call, 0), "STORE ");
scatter(pack_token(STag_Data, 1), 0);
scatter(pack_token(STag_Call, 0), "FETCH ");
scatter(pack_token(STag_Call, 0), "PRINT ");
scatter(pack_token(STag_Format, 0xA), 0);
scatter(pack_token(STag_Imm, 0), "F_STEP ");
scatter(pack_token(STag_Imm, 0), "F_STEP ");
scatter(pack_token(STag_Imm, 0), "F_STEP ");
scatter(pack_token(STag_Imm, 0), "F_STEP ");
scatter(pack_token(STag_Imm, 0), "F_STEP ");
relink_tape();
run_full = true;
compile_and_run_tape();
run_full = false;
MS_WNDCLASSA wc;
mem_fill(u8_(& wc), 0, sizeof(wc));
wc.lpfnWndProc = win_proc;
wc.hInstance = ms_get_stock_object(0);
wc.lpszClassName = "ColorForthWindow";
wc.hbrBackground = ms_get_stock_object(4);
ms_register_class_a(& wc);
void* hwnd = ms_create_window_ex_a(0, wc.lpszClassName, "Sourceless Global Memory Explorer", MS_WS_OVERLAPPEDWINDOW | MS_WS_VISIBLE, 100, 100, 1100, 750, nullptr, nullptr, wc.hInstance, nullptr);
MS_MSG msg;
while (ms_get_message_a(& msg, nullptr, 0, 0)) { ms_translate_message(& msg); ms_dispatch_message_a(& msg); }
ms_exit_process(0);
return 0;
}

1208
attempt_1/microui.c Normal file

File diff suppressed because it is too large Load Diff

296
attempt_1/microui.h Normal file
View File

@@ -0,0 +1,296 @@
/*
** Copyright (c) 2024 rxi
**
** This library is free software; you can redistribute it and/or modify it
** under the terms of the MIT license. See `microui.c` for details.
*/
#ifndef MICROUI_H
#define MICROUI_H
#define MU_VERSION "2.02"
#define MU_COMMANDLIST_SIZE (256 * 1024)
#define MU_ROOTLIST_SIZE 32
#define MU_CONTAINERSTACK_SIZE 32
#define MU_CLIPSTACK_SIZE 32
#define MU_IDSTACK_SIZE 32
#define MU_LAYOUTSTACK_SIZE 16
#define MU_CONTAINERPOOL_SIZE 48
#define MU_TREENODEPOOL_SIZE 48
#define MU_MAX_WIDTHS 16
#define MU_REAL float
#define MU_REAL_FMT "%.3g"
#define MU_SLIDER_FMT "%.2f"
#define MU_MAX_FMT 127
#define mu_stack(T, n) struct { int idx; T items[n]; }
#define mu_min(a, b) ((a) < (b) ? (a) : (b))
#define mu_max(a, b) ((a) > (b) ? (a) : (b))
#define mu_clamp(x, a, b) mu_min(b, mu_max(a, x))
enum {
MU_CLIP_PART = 1,
MU_CLIP_ALL
};
enum {
MU_COMMAND_JUMP = 1,
MU_COMMAND_CLIP,
MU_COMMAND_RECT,
MU_COMMAND_TEXT,
MU_COMMAND_ICON,
MU_COMMAND_MAX
};
enum {
MU_COLOR_TEXT,
MU_COLOR_BORDER,
MU_COLOR_WINDOWBG,
MU_COLOR_TITLEBG,
MU_COLOR_TITLETEXT,
MU_COLOR_PANELBG,
MU_COLOR_BUTTON,
MU_COLOR_BUTTONHOVER,
MU_COLOR_BUTTONFOCUS,
MU_COLOR_BASE,
MU_COLOR_BASEHOVER,
MU_COLOR_BASEFOCUS,
MU_COLOR_SCROLLBASE,
MU_COLOR_SCROLLTHUMB,
MU_COLOR_MAX
};
enum {
MU_ICON_CLOSE = 1,
MU_ICON_CHECK,
MU_ICON_COLLAPSED,
MU_ICON_EXPANDED,
MU_ICON_MAX
};
enum {
MU_RES_ACTIVE = (1 << 0),
MU_RES_SUBMIT = (1 << 1),
MU_RES_CHANGE = (1 << 2)
};
enum {
MU_OPT_ALIGNCENTER = (1 << 0),
MU_OPT_ALIGNRIGHT = (1 << 1),
MU_OPT_NOINTERACT = (1 << 2),
MU_OPT_NOFRAME = (1 << 3),
MU_OPT_NORESIZE = (1 << 4),
MU_OPT_NOSCROLL = (1 << 5),
MU_OPT_NOCLOSE = (1 << 6),
MU_OPT_NOTITLE = (1 << 7),
MU_OPT_HOLDFOCUS = (1 << 8),
MU_OPT_AUTOSIZE = (1 << 9),
MU_OPT_POPUP = (1 << 10),
MU_OPT_CLOSED = (1 << 11),
MU_OPT_EXPANDED = (1 << 12)
};
enum {
MU_MOUSE_LEFT = (1 << 0),
MU_MOUSE_RIGHT = (1 << 1),
MU_MOUSE_MIDDLE = (1 << 2)
};
enum {
MU_KEY_SHIFT = (1 << 0),
MU_KEY_CTRL = (1 << 1),
MU_KEY_ALT = (1 << 2),
MU_KEY_BACKSPACE = (1 << 3),
MU_KEY_RETURN = (1 << 4)
};
typedef struct mu_Context mu_Context;
typedef unsigned mu_Id;
typedef MU_REAL mu_Real;
typedef void* mu_Font;
typedef struct { int x, y; } mu_Vec2;
typedef struct { int x, y, w, h; } mu_Rect;
typedef struct { unsigned char r, g, b, a; } mu_Color;
typedef struct { mu_Id id; int last_update; } mu_PoolItem;
typedef struct { int type, size; } mu_BaseCommand;
typedef struct { mu_BaseCommand base; void *dst; } mu_JumpCommand;
typedef struct { mu_BaseCommand base; mu_Rect rect; } mu_ClipCommand;
typedef struct { mu_BaseCommand base; mu_Rect rect; mu_Color color; } mu_RectCommand;
typedef struct { mu_BaseCommand base; mu_Font font; mu_Vec2 pos; mu_Color color; char str[1]; } mu_TextCommand;
typedef struct { mu_BaseCommand base; mu_Rect rect; int id; mu_Color color; } mu_IconCommand;
typedef union {
int type;
mu_BaseCommand base;
mu_JumpCommand jump;
mu_ClipCommand clip;
mu_RectCommand rect;
mu_TextCommand text;
mu_IconCommand icon;
} mu_Command;
typedef struct {
mu_Rect body;
mu_Rect next;
mu_Vec2 position;
mu_Vec2 size;
mu_Vec2 max;
int widths[MU_MAX_WIDTHS];
int items;
int item_index;
int next_row;
int next_type;
int indent;
} mu_Layout;
typedef struct {
mu_Command *head, *tail;
mu_Rect rect;
mu_Rect body;
mu_Vec2 content_size;
mu_Vec2 scroll;
int zindex;
int open;
} mu_Container;
typedef struct {
mu_Font font;
mu_Vec2 size;
int padding;
int spacing;
int indent;
int title_height;
int scrollbar_size;
int thumb_size;
mu_Color colors[MU_COLOR_MAX];
} mu_Style;
struct mu_Context {
/* callbacks */
int (*text_width)(mu_Font font, const char *str, int len);
int (*text_height)(mu_Font font);
void (*draw_frame)(mu_Context *ctx, mu_Rect rect, int colorid);
/* core state */
mu_Style _style;
mu_Style *style;
mu_Id hover;
mu_Id focus;
mu_Id last_id;
mu_Rect last_rect;
int last_zindex;
int updated_focus;
int frame;
mu_Container *hover_root;
mu_Container *next_hover_root;
mu_Container *scroll_target;
char number_edit_buf[MU_MAX_FMT];
mu_Id number_edit;
/* stacks */
mu_stack(char, MU_COMMANDLIST_SIZE) command_list;
mu_stack(mu_Container*, MU_ROOTLIST_SIZE) root_list;
mu_stack(mu_Container*, MU_CONTAINERSTACK_SIZE) container_stack;
mu_stack(mu_Rect, MU_CLIPSTACK_SIZE) clip_stack;
mu_stack(mu_Id, MU_IDSTACK_SIZE) id_stack;
mu_stack(mu_Layout, MU_LAYOUTSTACK_SIZE) layout_stack;
/* retained state pools */
mu_PoolItem container_pool[MU_CONTAINERPOOL_SIZE];
mu_Container containers[MU_CONTAINERPOOL_SIZE];
mu_PoolItem treenode_pool[MU_TREENODEPOOL_SIZE];
/* input state */
mu_Vec2 mouse_pos;
mu_Vec2 last_mouse_pos;
mu_Vec2 mouse_delta;
mu_Vec2 scroll_delta;
int mouse_down;
int mouse_pressed;
int key_down;
int key_pressed;
char input_text[32];
};
mu_Vec2 mu_vec2(int x, int y);
mu_Rect mu_rect(int x, int y, int w, int h);
mu_Color mu_color(int r, int g, int b, int a);
void mu_init(mu_Context *ctx);
void mu_begin(mu_Context *ctx);
void mu_end(mu_Context *ctx);
void mu_set_focus(mu_Context *ctx, mu_Id id);
mu_Id mu_get_id(mu_Context *ctx, const void *data, int size);
void mu_push_id(mu_Context *ctx, const void *data, int size);
void mu_pop_id(mu_Context *ctx);
void mu_push_clip_rect(mu_Context *ctx, mu_Rect rect);
void mu_pop_clip_rect(mu_Context *ctx);
mu_Rect mu_get_clip_rect(mu_Context *ctx);
int mu_check_clip(mu_Context *ctx, mu_Rect r);
mu_Container* mu_get_current_container(mu_Context *ctx);
mu_Container* mu_get_container(mu_Context *ctx, const char *name);
void mu_bring_to_front(mu_Context *ctx, mu_Container *cnt);
int mu_pool_init(mu_Context *ctx, mu_PoolItem *items, int len, mu_Id id);
int mu_pool_get(mu_Context *ctx, mu_PoolItem *items, int len, mu_Id id);
void mu_pool_update(mu_Context *ctx, mu_PoolItem *items, int idx);
void mu_input_mousemove(mu_Context *ctx, int x, int y);
void mu_input_mousedown(mu_Context *ctx, int x, int y, int btn);
void mu_input_mouseup(mu_Context *ctx, int x, int y, int btn);
void mu_input_scroll(mu_Context *ctx, int x, int y);
void mu_input_keydown(mu_Context *ctx, int key);
void mu_input_keyup(mu_Context *ctx, int key);
void mu_input_text(mu_Context *ctx, const char *text);
mu_Command* mu_push_command(mu_Context *ctx, int type, int size);
int mu_next_command(mu_Context *ctx, mu_Command **cmd);
void mu_set_clip(mu_Context *ctx, mu_Rect rect);
void mu_draw_rect(mu_Context *ctx, mu_Rect rect, mu_Color color);
void mu_draw_box(mu_Context *ctx, mu_Rect rect, mu_Color color);
void mu_draw_text(mu_Context *ctx, mu_Font font, const char *str, int len, mu_Vec2 pos, mu_Color color);
void mu_draw_icon(mu_Context *ctx, int id, mu_Rect rect, mu_Color color);
void mu_layout_row(mu_Context *ctx, int items, const int *widths, int height);
void mu_layout_width(mu_Context *ctx, int width);
void mu_layout_height(mu_Context *ctx, int height);
void mu_layout_begin_column(mu_Context *ctx);
void mu_layout_end_column(mu_Context *ctx);
void mu_layout_set_next(mu_Context *ctx, mu_Rect r, int relative);
mu_Rect mu_layout_next(mu_Context *ctx);
void mu_draw_control_frame(mu_Context *ctx, mu_Id id, mu_Rect rect, int colorid, int opt);
void mu_draw_control_text(mu_Context *ctx, const char *str, mu_Rect rect, int colorid, int opt);
int mu_mouse_over(mu_Context *ctx, mu_Rect rect);
void mu_update_control(mu_Context *ctx, mu_Id id, mu_Rect rect, int opt);
#define mu_button(ctx, label) mu_button_ex(ctx, label, 0, MU_OPT_ALIGNCENTER)
#define mu_textbox(ctx, buf, bufsz) mu_textbox_ex(ctx, buf, bufsz, 0)
#define mu_slider(ctx, value, lo, hi) mu_slider_ex(ctx, value, lo, hi, 0, MU_SLIDER_FMT, MU_OPT_ALIGNCENTER)
#define mu_number(ctx, value, step) mu_number_ex(ctx, value, step, MU_SLIDER_FMT, MU_OPT_ALIGNCENTER)
#define mu_header(ctx, label) mu_header_ex(ctx, label, 0)
#define mu_begin_treenode(ctx, label) mu_begin_treenode_ex(ctx, label, 0)
#define mu_begin_window(ctx, title, rect) mu_begin_window_ex(ctx, title, rect, 0)
#define mu_begin_panel(ctx, name) mu_begin_panel_ex(ctx, name, 0)
void mu_text(mu_Context *ctx, const char *text);
void mu_label(mu_Context *ctx, const char *text);
int mu_button_ex(mu_Context *ctx, const char *label, int icon, int opt);
int mu_checkbox(mu_Context *ctx, const char *label, int *state);
int mu_textbox_raw(mu_Context *ctx, char *buf, int bufsz, mu_Id id, mu_Rect r, int opt);
int mu_textbox_ex(mu_Context *ctx, char *buf, int bufsz, int opt);
int mu_slider_ex(mu_Context *ctx, mu_Real *value, mu_Real low, mu_Real high, mu_Real step, const char *fmt, int opt);
int mu_number_ex(mu_Context *ctx, mu_Real *value, mu_Real step, const char *fmt, int opt);
int mu_header_ex(mu_Context *ctx, const char *label, int opt);
int mu_begin_treenode_ex(mu_Context *ctx, const char *label, int opt);
void mu_end_treenode(mu_Context *ctx);
int mu_begin_window_ex(mu_Context *ctx, const char *title, mu_Rect rect, int opt);
void mu_end_window(mu_Context *ctx);
void mu_open_popup(mu_Context *ctx, const char *name);
int mu_begin_popup(mu_Context *ctx, const char *name);
void mu_end_popup(mu_Context *ctx);
void mu_begin_panel_ex(mu_Context *ctx, const char *name, int opt);
void mu_end_panel(mu_Context *ctx);
#endif

BIN
win_proc.c Normal file

Binary file not shown.