Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 9dc4372bf3 | |||
| 784f3b9945 | |||
| 9db1748249 | |||
| bc30206e65 |
@@ -0,0 +1,50 @@
|
||||
root = true
|
||||
|
||||
[*.s]
|
||||
indent_style = tab
|
||||
indent_size = 2
|
||||
|
||||
[*.asm]
|
||||
indent_style = tab
|
||||
indent_size = 2
|
||||
|
||||
[*.refactor]
|
||||
indent_style = space
|
||||
indent_size = 4
|
||||
|
||||
[*.md]
|
||||
indent_style = space
|
||||
indent_size = 4
|
||||
|
||||
[*.c]
|
||||
indent_style = tab
|
||||
indent_size = 2
|
||||
charset = utf-8
|
||||
|
||||
[*.cpp]
|
||||
indent_style = tab
|
||||
indent_size = 2
|
||||
charset = utf-8
|
||||
|
||||
[*.h]
|
||||
indent_style = tab
|
||||
indent_size = 2
|
||||
charset = utf-8
|
||||
|
||||
[*.hpp]
|
||||
indent_style = tab
|
||||
indent_size = 2
|
||||
charset = utf-8
|
||||
|
||||
[*.{ps1, psm1}]
|
||||
indent_style = tab
|
||||
indent_size = 4
|
||||
|
||||
[*.odin]
|
||||
indent_style = tab
|
||||
indent_size = 2
|
||||
charset = utf-8
|
||||
|
||||
[*.{natvis, natstepfilter}]
|
||||
indent_style = tab
|
||||
indent_size = 4
|
||||
@@ -3,3 +3,4 @@
|
||||
references/processed_visuals
|
||||
build
|
||||
bootslop.proj
|
||||
clay_ui_temp
|
||||
|
||||
+15
-11
@@ -27,17 +27,21 @@ This document outlines the strict C style and architectural conventions expected
|
||||
* **Case:** Strictly use `lower_snake_case` for all functions and variables.
|
||||
* **Types:** Use `PascalCase` for type names (`FArena`, `SWord_Tag`).
|
||||
* **WinAPI Symbols:** When declaring foreign Win32 symbols, prefix the C function name with `ms_` (using `lower_snake_case`) and use the `asm("SymbolName")` attribute to link it to the actual DLL export.
|
||||
* *Correct:* `WinAPI U2 ms_register_class(const MS_WNDCLASSA* lpWndClass) asm("RegisterClassA");`
|
||||
* *Correct:* `WinAPI U2 ms_register_class_a(MS_WNDCLASSA const* lpWndClass) asm("RegisterClassA");`
|
||||
* *Incorrect:* `WinAPI U2 RegisterClassA(...);`
|
||||
|
||||
## 4. Memory Management
|
||||
* **No Standard Library:** The environment is built with `-nostdlib` and `-ffreestanding`. Never include `<stdlib.h>`, `<string.h>`, etc.
|
||||
* **Arenas over Malloc:** Use `FArena` and its associated macros (`farena_push`, `farena_push_type`, `farena_reset`) for all dynamic memory allocations. Do not use raw pointers with manual arithmetic when an arena can handle it.
|
||||
* **Memory Ops:** Use `mem_fill` and `mem_copy` instead of standard `memset`/`memcpy` within the application logic. (A minimal `memset`/`memcpy` shim is only provided to satisfy compiler intrinsic struct zeroing under `-nostdlib`).
|
||||
## 4. Formatting & Layout
|
||||
* **Vertical Alignment:** Align related variable declarations, struct fields, and function prototypes into columns to create a "sheet-like" layout. This improves visual parsing.
|
||||
* **Brace Style:** Use Allman style (braces on a new line) for function bodies control block (`if`, `for`, `switch`, etc.) that spans more than 50 lines or contains nested logic.
|
||||
* **Conditionals:** Always place `else if` and `else` statements on a new line, un-nested from the previous closing brace.
|
||||
|
||||
## 5. Modifiers
|
||||
* `internal`: Static functions.
|
||||
* `global`: Global state variables.
|
||||
* `IA_`: Internal Always Inline.
|
||||
* `I_`: Internal Inline.
|
||||
* Pointers use `*r` (restrict) or `*v` (volatile) macros where applicable.
|
||||
## 5. Memory Management
|
||||
* **Standard Library:** The C standard library is linked, but headers like `<stdlib.h>` or `<string.h>` should not be included directly. Required functions should be declared manually if needed, or accessed via compiler builtins.
|
||||
* **Arenas over Malloc:** Use `FArena` and its associated macros (`farena_push`, `farena_push_type`, `farena_reset`) for all dynamic memory allocations. Do not use raw pointers with manual arithmetic when an arena can handle it.
|
||||
* **Memory Ops:** Use `mem_fill` and `mem_copy` instead of standard `memset`/`memcpy` within the application logic.
|
||||
|
||||
## 6. Type Qualifiers
|
||||
* **`const` Placement:** The `const` keyword must always be placed to the right of the type it modifies. This maintains a consistent right-to-left reading of type declarations.
|
||||
* **Correct:** `char const* my_ptr;` (Pointer to a constant character)
|
||||
* **Correct:** `U4 const* const my_ptr;` (Constant pointer to a constant U4)
|
||||
* **Incorrect:** `const char* my_ptr;`
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# Technical Outline: Attempt 1
|
||||
|
||||
## Overview
|
||||
`attempt_1` is a minimal, `-nostdlib` C program that serves as a proof-of-concept for the "Lottes/Onat" sourceless ColorForth paradigm. It successfully integrates a visual editor, a live JIT compiler, and an execution environment into a single, cohesive Win32 application that runs without any external dependencies or the C runtime.
|
||||
`attempt_1` is a minimal C program that serves as a proof-of-concept for the "Lottes/Onat" sourceless ColorForth paradigm. It successfully integrates a visual editor, a live JIT compiler, and an execution environment into a single, cohesive Win32 application that links against the C runtime but avoids direct includes of standard headers, using manually declared functions instead.
|
||||
|
||||
The application presents a visual grid of 32-bit tokens and allows the user to navigate and edit them directly. On every keypress, the token array is re-compiled into x86-64 machine code and executed, with the results (register states and global memory) displayed instantly in the HUD.
|
||||
|
||||
|
||||
@@ -159,10 +159,11 @@ IA_ U8 atm_swap_u8(U8*r addr, U8 value){asm volatile("lock xchgq %0,%1":"=r"(val
|
||||
#pragma endregion Thread Coherence
|
||||
|
||||
#pragma region Debug
|
||||
WinAPI void process_exit(U4 status) asm("ExitProcess");
|
||||
WinAPI void ms_exit_process(U4 uExitCode) asm("ExitProcess"); // Kernel 32
|
||||
|
||||
#define debug_trap() __builtin_debugtrap()
|
||||
#if BUILD_DEBUG
|
||||
IA_ void assert(U8 cond) { if(cond){return;} else{debug_trap(); process_exit(1);} }
|
||||
IA_ void assert(U8 cond) { if(cond){return;} else{debug_trap(); ms_exit_process(1);} }
|
||||
#else
|
||||
#define assert(cond)
|
||||
#endif
|
||||
@@ -182,6 +183,24 @@ IA_ U8 align_pow2(U8 x, U8 b) {
|
||||
return ((x + b - 1) & (~(b - 1)));
|
||||
}
|
||||
|
||||
#if 0
|
||||
#pragma clang optimize off
|
||||
// TODO(Ed): Replace these later (only matters if CRT is not used)
|
||||
void* memset(void* dest, int c, U8 count) {
|
||||
U1* bytes = (U1*)dest;
|
||||
while (count--) *bytes++ = (U1)c;
|
||||
return dest;
|
||||
}
|
||||
|
||||
void* memcpy(void* dest, const void* src, U8 count) {
|
||||
U1* d = (U1*)dest;
|
||||
const U1* s = (const U1*)src;
|
||||
while (count--) *d++ = *s++;
|
||||
return dest;
|
||||
}
|
||||
#pragma clang optimize on
|
||||
#endif
|
||||
|
||||
IA_ U8 mem_copy (U8 dest, U8 src, U8 len) { return (U8)(__builtin_memcpy ((void*)dest, (void const*)src, len)); }
|
||||
IA_ U8 mem_copy_overlapping(U8 dest, U8 src, U8 len) { return (U8)(__builtin_memmove((void*)dest, (void const*)src, len)); }
|
||||
IA_ U8 mem_fill (U8 dest, U8 value, U8 len) { return (U8)(__builtin_memset ((void*)dest, (int) value, len)); }
|
||||
@@ -224,6 +243,13 @@ IA_ Slice mem_bump(U8 start, U8 cap, U8*r used, U8 amount) {
|
||||
}
|
||||
#pragma endregion Memory
|
||||
|
||||
#pragma region Encoding
|
||||
IA_ void u64_to_hex(U8 val, char* buf, S4 chars) {
|
||||
static const char hex_chars[] = "0123456789ABCDEF";
|
||||
for(S1 i = chars - 1; i >= 0; --i) { buf[i] = hex_chars[val & 0xF]; val >>= 4; }
|
||||
}
|
||||
#pragma endregion Encoding
|
||||
|
||||
#pragma region Math
|
||||
#define u8_max 0xffffffffffffffffull
|
||||
|
||||
@@ -332,9 +358,6 @@ IA_ U8 hash64_fnv1a_ret(Slice data, U8 seed) { U8 h = 0; hash64_fnv1a(& h, data,
|
||||
#define MS_STD_INPUT u4_(-10)
|
||||
#define MS_STD_OUTPUT u4_(-11)
|
||||
typedef Struct_(MS_Handle){U8 id;};
|
||||
WinAPI MS_Handle ms_get_std_handle(U4 handle_type) asm("GetStdHandle");
|
||||
WinAPI B4 ms_read_console(MS_Handle handle, UTF8*r buffer, U4 to_read, U4*r num_read, U8 reserved_input_control) asm("ReadConsoleA");
|
||||
WinAPI B4 ms_write_console(MS_Handle handle, UTF8 const*r buffer, U4 chars_to_write, U4*v chars_written, U8 reserved) asm("WriteConsoleA");
|
||||
#pragma endregion IO
|
||||
|
||||
#pragma region Key Table Linear (KTL)
|
||||
@@ -581,37 +604,83 @@ typedef struct MS_WNDCLASSA {
|
||||
char const* lpszMenuName;
|
||||
char const* lpszClassName;
|
||||
} MS_WNDCLASSA;
|
||||
|
||||
typedef struct MS_POINT { S4 x, y; } MS_POINT;
|
||||
typedef struct MS_MSG { void* hwnd; U4 message; U8 wParam; S8 lParam; U4 time; MS_POINT pt; } MS_MSG;
|
||||
typedef struct MS_RECT { S4 left, top, right, bottom; } MS_RECT;
|
||||
typedef struct MS_PAINTSTRUCT { void* hdc; S4 fErase; MS_RECT rcPaint; S4 fRestore; S4 fIncUpdate; U1 rgbReserved[32]; } MS_PAINTSTRUCT;
|
||||
|
||||
// Win32 API declarations
|
||||
WinAPI void* ms_virtual_alloc(void* lpAddress, U8 dwSize, U4 flAllocationType, U4 flProtect) asm("VirtualAlloc");
|
||||
// --- Kernel32 ---
|
||||
WinAPI void ms_exit_process(U4 uExitCode) asm("ExitProcess");
|
||||
WinAPI U2 ms_register_class_a(const MS_WNDCLASSA* lpWndClass) asm("RegisterClassA");
|
||||
WinAPI void* ms_create_window_ex_a(U4 dwExStyle, char const* lpClassName, char const* lpWindowName, U4 dwStyle, S4 X, S4 Y, S4 nWidth, S4 nHeight, void* hWndParent, void* hMenu, void* hInstance, void* lpParam) asm("CreateWindowExA");
|
||||
WinAPI MS_Handle ms_get_std_handle(U4 handle_type) asm("GetStdHandle");
|
||||
WinAPI void* ms_virtual_alloc(void* lpAddress, U8 dwSize, U4 flAllocationType, U4 flProtect) asm("VirtualAlloc");
|
||||
WinAPI B4 ms_read_console(
|
||||
MS_Handle handle,
|
||||
UTF8*r buffer,
|
||||
U4 to_read,
|
||||
U4*r num_read,
|
||||
U8 reserved_input_control
|
||||
) asm("ReadConsoleA");
|
||||
WinAPI B4 ms_write_console(
|
||||
MS_Handle handle,
|
||||
UTF8 const*r buffer,
|
||||
U4 chars_to_write,
|
||||
U4*v chars_written,
|
||||
U8 reserved
|
||||
) asm("WriteConsoleA");
|
||||
|
||||
// --- User32 ---
|
||||
WinAPI U2 ms_register_class_a(MS_WNDCLASSA const* lpWndClass) asm("RegisterClassA");
|
||||
WinAPI void* ms_create_window_ex_a(
|
||||
U4 dwExStyle,
|
||||
char const* lpClassName,
|
||||
char const* lpWindowName,
|
||||
U4 dwStyle,
|
||||
S4 X,
|
||||
S4 Y,
|
||||
S4 nWidth,
|
||||
S4 nHeight,
|
||||
void* hWndParent,
|
||||
void* hMenu,
|
||||
void* hInstance,
|
||||
void* lpParam
|
||||
) asm("CreateWindowExA");
|
||||
WinAPI S4 ms_show_window(void* hWnd, S4 nCmdShow) asm("ShowWindow");
|
||||
WinAPI S4 ms_get_message_a(MS_MSG* lpMsg, void* hWnd, U4 wMsgFilterMin, U4 wMsgFilterMax) asm("GetMessageA");
|
||||
WinAPI S4 ms_translate_message(const MS_MSG* lpMsg) asm("TranslateMessage");
|
||||
WinAPI S8 ms_dispatch_message_a(const MS_MSG* lpMsg) asm("DispatchMessageA");
|
||||
WinAPI S4 ms_translate_message(MS_MSG const* lpMsg) asm("TranslateMessage");
|
||||
WinAPI S8 ms_dispatch_message_a(MS_MSG const* lpMsg) asm("DispatchMessageA");
|
||||
WinAPI S8 ms_def_window_proc_a(void* hWnd, U4 Msg, U8 wParam, S8 lParam) asm("DefWindowProcA");
|
||||
WinAPI void ms_post_quit_message(S4 nExitCode) asm("PostQuitMessage");
|
||||
WinAPI S4 ms_invalidate_rect(void* hWnd, const MS_RECT* lpRect, S4 bErase) asm("InvalidateRect");
|
||||
WinAPI S4 ms_invalidate_rect(void* hWnd, MS_RECT const* lpRect, S4 bErase) asm("InvalidateRect");
|
||||
WinAPI S2 ms_get_async_key_state(S4 vKey) asm("GetAsyncKeyState");
|
||||
|
||||
// --- GDI32 ---
|
||||
WinAPI void* ms_begin_paint(void* hWnd, MS_PAINTSTRUCT* lpPaint) asm("BeginPaint");
|
||||
WinAPI S4 ms_end_paint(void* hWnd, const MS_PAINTSTRUCT* lpPaint) asm("EndPaint");
|
||||
WinAPI S4 ms_end_paint(void* hWnd, MS_PAINTSTRUCT const* lpPaint) asm("EndPaint");
|
||||
WinAPI U4 ms_set_text_color(void* hdc, U4 color) asm("SetTextColor");
|
||||
WinAPI U4 ms_set_bk_color(void* hdc, U4 color) asm("SetBkColor");
|
||||
WinAPI S4 ms_text_out_a(void* hdc, S4 x, S4 y, char const* lpString, S4 c) asm("TextOutA");
|
||||
WinAPI void* ms_get_stock_object(S4 i) asm("GetStockObject");
|
||||
WinAPI void* ms_create_font_a(S4 cHeight, S4 cWidth, S4 cEscapement, S4 cOrientation, S4 cWeight, U4 bItalic, U4 bUnderline, U4 bStrikeOut, U4 iCharSet, U4 iOutPrecision, U4 iClipPrecision, U4 iQuality, U4 iPitchAndFamily, char const* pszFaceName) asm("CreateFontA");
|
||||
WinAPI void* ms_create_font_a(
|
||||
S4 cHeight,
|
||||
S4 cWidth,
|
||||
S4 cEscapement,
|
||||
S4 cOrientation,
|
||||
S4 cWeight,
|
||||
U4 bItalic,
|
||||
U4 bUnderline,
|
||||
U4 bStrikeOut,
|
||||
U4 iCharSet,
|
||||
U4 iOutPrecision,
|
||||
U4 iClipPrecision,
|
||||
U4 iQuality,
|
||||
U4 iPitchAndFamily,
|
||||
char const* pszFaceName
|
||||
) asm("CreateFontA");
|
||||
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_set_bk_mode(void* hdc, S4 mode) asm("SetBkMode");
|
||||
WinAPI void* ms_create_solid_brush(U4 color) asm("CreateSolidBrush");
|
||||
WinAPI S4 ms_delete_object(void* ho) asm("DeleteObject");
|
||||
WinAPI S2 ms_get_async_key_state(S4 vKey) asm("GetAsyncKeyState");
|
||||
|
||||
#define MS_MEM_COMMIT 0x00001000
|
||||
#define MS_MEM_RESERVE 0x00002000
|
||||
|
||||
+190
-217
@@ -1,14 +1,9 @@
|
||||
// Fundamental Boolean and Null types for no-std environment
|
||||
#define true 1
|
||||
#define false 0
|
||||
#define NULL ((void*)0)
|
||||
|
||||
#include "duffle.amd64.win32.h"
|
||||
|
||||
// --- Semantic Tags (Using X-Macros & Enum_) ---
|
||||
// Colors translated from Cozy-and-WIndy:
|
||||
// 0x00bbggrr Win32 format
|
||||
typedef Enum_(U4, STag) {
|
||||
|
||||
#define Tag_Entries() \
|
||||
X(Define, "Define", 0x0018AEFF, ":") /* Orange-ish (Language.Type) */ \
|
||||
X(Call, "Call", 0x00D6A454, "~") /* Soft Blue (Language.Class) */ \
|
||||
@@ -17,27 +12,22 @@ typedef Enum_(U4, STag) {
|
||||
X(Comment, "Comment", 0x00AAAAAA, ".") /* Grey (Language.Comment) */ \
|
||||
X(Format, "Format", 0x003A2F3B, " ") /* Current Line BG for invisibles */
|
||||
|
||||
typedef Enum_(U4, STag) {
|
||||
#define X(n, s, c, p) tmpl(STag, n),
|
||||
Tag_Entries()
|
||||
#undef X
|
||||
STag_Count,
|
||||
};
|
||||
|
||||
// Helper array to fetch Hex colors for UI rendering based on STag
|
||||
global U4 tag_colors[] = {
|
||||
#define X(n, s, c, p) c,
|
||||
Tag_Entries()
|
||||
#undef X
|
||||
};
|
||||
|
||||
// Helper array to fetch the text prefix based on STag
|
||||
global const char* tag_prefixes[] = {
|
||||
#define X(n, s, c, p) p,
|
||||
Tag_Entries()
|
||||
#undef X
|
||||
};
|
||||
|
||||
// Helper array to fetch the full name of the STag
|
||||
global const char* tag_names[] = {
|
||||
#define X(n, s, c, p) s,
|
||||
Tag_Entries()
|
||||
@@ -45,12 +35,12 @@ global const char* tag_names[] = {
|
||||
};
|
||||
|
||||
// Token Packing: 28 bits payload | 4 bits tag
|
||||
#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 pack_token(tag, val) ((u4_(tag) << 28) | (u4_(val) & 0x0FFFFFFF))
|
||||
#define unpack_tag(token) ( ((token) >> 28) & 0x0F)
|
||||
#define unpack_val(token) ( (token) & 0x0FFFFFFF)
|
||||
|
||||
// 2-Character Mapped Dictionary Helper
|
||||
#define ID2(a, b) (((U4)(a) << 8) | (U4)(b))
|
||||
#define id2(a, b) ((u4_(a) << 8) | u4_(b))
|
||||
|
||||
#define TOKENS_PER_ROW 8
|
||||
|
||||
@@ -93,121 +83,99 @@ typedef struct {
|
||||
global DictEntry dict[256];
|
||||
global U8 dict_count = 0;
|
||||
|
||||
#pragma clang optimize off
|
||||
void* memset(void* dest, int c, U8 count) {
|
||||
U1* bytes = (U1*)dest;
|
||||
while (count--) *bytes++ = (U1)c;
|
||||
return dest;
|
||||
}
|
||||
|
||||
void* memcpy(void* dest, const void* src, U8 count) {
|
||||
U1* d = (U1*)dest;
|
||||
const U1* s = (const U1*)src;
|
||||
while (count--) *d++ = *s++;
|
||||
return dest;
|
||||
}
|
||||
#pragma clang optimize on
|
||||
|
||||
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*r ptr = C_(U4*r, tape_arena.start + tape_arena.used);
|
||||
U4*r ptr = u4_r(tape_arena.start + tape_arena.used);
|
||||
ptr[0] = token;
|
||||
tape_arena.used += sizeof(U4);
|
||||
|
||||
U8*r aptr = C_(U8*r, anno_arena.start + anno_arena.used);
|
||||
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]) {
|
||||
int i = 0; while(i < 8 && anno_str[i]) {
|
||||
dest[i] = anno_str[i];
|
||||
i++;
|
||||
i ++;
|
||||
}
|
||||
}
|
||||
anno_arena.used += sizeof(U8);
|
||||
}
|
||||
}
|
||||
|
||||
IA_ void u64_to_hex(U8 val, char* buf, S4 chars) {
|
||||
static const char hex_chars[] = "0123456789ABCDEF";
|
||||
for(S1 i = chars - 1; i >= 0; --i) { buf[i] = hex_chars[val & 0xF]; val >>= 4; }
|
||||
}
|
||||
|
||||
// --- Minimal x86-64 Emitter ---
|
||||
internal void emit8(U1 b) {
|
||||
if (code_arena.used + 1 <= code_arena.capacity) {
|
||||
U1* ptr = (U1*)(code_arena.start + code_arena.used);
|
||||
*ptr = b;
|
||||
U1*r ptr = u1_r(code_arena.start + code_arena.used);
|
||||
ptr[0] = b;
|
||||
code_arena.used += 1;
|
||||
}
|
||||
}
|
||||
|
||||
internal void emit32(U4 val) {
|
||||
if (code_arena.used + 4 <= code_arena.capacity) {
|
||||
U4* ptr = (U4*)(code_arena.start + code_arena.used);
|
||||
*ptr = val;
|
||||
U4*r ptr = u4_r(code_arena.start + code_arena.used);
|
||||
ptr[0] = val;
|
||||
code_arena.used += 4;
|
||||
}
|
||||
}
|
||||
|
||||
internal void compile_action(U4 val) {
|
||||
if (val == ID2('S','W')) { // SWAP: xchg rax, rdx
|
||||
internal void compile_action(U4 val)
|
||||
{
|
||||
if (val == id2('S','W')) { // SWAP: xchg rax, rdx
|
||||
emit8(0x48); emit8(0x87); emit8(0xC2);
|
||||
return;
|
||||
} else if (val == ID2('M','*')) { // MULT: imul rax, rdx
|
||||
} else if (val == id2('M','*')) { // MULT: imul rax, rdx
|
||||
emit8(0x48); emit8(0x0F); emit8(0xAF); emit8(0xC2);
|
||||
return;
|
||||
} else if (val == ID2('+',' ')) { // ADD: add rax, rdx
|
||||
} else if (val == id2('+',' ')) { // ADD: add rax, rdx
|
||||
emit8(0x48); emit8(0x01); emit8(0xD0);
|
||||
return;
|
||||
} else if (val == ID2('@',' ')) { // FETCH: mov rax, QWORD PTR [rcx + rax*8]
|
||||
} else if (val == id2('@',' ')) { // FETCH: mov rax, QWORD PTR [rcx + rax*8]
|
||||
emit8(0x48); emit8(0x8B); emit8(0x04); emit8(0xC1);
|
||||
return;
|
||||
} else if (val == ID2('-','1')) { // DEC: dec rax
|
||||
} else if (val == id2('-','1')) { // DEC: dec rax
|
||||
emit8(0x48); emit8(0xFF); emit8(0xC8);
|
||||
return;
|
||||
} else if (val == ID2('!',' ')) { // STORE: mov QWORD PTR [rcx + rax*8], rdx
|
||||
} else if (val == id2('!',' ')) { // STORE: mov QWORD PTR [rcx + rax*8], rdx
|
||||
emit8(0x48); emit8(0x89); emit8(0x14); emit8(0xC1);
|
||||
return;
|
||||
} else if (val == ID2('R','0')) { // RET_IF_ZERO: test rax, rax; jnz +1; ret
|
||||
} else if (val == id2('R','0')) { // RET_IF_ZERO: test rax, rax; jnz +1; ret
|
||||
emit8(0x48); emit8(0x85); emit8(0xC0); // test rax, rax
|
||||
emit8(0x75); emit8(0x01); // jnz skip_ret (+1 byte)
|
||||
emit8(0xC3); // ret
|
||||
return;
|
||||
} else if (val == ID2('R','E')) { // RET
|
||||
} else if (val == id2('R','E')) { // RET
|
||||
emit8(0xC3);
|
||||
return;
|
||||
} else if (val == ID2('P','R')) { // PRINT: call ms_builtin_print
|
||||
} else if (val == id2('P','R')) { // PRINT: call ms_builtin_print
|
||||
emit8(0x51); // push rcx
|
||||
emit8(0x52); // push rdx
|
||||
emit8(0x48); emit8(0x83); emit8(0xEC); emit8(0x20); // sub rsp, 32
|
||||
emit8(0x48); emit8(0x89); emit8(0xC1); // mov rcx, rax
|
||||
emit8(0x49); emit8(0xB8); // mov r8, imm64
|
||||
U8 addr = (U8)&ms_builtin_print;
|
||||
emit32((U4)(addr & 0xFFFFFFFF));
|
||||
emit32((U4)(addr >> 32));
|
||||
U8 addr = u8_(& ms_builtin_print);
|
||||
emit32(u4_(addr & 0xFFFFFFFF));
|
||||
emit32(u4_(addr >> 32));
|
||||
emit8(0x41); emit8(0xFF); emit8(0xD0); // call r8
|
||||
emit8(0x48); emit8(0x83); emit8(0xC4); emit8(0x20); // add rsp, 32
|
||||
emit8(0x5A); // pop rdx
|
||||
emit8(0x59); // pop rcx
|
||||
return;
|
||||
}
|
||||
|
||||
// Dictionary Resolver (Call User Word)
|
||||
for (U8 i = 0; i < dict_count; i++) {
|
||||
if (dict[i].val == val) {
|
||||
U4 target = dict[i].offset;
|
||||
for (U8 entry = 0; entry < dict_count; entry++) {
|
||||
if (dict[entry].val == val) {
|
||||
U4 target = dict[entry].offset;
|
||||
U4 current = code_arena.used;
|
||||
S4 rel32 = (S4)target - (S4)(current + 5);
|
||||
S4 rel32 = s4_(target) - s4_(current + 5);
|
||||
emit8(0xE8); // CALL rel32
|
||||
emit32((U4)rel32);
|
||||
emit32(u4_(rel32));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
IA_ void compile_and_run_tape(void) {
|
||||
farena_reset(&code_arena);
|
||||
IA_ void compile_and_run_tape(void)
|
||||
{
|
||||
farena_reset(& code_arena);
|
||||
dict_count = 0;
|
||||
log_count = 0;
|
||||
|
||||
@@ -215,18 +183,17 @@ IA_ void compile_and_run_tape(void) {
|
||||
emit8(0x48); emit8(0x8B); emit8(0x41); emit8(0x70); // mov rax, [rcx+112]
|
||||
emit8(0x48); emit8(0x8B); emit8(0x51); emit8(0x78); // mov rdx, [rcx+120]
|
||||
|
||||
U4*r tape_ptr = C_(U4*r, tape_arena.start);
|
||||
U4*r tape_ptr = u4_r(tape_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 == tmpl(STag, Define)) {
|
||||
if (!in_def) {
|
||||
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) {
|
||||
emit8(0xE9); // JMP rel32 (Skip over definition body)
|
||||
def_jmp_offset = code_arena.used;
|
||||
emit32(0);
|
||||
@@ -237,22 +204,27 @@ IA_ void compile_and_run_tape(void) {
|
||||
dict[dict_count].offset = code_arena.used;
|
||||
dict_count++;
|
||||
}
|
||||
} else if (tag == tmpl(STag, Call)) {
|
||||
}
|
||||
else if (tag == STag_Call)
|
||||
{
|
||||
compile_action(val);
|
||||
if (val == ID2('R','E') && in_def) {
|
||||
if (val == id2('R','E') && in_def) {
|
||||
// End of definition block, patch the jump
|
||||
U4 current = code_arena.used;
|
||||
*(U4*)(code_arena.start + def_jmp_offset) = current - (def_jmp_offset + 4);
|
||||
u4_r(code_arena.start + def_jmp_offset)[0] = current - (def_jmp_offset + 4);
|
||||
in_def = false;
|
||||
}
|
||||
} else if (tag == tmpl(STag, Data)) {
|
||||
}
|
||||
else if (tag == tmpl(STag, Data)) {
|
||||
emit8(0x48); emit8(0x89); emit8(0xC2); // mov rdx, rax
|
||||
emit8(0x48); emit8(0xC7); emit8(0xC0); emit32(val); // mov rax, imm32
|
||||
} else if (tag == tmpl(STag, Imm)) {
|
||||
}
|
||||
else if (tag == tmpl(STag, Imm))
|
||||
{
|
||||
if (in_def) {
|
||||
// If we execute something, we jump out of def block first
|
||||
U4 current = code_arena.used;
|
||||
*(U4*)(code_arena.start + def_jmp_offset) = current - (def_jmp_offset + 4);
|
||||
u4_r(code_arena.start + def_jmp_offset)[0] = current - (def_jmp_offset + 4);
|
||||
in_def = false;
|
||||
}
|
||||
compile_action(val);
|
||||
@@ -262,7 +234,7 @@ IA_ void compile_and_run_tape(void) {
|
||||
if (in_def) {
|
||||
// If we hit cursor inside a definition, patch jump so it doesn't crash on execution
|
||||
U4 current = code_arena.used;
|
||||
*(U4*)(code_arena.start + def_jmp_offset) = current - (def_jmp_offset + 4);
|
||||
u4_r(code_arena.start + def_jmp_offset)[0] = current - (def_jmp_offset + 4);
|
||||
}
|
||||
|
||||
// Epilogue: Save VM state back to globals
|
||||
@@ -271,8 +243,8 @@ IA_ void compile_and_run_tape(void) {
|
||||
emit8(0xC3); // ret
|
||||
|
||||
// Cast code arena to function pointer and CALL it!
|
||||
typedef void (*JIT_Func)(U8* globals_ptr);
|
||||
JIT_Func func = (JIT_Func)code_arena.start;
|
||||
typedef void JIT_Func(U8* globals_ptr);
|
||||
JIT_Func* func = (JIT_Func*)code_arena.start;
|
||||
func(vm_globals);
|
||||
|
||||
// Read state for UI
|
||||
@@ -292,18 +264,18 @@ IA_ void compile_and_run_tape(void) {
|
||||
#define MS_VK_SHIFT 0x10
|
||||
|
||||
// --- Window Procedure ---
|
||||
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);
|
||||
U4*r tape_ptr = C_(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;
|
||||
U4 tag = unpack_tag(t);
|
||||
U4 val = unpack_val(t);
|
||||
U1 c = u1_(wparam);
|
||||
|
||||
// Skip control characters and the 'E' that triggered the mode
|
||||
if (c < 32) break;
|
||||
@@ -316,96 +288,92 @@ S8 win_proc(void* hwnd, U4 msg, U8 wparam, S8 lparam) {
|
||||
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);
|
||||
tape_ptr[cursor_idx] = pack_token(tag, val);
|
||||
}
|
||||
} else if (tag != STag_Format) {
|
||||
U8*r anno_ptr = C_(U8*r, anno_arena.start);
|
||||
char* anno_str = (char*)&anno_ptr[cursor_idx];
|
||||
|
||||
}
|
||||
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++;
|
||||
|
||||
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';
|
||||
|
||||
// Update the 2-char token ID from the first 2 chars
|
||||
char c1 = anno_str[0] ? anno_str[0] : ' ';
|
||||
char c2 = anno_str[1] ? anno_str[1] : ' ';
|
||||
val = ID2(c1, c2);
|
||||
tape_ptr[cursor_idx] = PACK_TOKEN(tag, val);
|
||||
val = id2(c1, c2);
|
||||
tape_ptr[cursor_idx] = pack_token(tag, val);
|
||||
}
|
||||
}
|
||||
|
||||
vm_rax = 0; vm_rdx = 0; mem_zero(u8_(vm_globals), sizeof(vm_globals));
|
||||
compile_and_run_tape();
|
||||
ms_invalidate_rect(hwnd, NULL, true);
|
||||
ms_invalidate_rect(hwnd, nullptr, true);
|
||||
return 0;
|
||||
}
|
||||
case MS_WM_KEYDOWN: {
|
||||
if (wparam == 0x45 && editor_mode == MODE_NAV) { // 'E'
|
||||
editor_mode = MODE_EDIT;
|
||||
ms_invalidate_rect(hwnd, NULL, true);
|
||||
ms_invalidate_rect(hwnd, nullptr, true);
|
||||
return 0; // Consume the keypress so it doesn't trigger WM_CHAR
|
||||
}
|
||||
if (wparam == 0x1B && editor_mode == MODE_EDIT) { // ESC
|
||||
editor_mode = MODE_NAV;
|
||||
ms_invalidate_rect(hwnd, NULL, true);
|
||||
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);
|
||||
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 = C_(U8*r, anno_arena.start);
|
||||
char* anno_str = (char*)&anno_ptr[cursor_idx];
|
||||
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++;
|
||||
while (len < 8 && anno_str[len] != '\0' && anno_str[len] != ' ') len ++;
|
||||
if (len > 0) {
|
||||
anno_str[len-1] = '\0';
|
||||
anno_str[len - 1] = '\0';
|
||||
char c1 = anno_str[0] ? anno_str[0] : ' ';
|
||||
char c2 = anno_str[1] ? anno_str[1] : ' ';
|
||||
tape_ptr[cursor_idx] = PACK_TOKEN(tag, ID2(c1, c2));
|
||||
tape_ptr[cursor_idx] = pack_token(tag, id2(c1, c2));
|
||||
}
|
||||
}
|
||||
vm_rax = 0; vm_rdx = 0; mem_zero(u8_(vm_globals), sizeof(vm_globals));
|
||||
compile_and_run_tape();
|
||||
ms_invalidate_rect(hwnd, NULL, true);
|
||||
ms_invalidate_rect(hwnd, nullptr, true);
|
||||
}
|
||||
return 0; // Block navigation keys in Edit Mode
|
||||
}
|
||||
|
||||
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_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--;
|
||||
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--;
|
||||
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--;
|
||||
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++;
|
||||
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++; // Skip the newline
|
||||
next_line_start ++; // Skip the newline
|
||||
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++;
|
||||
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);
|
||||
}
|
||||
@@ -418,51 +386,53 @@ S8 win_proc(void* hwnd, U4 msg, U8 wparam, S8 lparam) {
|
||||
if (wparam == MS_VK_TAB) {
|
||||
// Cycle Color Tag
|
||||
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) {
|
||||
U4 tag = (unpack_tag(t) + 1) % STag_Count;
|
||||
tape_ptr[cursor_idx] = pack_token(tag, unpack_val(t));
|
||||
}
|
||||
else if (wparam == MS_VK_BACK)
|
||||
{
|
||||
// Delete Token
|
||||
// Shift: delete AT cursor | Regular: delete TO THE LEFT
|
||||
U8 delete_idx = cursor_idx;
|
||||
B4 is_shift = (ms_get_async_key_state(MS_VK_SHIFT) & 0x8000) != 0;
|
||||
|
||||
if (!is_shift) {
|
||||
if (is_shift == false) {
|
||||
if (cursor_idx > 0) {
|
||||
delete_idx = cursor_idx - 1;
|
||||
cursor_idx--;
|
||||
} else return 0;
|
||||
}
|
||||
|
||||
else return 0;
|
||||
}
|
||||
if (tape_count > 0) {
|
||||
U8*r anno_ptr = C_(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];
|
||||
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);
|
||||
}
|
||||
} else if (wparam == MS_VK_SPACE || wparam == MS_VK_RETURN) {
|
||||
}
|
||||
else if (wparam == MS_VK_SPACE || wparam == MS_VK_RETURN) {
|
||||
// Insert New Token
|
||||
// Shift: insert AFTER cursor | Regular: insert BEFORE cursor
|
||||
B4 is_shift = (ms_get_async_key_state(MS_VK_SHIFT) & 0x8000) != 0;
|
||||
U8 insert_idx = cursor_idx;
|
||||
if (is_shift) insert_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 = C_(U8*r, anno_arena.start);
|
||||
for (U8 i = tape_count; i > insert_idx; i--) {
|
||||
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);
|
||||
tape_ptr[insert_idx] = pack_token(STag_Format, 0xA);
|
||||
anno_ptr[insert_idx] = 0;
|
||||
} else {
|
||||
tape_ptr[insert_idx] = PACK_TOKEN(STag_Comment, ID2(' ',' '));
|
||||
tape_ptr[insert_idx] = pack_token(STag_Comment, id2(' ',' '));
|
||||
anno_ptr[insert_idx] = 0;
|
||||
}
|
||||
if (is_shift) cursor_idx++;
|
||||
if (is_shift) cursor_idx ++;
|
||||
tape_arena.used += sizeof(U4);
|
||||
anno_arena.used += sizeof(U8);
|
||||
}
|
||||
@@ -474,12 +444,12 @@ S8 win_proc(void* hwnd, U4 msg, U8 wparam, S8 lparam) {
|
||||
|
||||
compile_and_run_tape();
|
||||
|
||||
ms_invalidate_rect(hwnd, NULL, true);
|
||||
ms_invalidate_rect(hwnd, nullptr, true);
|
||||
return 0;
|
||||
}
|
||||
case MS_WM_PAINT: {
|
||||
MS_PAINTSTRUCT ps;
|
||||
void* hdc = ms_begin_paint(hwnd, &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);
|
||||
|
||||
@@ -495,34 +465,34 @@ S8 win_proc(void* hwnd, U4 msg, U8 wparam, S8 lparam) {
|
||||
S4 start_x = 40, start_y = 60, spacing_x = 110, spacing_y = 35;
|
||||
S4 x = start_x, y = start_y;
|
||||
|
||||
U4*r tape_ptr = C_(U4*r, tape_arena.start);
|
||||
U8*r anno_ptr = C_(U8*r, anno_arena.start);
|
||||
U4*r tape_ptr = u4_r(tape_arena.start);
|
||||
U8*r anno_ptr = u8_r(anno_arena.start);
|
||||
|
||||
// Render Tokens
|
||||
for (U8 i = 0; i < tape_count; i++) {
|
||||
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) {
|
||||
if (render_y >= 30 && render_y < 500)
|
||||
{
|
||||
U4 t = tape_ptr[i];
|
||||
U4 tag = UNPACK_TAG(t);
|
||||
U4 val = UNPACK_VAL(t);
|
||||
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 {
|
||||
}
|
||||
else
|
||||
{
|
||||
U4 color = tag_colors[tag];
|
||||
const char* prefix = tag_prefixes[tag];
|
||||
|
||||
@@ -532,24 +502,27 @@ S8 win_proc(void* hwnd, U4 msg, U8 wparam, S8 lparam) {
|
||||
ms_set_text_color(hdc, 0x001E1E1E);
|
||||
}
|
||||
|
||||
char val_str[9]; if (tag == STag_Data) {
|
||||
char val_str[9];
|
||||
if (tag == STag_Data) {
|
||||
u64_to_hex(val, val_str, 6);
|
||||
val_str[6] = '\0';
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
// Extract annotation string
|
||||
char* a_str = (char*)&anno;
|
||||
char* a_str = (char*) & anno;
|
||||
if (a_str[0] == '\0') {
|
||||
// Fallback to 2-character ID
|
||||
val_str[0] = (char)((val >> 8) & 0xFF);
|
||||
val_str[1] = (char)(val & 0xFF);
|
||||
val_str[2] = ' '; val_str[3] = ' '; val_str[4] = ' '; val_str[5] = ' ';
|
||||
val_str[6] = '\0';
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
mem_copy(u8_(val_str), u8_(a_str), 8);
|
||||
val_str[8] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
char out_buf[12];
|
||||
out_buf[0] = prefix[0];
|
||||
out_buf[1] = ' ';
|
||||
@@ -559,10 +532,12 @@ S8 win_proc(void* hwnd, U4 msg, U8 wparam, S8 lparam) {
|
||||
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) {
|
||||
}
|
||||
else if (unpack_tag(tape_ptr[i]) == STag_Format && unpack_val(tape_ptr[i]) == 0xA) {
|
||||
x = start_x;
|
||||
y += spacing_y;
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
x += spacing_x;
|
||||
}
|
||||
}
|
||||
@@ -591,25 +566,23 @@ S8 win_proc(void* hwnd, U4 msg, U8 wparam, S8 lparam) {
|
||||
|
||||
// HUD: Display Current Token Meaning
|
||||
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_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++;
|
||||
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++) {
|
||||
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);
|
||||
@@ -620,7 +593,7 @@ S8 win_proc(void* hwnd, U4 msg, U8 wparam, S8 lparam) {
|
||||
// Print Log
|
||||
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++) {
|
||||
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);
|
||||
@@ -631,7 +604,7 @@ S8 win_proc(void* hwnd, U4 msg, U8 wparam, S8 lparam) {
|
||||
ms_delete_object(hBrushEdit);
|
||||
ms_delete_object(hBrushNav);
|
||||
ms_delete_object(hHudBrush);
|
||||
ms_end_paint(hwnd, &ps);
|
||||
ms_end_paint(hwnd, & ps);
|
||||
return 0;
|
||||
}
|
||||
case MS_WM_DESTROY: { ms_post_quit_message(0); return 0; }
|
||||
@@ -641,63 +614,63 @@ S8 win_proc(void* hwnd, U4 msg, U8 wparam, S8 lparam) {
|
||||
|
||||
int main(void) {
|
||||
// 1. Initialize Memory Arenas using WinAPI + FArena
|
||||
Slice tape_mem = slice_ut_(u8_(ms_virtual_alloc(NULL, 64 * 1024, MS_MEM_COMMIT | MS_MEM_RESERVE, MS_PAGE_READWRITE)), 64 * 1024);
|
||||
Slice anno_mem = slice_ut_(u8_(ms_virtual_alloc(NULL, 64 * 1024, MS_MEM_COMMIT | MS_MEM_RESERVE, MS_PAGE_READWRITE)), 64 * 1024);
|
||||
Slice code_mem = slice_ut_(u8_(ms_virtual_alloc(NULL, 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);
|
||||
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);
|
||||
farena_init(& tape_arena, tape_mem);
|
||||
farena_init(& anno_arena, anno_mem);
|
||||
farena_init(& code_arena, code_mem);
|
||||
|
||||
// Bootstrap Robust Sample: Factorial State Machine
|
||||
scatter(PACK_TOKEN(STag_Comment, ID2('I','N')), "INIT "); // .IN
|
||||
scatter(PACK_TOKEN(STag_Data, 5), 0); // $5
|
||||
scatter(PACK_TOKEN(STag_Data, 0), 0); // $0 (Addr)
|
||||
scatter(PACK_TOKEN(STag_Imm, ID2('!',' ')), "STORE "); // ^!
|
||||
scatter(pack_token(STag_Comment, id2('I','N')), "INIT "); // .IN
|
||||
scatter(pack_token(STag_Data, 5), 0); // $5
|
||||
scatter(pack_token(STag_Data, 0), 0); // $0 (Addr)
|
||||
scatter(pack_token(STag_Imm, id2('!',' ')), "STORE "); // ^!
|
||||
|
||||
scatter(PACK_TOKEN(STag_Data, 1), 0); // $1
|
||||
scatter(PACK_TOKEN(STag_Data, 1), 0); // $1 (Addr)
|
||||
scatter(PACK_TOKEN(STag_Imm, ID2('!',' ')), "STORE "); // ^!
|
||||
scatter(pack_token(STag_Data, 1), 0); // $1
|
||||
scatter(pack_token(STag_Data, 1), 0); // $1 (Addr)
|
||||
scatter(pack_token(STag_Imm, id2('!',' ')), "STORE "); // ^!
|
||||
|
||||
scatter(PACK_TOKEN(STag_Format, 0xA), 0); // Newline
|
||||
scatter(pack_token(STag_Format, 0xA), 0); // Newline
|
||||
|
||||
// Define the FS (Factorial Step) word in memory
|
||||
scatter(PACK_TOKEN(STag_Define, ID2('F','S')), "F_STEP ");
|
||||
scatter(PACK_TOKEN(STag_Data, 0), 0);
|
||||
scatter(PACK_TOKEN(STag_Call, ID2('@',' ')), "FETCH ");
|
||||
scatter(PACK_TOKEN(STag_Call, ID2('R','0')), "RET_IF_Z");
|
||||
scatter(PACK_TOKEN(STag_Format, 0xA), 0); // Newline
|
||||
scatter(pack_token(STag_Define, id2('F','S')), "F_STEP ");
|
||||
scatter(pack_token(STag_Data, 0), 0);
|
||||
scatter(pack_token(STag_Call, id2('@',' ')), "FETCH ");
|
||||
scatter(pack_token(STag_Call, id2('R','0')), "RET_IF_Z");
|
||||
scatter(pack_token(STag_Format, 0xA), 0); // Newline
|
||||
|
||||
scatter(PACK_TOKEN(STag_Data, 1), 0);
|
||||
scatter(PACK_TOKEN(STag_Call, ID2('@',' ')), "FETCH ");
|
||||
scatter(PACK_TOKEN(STag_Data, 0), 0);
|
||||
scatter(PACK_TOKEN(STag_Call, ID2('@',' ')), "FETCH ");
|
||||
scatter(PACK_TOKEN(STag_Call, ID2('M','*')), "MULT ");
|
||||
scatter(PACK_TOKEN(STag_Data, 1), 0);
|
||||
scatter(PACK_TOKEN(STag_Call, ID2('!',' ')), "STORE ");
|
||||
scatter(PACK_TOKEN(STag_Format, 0xA), 0); // Newline
|
||||
scatter(pack_token(STag_Data, 1), 0);
|
||||
scatter(pack_token(STag_Call, id2('@',' ')), "FETCH ");
|
||||
scatter(pack_token(STag_Data, 0), 0);
|
||||
scatter(pack_token(STag_Call, id2('@',' ')), "FETCH ");
|
||||
scatter(pack_token(STag_Call, id2('M','*')), "MULT ");
|
||||
scatter(pack_token(STag_Data, 1), 0);
|
||||
scatter(pack_token(STag_Call, id2('!',' ')), "STORE ");
|
||||
scatter(pack_token(STag_Format, 0xA), 0); // Newline
|
||||
|
||||
scatter(PACK_TOKEN(STag_Data, 0), 0);
|
||||
scatter(PACK_TOKEN(STag_Call, ID2('@',' ')), "FETCH ");
|
||||
scatter(PACK_TOKEN(STag_Call, ID2('-','1')), "DEC ");
|
||||
scatter(PACK_TOKEN(STag_Data, 0), 0);
|
||||
scatter(PACK_TOKEN(STag_Call, ID2('!',' ')), "STORE ");
|
||||
scatter(pack_token(STag_Data, 0), 0);
|
||||
scatter(pack_token(STag_Call, id2('@',' ')), "FETCH ");
|
||||
scatter(pack_token(STag_Call, id2('-','1')), "DEC ");
|
||||
scatter(pack_token(STag_Data, 0), 0);
|
||||
scatter(pack_token(STag_Call, id2('!',' ')), "STORE ");
|
||||
|
||||
scatter(PACK_TOKEN(STag_Data, 1), 0);
|
||||
scatter(PACK_TOKEN(STag_Call, ID2('@',' ')), "FETCH ");
|
||||
scatter(PACK_TOKEN(STag_Call, ID2('P','R')), "PRINT "); // Print Accumulator!
|
||||
scatter(pack_token(STag_Data, 1), 0);
|
||||
scatter(pack_token(STag_Call, id2('@',' ')), "FETCH ");
|
||||
scatter(pack_token(STag_Call, id2('P','R')), "PRINT "); // Print Accumulator!
|
||||
|
||||
scatter(PACK_TOKEN(STag_Call, ID2('R','E')), "RETURN "); // Return!
|
||||
scatter(pack_token(STag_Call, id2('R','E')), "RETURN "); // Return!
|
||||
|
||||
scatter(PACK_TOKEN(STag_Format, 0xA), 0); // Newline
|
||||
scatter(pack_token(STag_Format, 0xA), 0); // Newline
|
||||
|
||||
// Call it
|
||||
scatter(PACK_TOKEN(STag_Imm, ID2('F','S')), "F_STEP "); // ^FS
|
||||
scatter(PACK_TOKEN(STag_Imm, ID2('F','S')), "F_STEP ");
|
||||
scatter(PACK_TOKEN(STag_Imm, ID2('F','S')), "F_STEP ");
|
||||
scatter(PACK_TOKEN(STag_Imm, ID2('F','S')), "F_STEP ");
|
||||
scatter(PACK_TOKEN(STag_Imm, ID2('F','S')), "F_STEP ");
|
||||
scatter(pack_token(STag_Imm, id2('F','S')), "F_STEP "); // ^FS
|
||||
scatter(pack_token(STag_Imm, id2('F','S')), "F_STEP ");
|
||||
scatter(pack_token(STag_Imm, id2('F','S')), "F_STEP ");
|
||||
scatter(pack_token(STag_Imm, id2('F','S')), "F_STEP ");
|
||||
scatter(pack_token(STag_Imm, id2('F','S')), "F_STEP ");
|
||||
|
||||
MS_WNDCLASSA wc;
|
||||
mem_fill(u8_(& wc), 0, sizeof(wc));
|
||||
@@ -705,11 +678,11 @@ int main(void) {
|
||||
wc.hInstance = ms_get_stock_object(0);
|
||||
wc.lpszClassName = "ColorForthWindow";
|
||||
wc.hbrBackground = ms_get_stock_object(4);
|
||||
ms_register_class_a(&wc);
|
||||
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, NULL, NULL, wc.hInstance, NULL);
|
||||
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, NULL, 0, 0)) { ms_translate_message(&msg); ms_dispatch_message_a(&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;
|
||||
}
|
||||
|
||||
Binary file not shown.
@@ -0,0 +1,31 @@
|
||||
---
|
||||
name: colorforth-nudge
|
||||
description: "Interactive mentor for building a sourceless, zero-overhead ColorForth derivative. Use when the user wants to work on the 'bootslop' project, providing guided nudges and architectural validation based on the Lottes/Onat paradigm."
|
||||
---
|
||||
|
||||
# ColorForth Nudge & Review Skill
|
||||
|
||||
This skill transforms Gemini CLI into a highly contextualized mentor for building a specific type of zero-overhead, sourceless ColorForth derivative.
|
||||
|
||||
## Workflow Trigger
|
||||
|
||||
This skill should be activated when the user expresses intent to work on the "bootslop" or "ColorForth" project.
|
||||
|
||||
## Your Role: The Mentor
|
||||
|
||||
Your primary goal is to *guide*, not *do*. The user is learning how to build this system from scratch. Your task is to provide architectural validation, specific tactical assistance when requested, and "guided nudges" to help them get to the next step.
|
||||
|
||||
## Session Start Procedure
|
||||
|
||||
On activation, immediately perform the following steps:
|
||||
|
||||
1. **Refresh Context:** Read the following two files from the project root to load the complete architectural blueprint into your context:
|
||||
* `C:/projects/forth/bootslop/CONVENTIONS.md`
|
||||
* `C:/projects/forth/bootslop/references/Architectural_Consolidation.md`
|
||||
|
||||
2. **Analyze Current State:**
|
||||
* List the contents of the `attempt_1/` directory.
|
||||
* Read the `attempt_1/main.c` file.
|
||||
|
||||
3. **Prompt for Nudge:** Conclude your first response with a summary of the project's current state and ask the user for the next step.
|
||||
* **Example:** *"The context is loaded. The current prototype has a working JIT compiler, a modal editor, and a 2-character dictionary resolver. The editor supports keyboard input and visualizes the sourceless token array. What is the next implementation step you'd like me to guide you through?"*
|
||||
@@ -51,8 +51,8 @@ $compiler_args += $flag_no_optimization
|
||||
$compiler_args += $flag_diagnostics_absolute_paths
|
||||
$compiler_args += $flag_exceptions_disabled
|
||||
$compiler_args += ($flag_include + (join-path $path_root "attempt_1"))
|
||||
$compiler_args += "-nostdlib"
|
||||
$compiler_args += "-ffreestanding"
|
||||
# $compiler_args += "-nostdlib"
|
||||
# $compiler_args += "-ffreestanding"
|
||||
$compiler_args += $flag_compile
|
||||
$compiler_args += $flag_path_output, $object
|
||||
$compiler_args += $unit_source
|
||||
@@ -73,11 +73,10 @@ $linker_args += $flag_link_win_debug
|
||||
$linker_args += $flag_link_win_pdb + $pdb
|
||||
$linker_args += $flag_link_mapfile + $map
|
||||
$linker_args += $flag_link_win_subsystem_console
|
||||
$linker_args += "/nodefaultlib"
|
||||
# $linker_args += "/nodefaultlib"
|
||||
$linker_args += "kernel32.lib"
|
||||
$linker_args += "user32.lib"
|
||||
$linker_args += "gdi32.lib"
|
||||
$linker_args += "/entry:main"
|
||||
$linker_args += $object
|
||||
|
||||
$linker_args | ForEach-Object { Write-Host $_ }
|
||||
|
||||
Reference in New Issue
Block a user