Compare commits

...

4 Commits

Author SHA1 Message Date
ed 9dc4372bf3 cleanup 2026-02-20 20:51:36 -05:00
ed 784f3b9945 cleanup 2026-02-20 20:46:25 -05:00
ed 9db1748249 adjustments 2026-02-20 20:33:39 -05:00
ed bc30206e65 add skill and some adjustments 2026-02-20 19:42:19 -05:00
9 changed files with 800 additions and 673 deletions
+50
View File
@@ -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
+1
View File
@@ -3,3 +3,4 @@
references/processed_visuals
build
bootslop.proj
clay_ui_temp
+15 -11
View File
@@ -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 -1
View File
@@ -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.
+85 -16
View File
@@ -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
View File
@@ -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.
+31
View File
@@ -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?"*
+3 -4
View File
@@ -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 $_ }