This is a submission for the Hacktoberfest Open-Source AI Challenge Week 3: Slow and Steady
TLDR;
With Cat Coding - my old cat Pitypan...
For further actions, you may consider blocking this person and/or reporting abuse
The byte-alongside-instruction dump is the part I would actually use, and for a specific reason.
I ship WebAssembly in production - an ONNX model running in the browser for background removal - and the debugging story for browser wasm is not really a syntax problem. When it goes wrong it is almost never "I cannot read the disassembly", it is "linear memory grew, a threaded init broke because the page is not cross-origin isolated, or an allocation path in generated code did something I did not predict". At that point a WAT pane in devtools is close to useless, because the address disappears the moment you scroll away from the line.
That is why
00000032 : 20 00 : GET 0is a better artefact than a prettier disassembler: the address lives in the line, so a bug report can quote one line and know it points at exactly one instruction. A debugger affordance that survives copy-paste is worth more to me than nicer mnemonics, and theBACKstep is the other half of that - it is the only part of wasm inspection I have ever wanted and never had.To the "why not target a wasm-native language" question in the comments: in the browser the parts that eat the time sit below the language layer. Memory can only grow, never shrink, so one large file leaves that RAM unavailable for the rest of the session. Threads need SharedArrayBuffer, which needs cross-origin isolation, which breaks ordinary third-party script loading. I ended up with the boring shape - plain JS orchestration, wasm only where the math is heavy - because the readability of the wasm source was never the bottleneck.
So I would put HEXAW exactly where you have it: small hand-written modules and teaching, where a single-page module can genuinely be held in your head. That is a real niche, not a compromise.
In the next version, I'm planning to make dynamic memory addresses easier to track.
For example, function definitions and code bodies live in separate sections, and WASM makes extensive use of LEB128 encoding:
CONST -1→41 7FCONST 300→41 AC 02So the length of an instruction can change depending on its value, which makes tracking byte offsets a bit tricky.
And yes, that's exactly the idea behind HEXAW: a simple way to write small programs and see their WASM binary representation in almost real time.
The part that will bite you when you add the address tracking: the length prefix is itself LEB128. Each function body in the code section is
size:u32followed by the body, so the moment a body crosses 127 -> 128 bytes the prefix widens from 1 byte to 2, and every function after it shifts by one - the offset next to function 3 changes even though the edit was in function 1. The local-declaration counts inside the body do the same thing.So an offset column can't be a running sum over the visible lines; it has to be recomputed from the encoded bytes of the whole module on each keystroke, or it quietly lies after the first carry. Colouring the size fields and the immediates separately is worth doing for exactly that reason - they are the two places where source position and byte position stop being one-to-one.
Data addresses are the forgiving case: those come from data segment offsets, so growing the code section leaves them alone. Only code offsets churn.
The forward/backward stepper is a useful teaching affordance because it lets a learner test a single control-flow assumption instead of treating the compiled module as opaque. For the
BRIF 1example, a compact trace that shows stack values, the chosen branch, and the instruction address before and after the step would make the debugger’s contract easier to evaluate without requiring the reader to infer it from the bytes.Having the bytes stay beside the instruction makes this much easier for me to reason about. I’m curious about the boundary of BACK when a module calls an imported function with an external effect. Does the debugger stop at that boundary, record enough to replay a result, or currently keep the examples inside the local VM state? Making that limit visible would be a useful part of the teaching model too.
Ngl, this is pretty cool! I've been diving deep into WASM for a while now and the idea is awesome, makes me think of the old Commodore 64 era cartridges (before my time, but my mom had an old 1 that was in a box at my grandma's house), simply slot it into a new pc and it just works. But everyone looks at it as a 'final destination' for code, never as a destination that needs a new road? I mean why write it in python if it ends up in WASM, as opposed to a language written specifically for WASM (yes, ok Rust exists, but it's not the same). I'm currently (or well my AI agent I set to the task is) working on a standalone OS, built specifically for 1 single purpose... To run WASM and to scale across multiple nodes (so it can run on a datacenter as a unified OS). It's gunna take a LOOOONG time, but I've got time... Not enough patience to wait for it, but that's fine, it's why I have a bunch of other projects to keep me busy 😂
Feel free to test this language maybe worth to use it. Even contribute it.
Will do, though atm a bit busy, I'll bookmark for now and get back to it! For now, I'm fixated on my latest experiment, I wanted to make a DB-driven LLM, it cant think, but it does show incredible promise for codebase optimizations... I ingested 5 codebases and it analyzed the functions in it and suggested parity functions between the codebases that are more effective (better error handling, more performant, simplicity, etc.), so gunna dive into that first a bit more, so I can see if I can get codebase translation working (eg. python to rust), I'll have a look whether I can ingest HEXAW and see how it compares, would be cool if it's more optimized than the rest!
This is such a brilliant blend of retro nostalgia and modern engineering! Escaping the WAT parenthesis jungle with a clean, Z80-inspired assembler listing is a dream for anyone who loves low-level programming.
Seeing the exact hex bytes right next to the mnemonics (00000032 : 20 00 : GET 0) is an incredible educational tool for truly understanding what's happening under the hood in WebAssembly. Massive props for shipping HEXAW and integrating time-travel debugging! 👏
Really interesting project! I like the idea of seeing the actual WASM bytes alongside readable instructions. The built-in debugger and AI mentor make HEXAW especially useful for learning how WebAssembly works under the hood.
rewind for wasm. tiny format, fun idea.
I would like to proposed as human first programming language, where any one can feel the assembly programming simplicity. When we go down to the roots.
what does human-first look like past the first assembly lesson?
Seeing EQZ / BRIF 1 / BR 0 laid out as a flat listing makes structured control flow in WASM click in a way WAT never did for me. Does the mentor get the validated stack state as context, or just the source and the error? Feeding it the actual types on the stack seems like it would stop it from suggesting code that wouldn’t validate.
This is a great topic. I am put your request : improved debugging with stack to a development roadmap.