Compare commits

..

6 Commits

Author SHA1 Message Date
ed f18af12968 progress (need to review further) 2026-02-22 18:09:22 -05:00
ed 03fb6a8180 add bootslop sproject toml for manual_slop 2026-02-21 20:58:26 -05:00
ed 67f8639ee7 progress 2026-02-21 14:18:15 -05:00
ed 6953e6b9b3 progress 2026-02-21 13:11:54 -05:00
ed 0a78cd8405 more gud ui 2026-02-21 12:16:32 -05:00
ed fcc4d4a515 gud ui 2026-02-21 12:11:39 -05:00
9 changed files with 2612 additions and 527 deletions
+31 -15
View File
@@ -44,24 +44,40 @@ Based on the curation in `./references/`, the resulting system MUST adhere to th
## Current Development Roadmap (attempt_1)
The prototype currently implements a functional WinAPI modal editor, a 2-register (`RAX`/`RDX`) JIT compiler with an `O(1)` visual linker, x68 32-bit instruction padding, implicit definition boundaries (Magenta Pipe), and an initial FFI Bridge (`emit_ffi_dance`).
The prototype currently implements:
- A functional WinAPI modal editor backed by `microui` for immediate-mode floating panels.
- A 2-register (`RAX`/`RDX`) JIT compiler with an `O(1)` visual linker (`tape_to_code_offset` table).
- x68-style 32-bit instruction padding via `pad32()` using `0x90` NOPs.
- Implicit definition boundaries (Magenta Pipe / `STag_Define`) emitting `JMP rel32` over the body and `xchg rax, rdx` at the entry point.
- An FFI Bridge (`x64_FFI_PROLOGUE`, `x64_FFI_MAP_ARGS`, `x64_FFI_CALL_ABS`, `x64_FFI_EPILOGUE`) for calling WinAPI functions safely from JIT'd code.
- Persistence via F1 (save) / F2 (load) to `cartridge.bin`.
- A Lambda tag (`STag_Lambda`) that compiles a code block out-of-line and leaves its address in `RAX`.
- A well-defined **x64 Emission DSL** (`#pragma region x64 Emission DSL`) with named REX prefixes, register encodings, ModRM/SIB composition macros, opcode constants, and composite instruction inline functions.
### x64 Emission DSL Discipline
All JIT code emission in `main.c` MUST use the x64 Emission DSL defined in the `#pragma region x64 Emission DSL` block. Raw magic bytes are forbidden. The allowed primitives are:
- **Composite helpers:** `x64_XCHG_RAX_RDX()`, `x64_MOV_RDX_RAX()`, `x64_MOV_RAX_RDX()`, `x64_ADD_RAX_RDX()`, `x64_SUB_RAX_RDX()`, `x64_IMUL_RAX_RDX()`, `x64_DEC_RAX()`, `x64_TEST_RAX_RAX()`, `x64_RET_IF_ZERO()`, `x64_RET_IF_SIGN()`, `x64_FETCH()`, `x64_STORE()`, `x64_CALL_RAX()`, `x64_RET()`.
- **Prologue/Epilogue:** `x64_JIT_PROLOGUE()`, `x64_JIT_EPILOGUE()`.
- **FFI:** `x64_FFI_PROLOGUE()`, `x64_FFI_MAP_ARGS()`, `x64_FFI_CALL_ABS(addr)`, `x64_FFI_EPILOGUE()`.
- **Raw emission only via named constants:** `emit8(x64_op_*)`, `emit8(x64_REX*)`, `emit8(x64_modrm(*))`, `emit32(val)`, `emit64(val)`.
- **Exception:** Forward jump placeholders (`JMP rel32`, `CALL rel32`) that have no composite helper may use `emit8(x64_op_JMP_rel32)` / `emit8(x64_op_CALL_rel32)` directly with a following `emit32(0)` placeholder, pending a dedicated DSL wrapper.
Here is a breakdown of the next steps to advance the `attempt_1` implementation towards a complete ColorForth derivative:
1. ~~**Refine the FFI / Tape Drive Argument Scatter:**~~ (Completed via `PRIM_PRINT` updating to load R8/R9 from `vm_globals`)
* Currently, the FFI bridge only maps `RAX` and `RDX` to the C-ABI `RCX` and `RDX`.
* Implement "Preemptive Scatter" logic so the FFI bridge correctly reads subsequent arguments (e.g., `R8`, `R9`) directly from pre-defined offsets in the `vm_globals` tape drive instead of just zeroing them out.
1. ~~**Refine the FFI / Tape Drive Argument Scatter:**~~ (Completed)
2. ~~**Implement the Self-Modifying Cartridge (Persistence):**~~ (Completed via F1/F2 save/load)
3. ~~**Refine Visual Editor Interactions:**~~ (Completed via `microui` integration)
4. ~~**Audit and enforce x64 Emission DSL usage throughout `main.c`:**~~ (Completed — all raw magic bytes replaced with named DSL constants and composite helpers)
2. **Expanded Annotation Layer (Variable-Length Comments):**
* The current `anno_arena` strictly allocates 8 bytes (a `U8`) per token.
* Refactor the visual editor and annotation memory management to allow for arbitrarily long text blocks (comments) to be attached to specific tokens without disrupting the `O(1)` compilation mapping.
5. **Add DSL wrappers for forward jump placeholders:**
- `x64_JMP_fwd_placeholder(U4* offset_out)` — emits `E9 00000000` and writes the patch offset.
- `x64_patch_fwd(U4 offset)` — patches a previously emitted placeholder with the current code position.
- This will eliminate the last remaining raw `emit8`/`emit32` pairs in `compile_and_run_tape`.
3. ~~**Implement the Self-Modifying Cartridge (Persistence):**~~ (Completed via F1/F2 save/load)
* 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.
6. **Expanded Annotation Layer (Variable-Length Comments):**
- The current `anno_arena` strictly allocates 8 bytes (a `U8`) per token.
- Refactor the visual editor and annotation memory management to allow for arbitrarily long text blocks (comments) to be attached to specific tokens without disrupting the `O(1)` compilation mapping.
4. **Refine Visual Editor Interactions:**
* Implement a proper internal text-editing cursor within the `STag_Data` and `STag_Format` (annotation) tokens, rather than relying on backspace-truncation and appendage.
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).
7. **Continuous Validation & Complex Control Flow:**
- Expand the primitive set to allow for more complex, AST-less control flow (e.g., handling Basic Block jumps `[ ]`).
- Investigate adding a `RET_IF_ZERO` + tail-call pattern for loops without explicit branch instructions.
+75 -27
View File
@@ -3,7 +3,7 @@
## Overview
`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.
The application presents a visual grid of 32-bit tokens rendered via `microui` floating panels 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.
## Core Concepts Implemented
@@ -17,42 +17,90 @@ The application presents a visual grid of 32-bit tokens and allows the user to n
3. **2-Register Stack & Global Memory:**
* The JIT compiler emits x86-64 that strictly adheres to Onat's `RAX`/`RDX` register stack.
* A `vm_globals` array is passed by pointer into the JIT'd code (via `RCX` on Win64), allowing instructions like `FETCH` and `STORE` to simulate the "tape drive" memory model.
* A `vm_globals` array (16 x `U8`) is passed by pointer into the JIT'd code via `RCX` (Win64 calling convention), held in `RBX` for the duration of execution.
* `vm_globals[14]` and `vm_globals[15]` serve as the `RAX` and `RDX` save/restore slots across JIT entry and exit.
* Indices 013 are available as the "tape drive" global memory for `FETCH`/`STORE` primitives.
4. **Handmade x86-64 JIT Emitter:**
* A small set of `emit8`/`emit32` functions write raw x86-64 opcodes into a `VirtualAlloc` block marked as executable (`PAGE_EXECUTE_READWRITE`).
* This buffer is cast to a C function pointer and called directly, bypassing the need for an external assembler like NASM or a complex library like Zydis for this prototype stage.
4. **Handmade x86-64 JIT Emitter with Named DSL:**
* A small set of `emit8`/`emit32`/`emit64` functions write raw x86-64 opcodes into a `VirtualAlloc` block marked `PAGE_EXECUTE_READWRITE`.
* All emission is done through a well-defined **x64 Emission DSL** (`#pragma region x64 Emission DSL`) consisting of:
* Named REX prefix constants (`x64_REX`, `x64_REX_R`, `x64_REX_B`, etc.).
* Named register encoding constants (`x64_reg_RAX`, `x64_reg_RDX`, etc.).
* ModRM and SIB composition macros (`x64_modrm(mod, reg, rm)`, `x64_sib(scale, index, base)`).
* Named opcode constants (`x64_op_MOV_reg_rm`, `x64_op_CALL_rel32`, etc.).
* Composite inline instruction helpers (`x64_XCHG_RAX_RDX()`, `x64_ADD_RAX_RDX()`, `x64_RET_IF_ZERO()`, `x64_FETCH()`, `x64_STORE()`, etc.).
* Prologue/Epilogue helpers (`x64_JIT_PROLOGUE()`, `x64_JIT_EPILOGUE()`).
* FFI helpers (`x64_FFI_PROLOGUE()`, `x64_FFI_MAP_ARGS()`, `x64_FFI_CALL_ABS(addr)`, `x64_FFI_EPILOGUE()`).
* **Raw magic bytes are forbidden** in `compile_and_run_tape` and `compile_action`. All emission uses the DSL.
5. **Modal Editor (Win32 GDI):**
* The UI is built with raw Win32 GDI calls defined in `duffle.h`.
* It features two modes: `Navigation` (gray cursor, arrow key movement) and `Edit` (orange cursor, text input).
5. **Modal Editor (Win32 GDI + microui):**
* The UI is built with `microui` rendered via raw Win32 GDI calls defined in `duffle.h`.
* It features two modes: `Navigation` (blue cursor, arrow key movement) and `Edit` (orange cursor, text input).
* The editor correctly handles token insertion, deletion (Vim-style backspace), tag cycling (Tab), and value editing, all while re-compiling and re-executing on every keystroke.
* Four floating panels: **ColorForth Source Tape**, **Compiler & Status**, **Registers & Globals**, **Print Log**.
6. **O(1) Dictionary & Visual Linking:**
* The dictionary relies on an edit-time visual linker. When the tape is modified, `relink_tape` resolves names to absolute source memory indices.
* The compiler resolves references in `O(1)` time instantly by indexing into an offset mapping table (`tape_to_code_offset`).
* The compiler resolves references in `O(1)` time by indexing into `tape_to_code_offset[65536]`.
7. **Implicit Definition Boundaries (Magenta Pipe):**
* Definitions implicitly cause the JIT to emit a `RET` to close the prior block, and an `xchg rax, rdx` to rotate the stack for the new block.
7. **Implicit Definition Boundaries (STag_Define):**
* A `STag_Define` token causes the JIT to:
1. Emit `RET` to close the prior block (via `x64_RET()`).
2. Emit a `JMP rel32` placeholder to skip over the new definition body.
3. Record the entry point in `tape_to_code_offset[i]`.
4. Emit `xchg rax, rdx` (via `x64_XCHG_RAX_RDX()`) as the definition's first instruction, rotating the 2-register stack.
8. **x68 Instruction Padding:**
* The JIT pads every logical block/instruction to exact 32-bit multiples using `0x90` (NOPs) to perfectly align with the visual token grid logic.
8. **Lambda Tag (STag_Lambda):**
* A `STag_Lambda` token compiles a code block out-of-line and leaves its absolute 64-bit address in `RAX` for use with `STORE` or `EXECUTE`.
* Implemented via `x64_MOV_RDX_RAX()` to save the prior TOS, a `mov rax, imm64` with a patched-in address, and a `JMP rel32` to skip the body.
9. **The FFI Bridge:**
* The system uses an FFI macro (`emit_ffi_dance`) to align the `RSP` stack to 16 bytes, allocate 32 bytes of shadow space, and map the 2-register data stack/globals into the Windows C-ABI (`RCX`, `RDX`, `R8`, `R9`) to safely call WinAPI functions (like `MessageBoxA`).
9. **x68 Instruction Padding:**
* `pad32()` pads every logical block/instruction to exact 32-bit multiples using `0x90` (NOPs), aligning with the visual token grid.
## What's Missing (TODO)
10. **The FFI Bridge:**
* `x64_FFI_PROLOGUE()` pushes `RDX`, aligns `RSP` to 16 bytes, and allocates 32 bytes of shadow space. * x64_FFI_MAP_ARGS() maps the 2-register stack and globals into Win64 ABI registers (RCX=RAX, R8=globals[0], R9=globals[1]). * x64_FFI_CALL_ABS(addr) loads the absolute 64-bit function address into R10 and calls it. * x64_FFI_EPILOGUE() restores RSP and pops RDX.
* **Saving/Loading (Persistence):** The tape and annotation arenas are purely in-memory and are lost when the program closes. Need to implement the self-modifying OS cartridge concept.
* **Expanded Instruction Set:** The JIT only knows a handful of primitives. It has no support for floating point or more complex branches.
* **Annotation Editing & Comments:** Typing into an annotation just appends characters up to 8 bytes. A proper text-editing cursor within the token is needed, and support for arbitrarily long comments should be implemented.
* **Tape Drive / Preemptive Scatter Logic:** Improve the FFI argument mapping to properly read from the "tape drive" memory slots instead of just mapping RAX/RDX to the first parameters.
Persistence (Cartridge Save/Load):
F1 saves the tape and annotation arenas (with metadata) to cartridge.bin via WriteFile.
F2 loads from cartridge.bin, re-runs relink_tape() and compile_and_run_tape() to restore full live state.
Primitive Instruction Set
```md
ID Name Emitted x86-64 (via DSL)
1 SWAP x64_XCHG_RAX_RDX()
2 MULT x64_IMUL_RAX_RDX()
3 ADD x64_ADD_RAX_RDX()
4 FETCH x64_FETCH() — mov rax, [rbx + rax*8]
5 DEC x64_DEC_RAX()
6 STORE x64_STORE() — mov [rbx + rax*8], rdx
7 RET_IF_Z x64_RET_IF_ZERO()
8 RETURN x64_RET()
9 PRINT FFI dance → ms_builtin_print
10 RET_IF_S x64_RET_IF_SIGN()
11 DUP x64_MOV_RDX_RAX()
12 DROP x64_MOV_RAX_RDX()
13 SUB x64_SUB_RAX_RDX()
14 EXECUTE x64_CALL_RAX()
```
## Whats Missing (TODO)
- DSL wrappers for forward jump placeholders: The JMP rel32 and CALL rel32 forward-jump patterns in compile_and_run_tape still use bare emit8(x64_op_JMP_rel32) + emit32(0) pairs. Dedicated x64_JMP_fwd_placeholder(U4* offset_out) and x64_patch_fwd(U4 offset) helpers should be added to the DSL to eliminate this last gap.
- Expanded Annotation Layer (Variable-Length Comments): The anno_arena strictly allocates 8 bytes per token. Arbitrarily long comment blocks need a separate indirection layer without disrupting the O(1) compile mapping.
- Expanded Instruction Set: No floating point. No multi-way branching beyond RET_IF_Z / RET_IF_S.
- Basic Block Jumps [ ]: Lottes-style scoped jump targets for structured control flow without an AST are not yet implemented.
- Tape Drive / Preemptive Scatter Improvements: The FFI argument mapping reads globals[0] and globals[1] for R8/R9. A proper scatter model that pre-places arguments into named slots before a call is not yet formalized.
- Self-Hosting Bootstrap: The editor and JIT are written in C. The long-term goal is to rewrite the core inside the custom language itself, discarding the C host.
## References Utilized
* **Heavily Utilized:**
* **Onat's Talks:** The core architecture (2-register stack, global memory tape, JIT philosophy) is a direct implementation of the concepts from his VAMP/KYRA presentations.
* **Lottes' Twitter Notes:** The 2-character mapped dictionary, `ret-if-signed` (`RET_IF_ZERO`), and annotation layer concepts were taken directly from his tweets.
* **User's `duffle.h` & `fortish-study`:** The C coding conventions (X-Macros, `FArena`, byte-width types, `ms_` prefixes) were adopted from these sources.
* **Lightly Utilized:**
* **Lottes' Blog:** Provided the high-level "sourceless" philosophy and inspiration.
* **Grok Searches:** Served to validate our understanding and provide parallels (like Wasm's linear memory), but did not provide direct implementation details.
### Heavily Utilized:
- Onats Talks: The core architecture (2-register stack, global memory tape, JIT philosophy) is a direct implementation of the concepts from his VAMP/KYRA presentations.
Lottes Twitter Notes: The 2-character mapped dictionary, ret-if-signed (RET_IF_ZERO), and annotation layer concepts were taken directly from his tweets.
- Users duffle.h & fortish-study: The C coding conventions (X-Macros, FArena, byte-width types, ms_ prefixes) were adopted from these sources.
### Lightly Utilized:
- Lottes Blog: Provided the high-level “sourceless” philosophy and inspiration.
- Grok Searches: Served to validate our understanding and provide parallels (like Wasms linear memory), but did not provide direct implementation details.
+17
View File
@@ -676,6 +676,11 @@ WinAPI void* ms_create_font_a(
U4 iPitchAndFamily,
char const* pszFaceName
) 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 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");
@@ -685,9 +690,21 @@ WinAPI S4 ms_delete_object(void* ho) asm("
#define MS_MEM_COMMIT 0x00001000
#define MS_MEM_RESERVE 0x00002000
#define MS_PAGE_READWRITE 0x04
#define MS_SRCCOPY 0x00CC0020
#define MS_WM_DESTROY 0x0002
#define MS_WM_SIZE 0x0005
#define MS_WM_PAINT 0x000F
#define MS_WM_ERASEBKGND 0x0014
#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_VISIBLE 0x10000000
#define MS_VK_LEFT 0x25
+714 -177
View File
File diff suppressed because it is too large Load Diff
+1208
View File
File diff suppressed because it is too large Load Diff
+296
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
-98
View File
@@ -1,98 +0,0 @@
#pragma region OS
#pragma warning(push)
#pragma warning(disable: 4820)
#pragma comment(lib, "Kernel32.lib")
#pragma comment(lib, "Advapi32.lib")
#define MS_INVALID_HANDLE_VALUE ((MS_HANDLE)(S8)-1)
#define MS_ANYSIZE_ARRAY 1
#define MS_MEM_COMMIT 0x00001000
#define MS_MEM_RESERVE 0x00002000
#define MS_MEM_RELEASE 0x00008000
#define MS_MEM_LARGE_PAGES 0x20000000
#define MS_PAGE_READWRITE 0x04
#define MS_TOKEN_ADJUST_PRIVILEGES (0x0020)
#define MS_SE_PRIVILEGE_ENABLED (0x00000002L)
#define MS_TOKEN_QUERY (0x0008)
#define MS__TEXT(quote) L ## quote // r_winnt
#define MS_TEXT(quote) MS__TEXT(quote) // r_winnt
#define MS_SE_LOCK_MEMORY_NAME MS_TEXT("SeLockMemoryPrivilege")
typedef int MS_BOOL;
typedef unsigned long MS_DWORD;
typedef MS_DWORD* MS_PDWORD;
typedef void* MS_HANDLE;
typedef MS_HANDLE* MS_PHANDLE;
typedef long MS_LONG;
typedef S8 MS_LONGLONG;
typedef char const* MS_LPCSTR;
typedef unsigned short* MS_LPWSTR, *MS_PWSTR;
typedef void* MS_LPVOID;
typedef MS_DWORD* MS_LPDWORD;
typedef U8 MS_ULONG_PTR, *MS_PULONG_PTR;
typedef void const* MS_LPCVOID;
typedef struct MS_SECURITY_ATTRIBUTES *MS_PSECURITY_ATTRIBUTES, *MS_LPSECURITY_ATTRIBUTES;
typedef struct MS_OVERLAPPED *MS_LPOVERLAPPED;
typedef def_union(MS_LARGE_INTEGER) { struct { MS_DWORD LowPart; MS_LONG HighPart; } _; struct { MS_DWORD LowPart; MS_LONG HighPart; } u; MS_LONGLONG QuadPart; };
typedef def_struct(MS_FILE) { void* _Placeholder; };
typedef def_struct(MS_SECURITY_ATTRIBUTES) { MS_DWORD nLength; A4_B1 _PAD_; MS_LPVOID lpSecurityDescriptor; MS_BOOL bInheritHandle; };
typedef def_struct(MS_OVERLAPPED) { MS_ULONG_PTR Internal; MS_ULONG_PTR InternalHigh; union { struct { MS_DWORD Offset; MS_DWORD OffsetHigh; } _; void* Pointer; } _; MS_HANDLE hEvent; };
typedef struct MS_LUID* MS_PLUID;
typedef struct MS_LUID_AND_ATTRIBUTES* MS_PLUID_AND_ATTRIBUTES;
typedef struct MS_TOKEN_PRIVILEGES* MS_PTOKEN_PRIVILEGES;
typedef def_struct(MS_LUID) { MS_DWORD LowPart; MS_LONG HighPart; };
typedef def_struct(MS_LUID_AND_ATTRIBUTES) { MS_LUID Luid; MS_DWORD Attributes; };
typedef def_struct(MS_TOKEN_PRIVILEGES) { MS_DWORD PrivilegeCount; MS_LUID_AND_ATTRIBUTES Privileges[MS_ANYSIZE_ARRAY]; };
WinAPI MS_BOOL CloseHandle(MS_HANDLE hObject);
WinAPI MS_BOOL AdjustTokenPrivileges(MS_HANDLE TokenHandle, MS_BOOL DisableAllPrivileges, MS_PTOKEN_PRIVILEGES NewState, MS_DWORD BufferLength, MS_PTOKEN_PRIVILEGES PreviousState, MS_PDWORD ReturnLength);
WinAPI MS_HANDLE GetCurrentProcess(void);
WinAPI U8 GetLargePageMinimum(void);
WinAPI MS_BOOL LookupPrivilegeValueW(MS_LPWSTR lpSystemName, MS_LPWSTR lpName, MS_PLUID lpLuid);
WinAPI MS_BOOL OpenProcessToken(MS_HANDLE ProcessHandle, MS_DWORD DesiredAccess, MS_PHANDLE TokenHandle);
WinAPI MS_LPVOID VirtualAlloc(MS_LPVOID lpAddress, U8 dwSize, MS_DWORD flAllocationType, MS_DWORD flProtect);
WinAPI MS_BOOL VirtualFree (MS_LPVOID lpAddress, U8 dwSize, MS_DWORD dwFreeType);
#pragma warning(pop)
typedef def_struct(OS_Windows_State) { OS_SystemInfo system_info; };
global OS_Windows_State os__windows_info;
IA_ OS_SystemInfo* os_system_info(void) { return & os__windows_info.system_info; }
I_
void os__enable_large_pages(void) {
MS_HANDLE token;
if (OpenProcessToken(GetCurrentProcess(), MS_TOKEN_ADJUST_PRIVILEGES | MS_TOKEN_QUERY, &token))
{
MS_LUID luid;
if (LookupPrivilegeValueW(0, MS_SE_LOCK_MEMORY_NAME, &luid))
{
MS_TOKEN_PRIVILEGES priv;
priv.PrivilegeCount = 1;
priv.Privileges[0].Luid = luid;
priv.Privileges[0].Attributes = MS_SE_PRIVILEGE_ENABLED;
AdjustTokenPrivileges(token, 0, & priv, size_of(priv), 0, 0);
}
CloseHandle(token);
}
}
I_
void os_init(void) {
os__enable_large_pages();
OS_SystemInfo*R_ info = & os__windows_info.system_info;
info->target_page_size = (U8)GetLargePageMinimum();
}
// TODO(Ed): Large pages disabled for now... (not failing gracefully)
IA_ U8 os__vmem_reserve(U8 size, Opts_vmem*R_ opts) {
assert(opts != nullptr);
void*R_ result = VirtualAlloc(cast(void*R_, opts->base_addr), size
, MS_MEM_RESERVE
// |MS_MEM_COMMIT|(opts->no_large_pages == false ? MS_MEM_LARGE_PAGES : 0)
, MS_PAGE_READWRITE
);
return u8_(result);
}
IA_ B4 os__vmem_commit(U8 vm, U8 size, Opts_vmem*R_ opts) {
assert(opts != nullptr);
// if (opts->no_large_pages == false ) { return 1; }
B4 result = (VirtualAlloc(cast(MS_LPVOID, vm), size, MS_MEM_COMMIT, MS_PAGE_READWRITE) != 0);
return result;
}
I_ void os_vmem_release(U8 vm, U8 size) { VirtualFree(cast(MS_LPVOID, vm), 0, MS_MEM_RELEASE); }
#pragma endregion OS
+61
View File
@@ -0,0 +1,61 @@
[project]
name = "bootslop"
git_dir = "C:/projects/forth/bootslop"
word_wrap = true
system_prompt = "Avoid reading bootslop.md. It has full discussion histories, its very expnesive for your token limits."
main_context = "C:/projects/forth/bootslop/GEMINI.md"
[output]
namespace = "bootslop"
output_dir = "./md_gen"
[files]
base_dir = "."
paths = [
"C:/projects/forth/bootslop/.editorconfig",
"C:/projects/forth/bootslop/CONVENTIONS.md",
"C:/projects/forth/bootslop/GEMINI.md",
"C:/projects/forth/bootslop/Readme.md",
"C:/projects/forth/bootslop/references/Architectural_Consolidation.md",
"C:/projects/forth/bootslop/references/kyra_in-depth.md",
"C:/projects/forth/bootslop/references/neokineogfx_in-depth.md",
"C:/projects/forth/bootslop/scripts/build.attempt_1.c.ps1",
"C:/projects/forth/bootslop/attempt_1/attempt_1.md",
"C:/projects/forth/bootslop/attempt_1/duffle.amd64.win32.h",
"C:/projects/forth/bootslop/attempt_1/main.c",
"C:/projects/forth/bootslop/attempt_1/microui.h",
]
[screenshots]
base_dir = "C:/Users/Ed/scoop/apps/sharex/current/ShareX/Screenshots/2026-02"
paths = []
[discussion]
roles = [
"User",
"AI",
"Vendor API",
"System",
]
active = "test"
auto_add = true
[discussion.discussions.main]
git_commit = ""
last_updated = "2026-02-22T11:09:05"
history = [
"@2026-02-21T20:58:31\nUser:\nwhat should we do next with attempt_1",
"@2026-02-21T20:58:32\nAI:\nNow I have a clear picture. Let me give you a prioritized assessment:\n\n---\n\n## Assessment: What to Do Next with `attempt_1`\n\nBased on the roadmap, the code, and the gap analysis, here's what I'd recommend in priority order:\n\n### 1. **Fix the JMP rel32 Hack & Add Forward-Jump DSL Wrappers** (Quick Win — Immediate)\n\nThis is listed as item #5 in the roadmap and it's the most mechanically obvious fix. Right now you have this abomination on line 657:\n\n```c\nemit8(x64_op_CALL_rel32 - 3); // E9 = JMP rel32\n```\n\n`0xE8 - 3 = 0xE5`, which is **wrong**. `JMP rel32` is `0xE9`, and `0xE8 - 3 = 0xE5` (which is `IN EAX, imm8`). This is a **live bug** — the define-skip jump is emitting garbage. It only works by accident if that code path is never actually taken, or if it's being masked by some other behavior.\n\nThe fix is trivial: you already have `x64_op_JMP_rel32` defined as `0xE9` in the DSL. Plus, adding the two helpers (`x64_JMP_fwd_placeholder` / `x64_CALL_fwd_placeholder` / `x64_patch_fwd`) will clean up ~6 raw emit patterns in `compile_and_run_tape`.\n\n**Also needed:** A `x64_MOV_RAX_IMM64()` helper and a `x64_MOV_RAX_IMM32()` helper for the Data and Lambda tag emission, which are currently still raw.\n\n### 2. **Add a `x64_MOV_RAX_IMM32(val)` / `x64_MOV_RAX_IMM64_placeholder()` DSL wrapper** (Quick Win)\n\nLines 683-686 and 707-710 are raw emit sequences for `mov rax, imm64` and `mov r/m, imm32` that should have named DSL wrappers. This is the last gap before you can honestly say \"all emission uses the DSL.\"\n\n### 3. **Basic Block Jumps `[ ]`** (The Real Next Feature)\n\nThis is item #7 from the roadmap and is the **most architecturally significant next step**. Right now your control flow is limited to:\n- `RET_IF_ZERO` / `RET_IF_SIGN` (conditional early returns)\n- Lambdas (out-of-line code blocks)\n- Unconditional `CALL`\n\nYou have no way to express a loop or a conditional branch *within* a definition. The `[ ]` basic block mechanism from Onat would give you:\n- `[` — mark the top of a basic block (save the code offset)\n- `]` — emit a conditional or unconditional backward jump to the `[`\n- Or: `[` emits a forward-jump placeholder, and `]` patches it (for if-style blocks)\n\nThis would let you write factorial as a loop inside a single definition instead of relying on repeated `Imm` calls to `F_STEP`.\n\n### 4. **Expanded Annotation Layer** (Important but Can Wait)\n\nThe 8-byte annotation limit per token is functional but restrictive. This is item #6 — refactoring to variable-length comments. I'd defer this until after `[ ]` blocks work, because it's a UI/data-structure change rather than a compiler feature.\n\n---\n\n## My Recommendation: Do Items 1 + 2 Right Now\n\nFix the JMP bug, add the forward-jump DSL wrappers, and add the remaining immediate-move wrappers. This is ~30 minutes of clean mechanical work, eliminates every remaining raw emit in `compile_and_run_tape`, and gives you the exact `x64_patch_fwd` infrastructure you'll need for `[ ]` basic blocks immediately after.\n\nWant me to implement items 1 and 2 now?",
]
[discussion.discussions.test]
git_commit = "03fb6a818060e71e53e1c240e5f869d4d7e64c49"
last_updated = "2026-02-22T17:03:58"
history = [
"@2026-02-22T11:15:32\nUser:\nWhat should we do next with attempt_1?",
"@2026-02-22T11:15:34\nAI:\nLooking at the `GEMINI.md` roadmap, items 1-4 are completed. The remaining items are:\n\n**5. DSL wrappers for forward jump placeholders** — The `JMP rel32` and `CALL rel32` forward-jump patterns in `compile_and_run_tape` still use bare `emit8(x64_op_JMP_rel32) + emit32(0)` pairs. This is the most surgical, self-contained next step.\n\n**6. Expanded Annotation Layer** — The `anno_arena` is fixed at 8 bytes per token. Arbitrary-length comments need an indirection layer.\n\n**7. Continuous Validation & Complex Control Flow** — Basic Block jumps `[ ]`, more conditional patterns, loop primitives.\n\n---\n\nMy recommendation is to tackle **#5 first**, because:\n\n- It's the smallest, most well-defined gap. The exact API is already specced in the roadmap:\n - `x64_JMP_fwd_placeholder(U4* offset_out)` — emits `E9 00000000`, writes the patch offset.\n - `x64_patch_fwd(U4 offset)` — patches the placeholder with the current code position.\n- It closes the last \"raw magic bytes\" hole in the DSL discipline, making the emitter fully consistent.\n- It's a prerequisite for **#7** (Basic Block `[ ]` jumps need exactly this mechanism to resolve forward targets cleanly).\n\nAfter #5, **#7 (Basic Blocks `[ ]`)** is the highest-leverage architectural feature — it's what unlocks structured control flow without an AST, which is the core of the Lottes/Onat paradigm. **#6** (variable-length annotations) is more of a quality-of-life editor feature and can wait.\n\nWant me to implement **#5** now?",
"@2026-02-22T11:15:45\nUser:\nAlright lets do 5.",
"@2026-02-22T11:17:41\nAI:\nLooking at `main.c`, I need to add two DSL helpers to the `x64 Emission DSL` region and then replace the bare `emit8`/`emit32` pairs in `compile_and_run_tape`. Let me identify exactly what needs changing.\n\nThere are three raw forward-jump sites in `compile_and_run_tape`:\n\n1. **`STag_Define` block** — `emit8(x64_op_CALL_rel32 - 3)` + `emit32(0)` (note: `E9` is `JMP rel32`, written as `CALL_rel32 - 3` which is a bug-prone magic expression)\n2. **`STag_Lambda` block** — `emit8(x64_op_JMP_rel32)` + `emit32(0)`\n3. **Both patch sites** — `u4_r(code_arena.start + <offset>)[0] = current - (<offset> + 4)`\n\nI'll add `x64_JMP_fwd_placeholder` and `x64_patch_fwd` to the DSL, then clean up all three sites.\n\nI can see the file was saved but the PowerShell string replacement missed the `STag_Define` and both patch sites inside the loop — the old raw patterns are still there in `compile_and_run_tape`. The new DSL helpers were added correctly to the DSL region, but the call sites in the loop body weren't updated. Let me fix those now.\n\nThe DSL helpers were added correctly but the call sites in `compile_and_run_tape` still have the old raw patterns. The string replacement is failing because of whitespace/tab differences. I'll use a Python helper script to do the targeted replacements reliably.\n\nThe file looks correct. Let me do a final verification build to confirm it compiles and links cleanly.\n\nItem 5 is done and clean. Here's a summary of what was accomplished:\n\n**Two new DSL helpers added** to the `#pragma region x64 Emission DSL` block, immediately after `x64_RET()`:\n\n- `x64_JMP_fwd_placeholder(U4* offset_out)` — emits `E9 00000000` and records the displacement field's offset for later patching.\n- `x64_patch_fwd(U4 offset)` — writes the correct `rel32` displacement back into the previously emitted placeholder, computed as `current_pos - (offset + 4)`.\n\n**Six raw emission sites eliminated** in `compile_and_run_tape`:\n\n| Site | Old | New |\n|---|---|---|\n| `STag_Define` JMP emission | `emit8(x64_op_CALL_rel32 - 3)` + `emit32(0)` | `x64_JMP_fwd_placeholder(& def_jmp_offset)` |\n| `STag_Lambda` JMP emission | `emit8(x64_op_JMP_rel32)` + `emit32(0)` | `x64_JMP_fwd_placeholder(& lambda_jmp_offset)` |\n| Lambda patch (in loop) | `u4_r(...)[0] = current - (offset + 4)` | `x64_patch_fwd(lambda_jmp_offset)` |\n| Define patch (in loop) | `u4_r(...)[0] = current - (offset + 4)` | `x64_patch_fwd(def_jmp_offset)` |\n| Lambda patch (tail) | `u4_r(...)[0] = current - (offset + 4)` | `x64_patch_fwd(lambda_jmp_offset)` |\n| Define patch (tail) | `u4_r(...)[0] = current - (offset + 4)` | `x64_patch_fwd(def_jmp_offset)` |\n\nThe DSL is now fully consistent — no raw forward-jump patterns remain anywhere in `compile_and_run_tape`. The `x64_op_JMP_rel32` exception note in `GEMINI.md` can now be retired as well. Ready to move on to **#7 (Basic Block jumps `[ ]`)** whenever you are.",
"@2026-02-22T11:41:36\nUser:\nMove on to 7. (basic block jumps) sure.",
"@2026-02-22T11:45:25\nAI:\nI have successfully implemented the Basic Block jumps (`[ ]`) and the `RET_IF_ZERO` + tail-call pattern for loops. \n\nHere is a breakdown of what was added to `attempt_1/main.c`:\n\n1. **New Primitives:**\n - `[ ` (`PRIM_IF`): Emits a conditional forward jump (`JZ rel32`) that skips the block if `RAX == 0`. It pushes the patch offset to a new `ctrl_stack` managed by the JIT compiler.\n - `] ` (`PRIM_END`): Pops the offset from `ctrl_stack` and patches the forward jump with the correct relative displacement.\n - `RECURSE ` (`PRIM_RECURSE`): Emits an unconditional backward jump (`JMP rel32`) to the entry point of the current definition (`tape_to_code_offset[current_def_idx]`).\n\n2. **Tail-Call Loop Pattern:**\n The `Factorial` test was refactored. Instead of manually calling `F_STEP` five times, `F_STEP` now ends with a `RECURSE` primitive. Because `F_STEP` already uses `RET_IF_Z` to break out when the counter reaches zero, this effectively creates a zero-overhead `while` loop using the tail-call pattern.\n\n3. **AST-Less Control Flow (`[ ]`):**\n A new `IF TEST` was added to the tape initialization. It demonstrates the `[` and `]` block. It pushes `0` to `RAX`, hits `[`, and correctly skips the inner block. Then it pushes `1` to `RAX`, hits `[`, and correctly executes the inner block.\n\nThe compiler logic for these constructs is extremely simple and operates strictly in `O(1)` time during the single JIT pass, adhering to the Lottes/Onat \"zero-overhead\" philosophy. The project builds cleanly and the executable is ready to run.\n\nWould you like to move on to **#6 (Expanded Annotation Layer)** next, or is there anything you want to tweak with the control flow?",
]
BIN
View File
Binary file not shown.