{"id":49796705,"url":"https://github.com/pirate/assembly-repl","last_synced_at":"2026-05-31T10:02:34.406Z","repository":{"id":355326280,"uuid":"1227658123","full_name":"pirate/assembly-repl","owner":"pirate","description":"A REPL for raw ASM assembly, LLVM IR, C++, C, Objective C on macOS/Linux ARM64/AMD64. Useful for learning assembly, optimizing LLMV output, debugging memory, etc.","archived":false,"fork":false,"pushed_at":"2026-05-12T08:16:00.000Z","size":1003,"stargazers_count":5,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-05-12T10:22:28.767Z","etag":null,"topics":["arm","arm64","assembly","c","c-language","clang","cpp","learning","llvm","llvm-clang","llvm-ir","macos","objective-c","repl","x64-assembly","x86-64"],"latest_commit_sha":null,"homepage":"https://www.npmjs.com/package/assembly-repl","language":"C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/pirate.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-05-03T01:35:47.000Z","updated_at":"2026-05-12T08:16:03.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/pirate/assembly-repl","commit_stats":null,"previous_names":["pirate/assembly-repl"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/pirate/assembly-repl","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pirate%2Fassembly-repl","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pirate%2Fassembly-repl/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pirate%2Fassembly-repl/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pirate%2Fassembly-repl/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/pirate","download_url":"https://codeload.github.com/pirate/assembly-repl/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pirate%2Fassembly-repl/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33726719,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-05-31T02:00:06.040Z","response_time":95,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["arm","arm64","assembly","c","c-language","clang","cpp","learning","llvm","llvm-clang","llvm-ir","macos","objective-c","repl","x64-assembly","x86-64"],"created_at":"2026-05-12T12:00:24.411Z","updated_at":"2026-05-31T10:02:34.391Z","avatar_url":"https://github.com/pirate.png","language":"C","funding_links":[],"categories":["Software Tools","C"],"sub_categories":["Debugging Tools"],"readme":"# 🧪 `assembly-repl`, \u003cbr/\u003e`llvmir-repl`, `cpp-repl`, `c-repl`, `objc-repl`, `wasm-repl`, `rust-repl`, `zig-repl`, `go-repl`\n\nA small family of low-level REPLs for learning assembly, WebAssembly, LLVM IR,\nand compiled systems languages.\n\nType assembly, run it directly on the CPU, and immediately see the register\nstate that came back. You can enter single instructions or define normal\nassembly routines with labels and indentation, then call them later with `bl`\n(arm64) or `call` (x86_64).\n\nThis is an educational toy for learning assembly, WebAssembly, LLVM IR, and\ncompiled snippets. It is not a sandbox, emulator, or production debugger. If you\nask it to crash, loop forever, corrupt memory, or jump into nonsense, it will\nprobably do exactly that. 🔥\n\n## Included REPLs ⚙️\n\n- `assembly-repl`: native assembly REPL\n- `c-repl`: C snippet REPL\n- `cpp-repl`: C++20 snippet REPL\n- `objc-repl`: Objective-C snippet REPL on macOS\n- `llvmir-repl`: LLVM IR snippet REPL\n- `wasm-repl`: WebAssembly instruction REPL\n- `rust-repl`: Rust snippet REPL\n- `zig-repl`: Zig snippet REPL\n- `go-repl`: Go snippet REPL\n\n## Requirements\n\n- `clang` at runtime for `assembly-repl`, `c-repl`, `objc-repl`, and\n  `llvmir-repl`\n- `clang++` at runtime for `cpp-repl`\n- `rustc` at runtime for `rust-repl`\n- `zig` at runtime for `zig-repl`\n- `go` at runtime for `go-repl`\n- `wasm-repl` uses Node's built-in WebAssembly runtime and does not require an\n  external Wasm toolchain\n- Objective-C snippets are supported on macOS, where Foundation and the Apple\n  Objective-C runtime are available\n\nThe npm package bundles the REPL runners, but it does not install language\nruntimes or compilers. If a required compiler is missing, the command exits with\ninstall hints for that dependency.\n\n## Install 🚀\n\nThe npm package bundles prebuilt native runners for `darwin-arm64`, `linux-x64`,\nand `linux-arm64`. Installing it does not run `node-gyp`, `make`, or a\nnative build.\n\nRun without installing globally:\n\n```sh\nnpx assembly-repl  # Run assembly-repl without a global install.\n\n# or for any of the other repls, e.g. llvmir-repl:\nnpx --package=assembly-repl llvmir-repl  # Run llvmir-repl from the same package.\nnpx --package=assembly-repl wasm-repl    # Run wasm-repl from the same package.\nnpx --package=assembly-repl rust-repl    # Run rust-repl from the same package.\nnpx --package=assembly-repl zig-repl     # Run zig-repl from the same package.\nnpx --package=assembly-repl go-repl      # Run go-repl from the same package.\n```\n\nOr install globally:\n\n```sh\nnpm i -g assembly-repl  # Install every REPL command globally.\nassembly-repl           # Start the native assembly REPL.\nc-repl                  # Start the C snippet REPL.\ncpp-repl                # Start the C++20 snippet REPL.\nobjc-repl               # Start the Objective-C snippet REPL.\nllvmir-repl             # Start the LLVM IR snippet REPL.\nwasm-repl               # Start the WebAssembly instruction REPL.\nrust-repl               # Start the Rust snippet REPL.\nzig-repl                # Start the Zig snippet REPL.\ngo-repl                 # Start the Go snippet REPL.\n```\n\nThe native runners are prebuilt, but the source-language REPLs still shell out to\ntheir compilers for the code you type. `wasm-repl` runs through Node's\nWebAssembly engine instead.\n\n## Help Lookup\n\nEvery REPL prints its `:help` text at startup. You can ask for help again or\nlook up a specific topic or instruction from the prompt:\n\n```text\n:help                         // Show the help screen for the current REPL.\n:help \u003ctopic-or-instruction\u003e  // Show focused help for one topic or instruction.\n:instructions                 // List all available instructions.\n```\n\nYou can also add `?` after an instruction or topic:\n\n```text\nasm\u003e mov?                 // Show help for the ARM64 or x86_64 move instruction.\nasm\u003e ldr?                 // Show help for ARM64 load-register forms.\nasm\u003e add x0, x0, #1?      // Show help for the instruction at the start of the line.\nc\u003e state?                 // Show help for the persistent C REPL state.\ncpp\u003e template?            // Show help for reusable C++ template definitions.\nobjc\u003e message?            // Show help for Objective-C message sends.\nir\u003e getelementptr?        // Show help for the LLVM IR pointer instruction.\nwasm\u003e i64.add?            // Show help for a WebAssembly numeric instruction.\nrust\u003e unsafe?             // Show help for unsafe Rust and external calls.\nzig\u003e extern?              // Show help for Zig external calls.\ngo\u003e syscall?              // Show help for Go syscall examples.\n```\n\nFor C, C++, Objective-C, LLVM IR, Rust, Zig, and Go, top-level definitions can\nbe pasted directly. `go-repl` also accepts normal `package` and `import`\ndeclarations. `:def ... :end` is only an explicit fallback when you want to force\ndefinition mode.\n\n## `assembly-repl`\n\n- Assembles each executable input with `clang`\n- Extracts the generated machine code from the object file\n  (Mach-O `__TEXT,__text` on macOS, ELF `.text` on Linux)\n- Maps the bytes into executable memory\n- Calls the code inside the REPL process\n- Persists general-purpose registers between lines\n- Persists labels, directives, and routines between executions\n- Prints registers and arithmetic flags after each instruction\n\n`assembly-repl` exposes a writable scratch page in a callee-saved register so you\ncan use it like a tiny heap. The register depends on the architecture:\n\n| arch   | scratch ptr | scratch size | syntax              |\n|--------|-------------|--------------|---------------------|\n| arm64  | `x19`       | `x20`        | ARM64               |\n| x86_64 | `r15`       | `r14`        | Intel, no prefixes  |\n\nAssembly examples below use ARM64 syntax unless the heading explicitly says `x86_64`.\n\n### `assembly-repl`: Quickstart\n\n```bash\nnpm i -g assembly-repl  # Install the package globally.\nassembly-repl           # Start the assembly REPL.\n\nasm\u003e :help              // Show commands, compiler path, and instruction help syntax.\nasm\u003e mov x0, #41        // Put 41 into x0.\nx0  0x0000000000000029  ...\n\nasm\u003e add x0, x0, #1     // Add 1 to x0.\nx0  0x000000000000002a  ...\n\nasm\u003e cmp x0, #42        // Compare x0 with 42 and update NZCV flags.\nnzcv 0x0000000060000000 [nZCv]\n```\n\nAt startup, the REPL also prints the selected compiler path, scratch register,\ncommands, and instruction help syntax.\n\n### `assembly-repl`: Examples\n\n\u003cdetails\u003e\u003csummary\u003e\u003ch4\u003e\u003ccode\u003eassembly-repl\u003c/code\u003e: Basics\u003c/h4\u003e\u003c/summary\u003e\n\nRegisters persist between lines:\n\n```text\nasm\u003e mov x0, #10        // Put 10 into x0.\nasm\u003e mov x1, #32        // Put 32 into x1.\nasm\u003e add x2, x0, x1     // Add x0 and x1, storing 42 in x2.\n```\n\nAfter the final line, `x2` contains `42`.\n\nYou can also inspect flags directly:\n\n```text\nasm\u003e cmp x0, #42        // Compare x0 with 42 and update NZCV.\nnzcv 0x0000000060000000 [nZCv]\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\u003csummary\u003e\u003ch4\u003e\u003ccode\u003eassembly-repl\u003c/code\u003e: Making a System Call\u003c/h4\u003e\u003c/summary\u003e\n\nThe raw syscall instruction and registers depend on the OS and architecture.\nThese examples call `getpid` and leave the pid in the normal return register.\n\nARM64 macOS:\n\n```asm\nmovz x16, #20                 // Load the Darwin getpid syscall number low bits.\nmovk x16, #0x200, lsl #16     // Add the Unix syscall class bits.\nsvc #0x80                     // Enter the kernel; pid returns in x0.\n```\n\nARM64 Linux:\n\n```asm\nmov x8, #172                  // Load the Linux arm64 getpid syscall number.\nsvc #0                        // Enter the kernel; pid returns in x0.\n```\n\nx86_64 Linux:\n\n```asm\nmov rax, 39                   // Load the Linux x86_64 getpid syscall number.\nsyscall                       // Enter the kernel; pid returns in rax.\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\u003csummary\u003e\u003ch4\u003e\u003ccode\u003eassembly-repl\u003c/code\u003e: Defining a Reusable Routine\u003c/h4\u003e\u003c/summary\u003e\n\nDirectives at column 0 are persisted immediately. Labels at column 0 start\npersistent definition blocks. Indented lines belong to the current block. When\nyou outdent, the block is committed and future input can call it.\n\n```text\nasm\u003e _double:                 // Start a persisted routine named _double.\nasm|   add x0, x0, x0         // Double the argument in x0.\nasm|   ret                    // Return to the generated REPL wrapper.\nasm| mov x0, #21              // Outdent to commit the block, then put 21 in x0.\ndefinition block committed\nx0  0x0000000000000015  ...\n\nasm\u003e bl _double               // Call the persisted routine.\nx0  0x000000000000002a  ...\n```\n\nThat is normal assembly shape: label at column 0, body indented, `ret` to return\nto the generated REPL wrapper.\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\u003csummary\u003e\u003ch4\u003e\u003ccode\u003eassembly-repl\u003c/code\u003e: Full Calculator\u003c/h4\u003e\u003c/summary\u003e\n\nThis computes:\n\n```text\n(7 + 35) * 2 = 84\n```\n\nPaste this into `assembly-repl`:\n\n```asm\ncalc_add:                     // x0 = x0 + x1.\n  add x0, x0, x1              // Add the two input registers.\n  ret                         // Return with the sum in x0.\n\ncalc_mul:                     // x0 = x0 * x1.\n  mul x0, x0, x1              // Multiply the two input registers.\n  ret                         // Return with the product in x0.\n\ncalculator_demo:              // Compute (7 + 35) * 2.\n  stp x29, x30, [sp, #-16]!   // Save frame pointer and link register.\n  mov x29, sp                 // Establish a frame pointer.\n  mov x0, #7                  // First add input.\n  mov x1, #35                 // Second add input.\n  bl calc_add                 // x0 becomes 42.\n  mov x1, #2                  // Set the multiply input.\n  bl calc_mul                 // x0 becomes 84.\n  ldp x29, x30, [sp], #16     // Restore frame pointer and link register.\n  ret                         // Return to the caller.\n\nbl calculator_demo            // Run the calculator demo.\n```\n\nThe result is left in `x0` as `0x54`, decimal `84`.\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\u003csummary\u003e\u003ch4\u003e\u003ccode\u003eassembly-repl\u003c/code\u003e: ARM64 To x86_64 Cheat Sheet 🧷\u003c/h4\u003e\u003c/summary\u003e\n\nThis section is only for `assembly-repl` on x86_64. The REPL uses Intel syntax\nwithout `%` register prefixes.\n\n| concept                | arm64                             | x86_64 (Intel syntax)            |\n|------------------------|-----------------------------------|----------------------------------|\n| immediate move         | `mov x0, #41`                     | `mov rax, 41`                    |\n| add                    | `add x0, x0, #1`                  | `add rax, 1`                     |\n| compare                | `cmp x0, #42`                     | `cmp rax, 42`                    |\n| store / load (scratch) | `str x0, [x19]` / `ldr x1, [x19]` | `mov [r15], rax` / `mov rcx, [r15]` |\n| call routine           | `bl square`                       | `call square`                    |\n| return                 | `ret`                             | `ret`                            |\n| flags shown            | `NZCV`                            | `OSZAPC`                         |\n| scratch ptr / size     | `x19` / `x20`                     | `r15` / `r14`                    |\n\nTwo short x86_64 examples — register persistence and a routine call:\n\n```text\nasm\u003e mov rax, 10         // Put 10 into rax.\nasm\u003e mov rcx, 32         // Put 32 into rcx.\nasm\u003e add rax, rcx        // Add rcx into rax, leaving 42 in rax.\n\nasm\u003e square:             // Start a persisted routine named square.\nasm|   imul rdi, rdi     // Square the input argument in rdi.\nasm|   mov rax, rdi      // Move the return value into rax.\nasm|   ret               // Return to the generated REPL wrapper.\nasm\u003e mov rdi, 12         // Put the argument 12 in rdi.\nasm\u003e call square         // Call square, leaving 144 in rax.\n```\n\nFor a complete x86_64 demo see *`assembly-repl`: x86_64 Linux Syscalls* below,\nincluding a working real-time scheduling switch.\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\u003csummary\u003e\u003ch4\u003e\u003ccode\u003eassembly-repl\u003c/code\u003e: ARM64 Registers 🧠\u003c/h4\u003e\u003c/summary\u003e\n\nRegisters persist between lines:\n\n```text\nasm\u003e mov x0, #10        // Put 10 into x0.\nasm\u003e mov x1, #32        // Put 32 into x1.\nasm\u003e add x2, x0, x1     // Add x0 and x1, storing 42 in x2.\n```\n\nAfter the final line, `x2` contains `42`.\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\u003csummary\u003e\u003ch4\u003e\u003ccode\u003eassembly-repl\u003c/code\u003e: ARM64 Scratch Memory 🧰\u003c/h4\u003e\u003c/summary\u003e\n\n`x19` points at a writable scratch page:\n\n```text\nasm\u003e mov x0, #123       // Put 123 into x0.\nasm\u003e str x0, [x19]      // Store x0 at the start of scratch memory.\nasm\u003e ldr x1, [x19]      // Load that scratch value into x1.\n```\n\nAfter the final line, `x1` contains `123`.\n\nYou can use offsets too:\n\n```text\nasm\u003e mov x0, #7         // Put 7 into x0.\nasm\u003e str x0, [x19, #8]  // Store x0 eight bytes into scratch memory.\nasm\u003e ldr x2, [x19, #8]  // Load that offset value into x2.\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\u003csummary\u003e\u003ch4\u003e\u003ccode\u003eassembly-repl\u003c/code\u003e: ARM64 Flags Explorer 🚩\u003c/h4\u003e\u003c/summary\u003e\n\nUse `cmp`, `adds`, and `subs` to watch the `NZCV` flags change.\n\n```asm\nmov x0, #-1             // Put -1 into x0.\nadds x0, x0, #1         // Add 1 and update NZCV flags.\n```\n\n`adds` writes the arithmetic result to `x0` and updates flags. After adding\n`-1 + 1`, `x0` is zero and the `Z` flag is set.\n\n```asm\nmov x0, #5              // Put 5 into x0.\nsubs x1, x0, #10        // Subtract 10, store -5 in x1, and update flags.\n```\n\nThis leaves a negative result in `x1`, so the `N` flag is set.\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\u003csummary\u003e\u003ch4\u003e\u003ccode\u003eassembly-repl\u003c/code\u003e: ARM64 Calling Convention Lab 🧠\u003c/h4\u003e\u003c/summary\u003e\n\nApple ARM64 passes the first integer arguments in `x0`, `x1`, `x2`, and so on.\nReturn values come back in `x0`.\n\n```asm\nsquare:                 // Define a routine that squares x0.\n  mul x0, x0, x0        // Multiply x0 by itself.\n  ret                   // Return with the result in x0.\n\nmov x0, #12             // Put the argument 12 in x0.\nbl square               // Call square.\n```\n\nAfter the call, `x0` contains `144`.\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\u003csummary\u003e\u003ch4\u003e\u003ccode\u003eassembly-repl\u003c/code\u003e: ARM64 Manual Stack Frames 🧱\u003c/h4\u003e\u003c/summary\u003e\n\nThis routine uses a conventional frame pointer and return-address save/restore.\n\n```asm\nincrement_with_frame:        // Define a routine that increments x0.\n  stp x29, x30, [sp, #-16]!  // Save frame pointer and link register.\n  mov x29, sp                // Establish a frame pointer.\n  add x0, x0, #1             // Increment x0.\n  ldp x29, x30, [sp], #16    // Restore frame pointer and link register.\n  ret                        // Return with the incremented value.\n\nmov x0, #41                  // Put the argument 41 in x0.\nbl increment_with_frame      // Call the routine.\n```\n\nWatch `sp`, `x29`, and `x30` in the register dump to see the call machinery.\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\u003csummary\u003e\u003ch4\u003e\u003ccode\u003eassembly-repl\u003c/code\u003e: ARM64 Pointer Arithmetic With Live Memory 🧰\u003c/h4\u003e\u003c/summary\u003e\n\n`x19` points at a writable scratch page. Use it like a tiny heap.\n\n```asm\nmov x0, #10             // Put 10 into x0.\nstr x0, [x19]           // Store 10 at scratch[0].\nmov x0, #20             // Put 20 into x0.\nstr x0, [x19, #8]       // Store 20 at scratch[8].\nldr x1, [x19]           // Load scratch[0] into x1.\nldr x2, [x19, #8]       // Load scratch[8] into x2.\nadd x3, x1, x2          // Add both loaded values into x3.\n```\n\nAfter the final line, `x3` contains `30`.\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\u003csummary\u003e\u003ch4\u003e\u003ccode\u003eassembly-repl\u003c/code\u003e: ARM64 Tiny Virtual Machine 🎛️\u003c/h4\u003e\u003c/summary\u003e\n\nStore a tiny instruction stream in scratch memory, then interpret it with native\nassembly.\n\nThis toy bytecode format uses pairs of 64-bit words:\n\n- opcode `1`: add immediate\n- opcode `2`: multiply immediate\n- opcode `0`: halt\n\n```asm\nrun_tiny_vm:            // Interpret opcode/value pairs from scratch memory.\n  mov x1, x19           // Point x1 at the scratch bytecode stream.\n  mov x0, #0            // Start the accumulator at 0.\nvm_loop:                // Begin the interpreter loop.\n  ldr x2, [x1], #8      // Load the next opcode and advance the stream.\n  cbz x2, vm_done       // Opcode 0 halts.\n  ldr x3, [x1], #8      // Load the opcode operand.\n  cmp x2, #1            // Check for add-immediate.\n  b.eq vm_add           // Branch to add handler.\n  cmp x2, #2            // Check for multiply-immediate.\n  b.eq vm_mul           // Branch to multiply handler.\n  b vm_done             // Unknown opcode halts.\nvm_add:                 // Add handler.\n  add x0, x0, x3        // Add operand into accumulator.\n  b vm_loop             // Continue interpreting.\nvm_mul:                 // Multiply handler.\n  mul x0, x0, x3        // Multiply accumulator by operand.\n  b vm_loop             // Continue interpreting.\nvm_done:                // Halt handler.\n  ret                   // Return with accumulator in x0.\n\nmov x0, #1              // Write opcode 1: add.\nstr x0, [x19]           // Store opcode at scratch[0].\nmov x0, #7              // Write operand 7.\nstr x0, [x19, #8]       // Store operand at scratch[8].\nmov x0, #1              // Write opcode 1: add.\nstr x0, [x19, #16]      // Store opcode at scratch[16].\nmov x0, #35             // Write operand 35.\nstr x0, [x19, #24]      // Store operand at scratch[24].\nmov x0, #2              // Write opcode 2: multiply.\nstr x0, [x19, #32]      // Store opcode at scratch[32].\nmov x0, #2              // Write operand 2.\nstr x0, [x19, #40]      // Store operand at scratch[40].\nmov x0, #0              // Write opcode 0: halt.\nstr x0, [x19, #48]      // Store halt opcode at scratch[48].\nbl run_tiny_vm          // Run the interpreter.\n```\n\nThe bytecode computes `(0 + 7 + 35) * 2`, so `x0` ends as `84`.\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\u003csummary\u003e\u003ch4\u003e\u003ccode\u003eassembly-repl\u003c/code\u003e: ARM64 Recursive Assembly 🌀\u003c/h4\u003e\u003c/summary\u003e\n\nRecursion works as long as you preserve the link register and any values you\nneed after recursive calls.\n\n```asm\nfactorial:                    // Define recursive factorial(x0).\n  stp x29, x30, [sp, #-32]!   // Save frame pointer and link register.\n  mov x29, sp                 // Establish a frame pointer.\n  str x0, [sp, #16]           // Save the current n.\n  cmp x0, #1                  // Check whether n \u003c= 1.\n  b.le factorial_base         // Use the base case for n \u003c= 1.\n  sub x0, x0, #1              // Prepare n - 1 for the recursive call.\n  bl factorial                // Compute factorial(n - 1).\n  ldr x1, [sp, #16]           // Reload n.\n  mul x0, x0, x1              // Multiply factorial(n - 1) by n.\n  b factorial_done            // Skip the base-case assignment.\nfactorial_base:               // Base case.\n  mov x0, #1                  // Return 1.\nfactorial_done:               // Shared function epilogue.\n  ldp x29, x30, [sp], #32     // Restore frame pointer and link register.\n  ret                         // Return with factorial result in x0.\n\nmov x0, #5                    // Put the input 5 in x0.\nbl factorial                  // Compute factorial(5).\n```\n\nAfter the call, `x0` contains `120`.\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\u003csummary\u003e\u003ch4\u003e\u003ccode\u003eassembly-repl\u003c/code\u003e: ARM64 Conditional Branches 🛣️\u003c/h4\u003e\u003c/summary\u003e\n\nBuild small control-flow routines and call them with different inputs.\n\n```asm\nmax:                    // Define max(x0, x1).\n  cmp x0, x1            // Compare the two inputs.\n  b.ge max_done         // Keep x0 when it is already \u003e= x1.\n  mov x0, x1            // Otherwise copy x1 into the return register.\nmax_done:               // Shared return point.\n  ret                   // Return with the larger value in x0.\n\nmov x0, #17             // First input.\nmov x1, #42             // Second input.\nbl max                  // Compute the larger value.\n```\n\nAfter the call, `x0` contains the larger value.\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\u003csummary\u003e\u003ch4\u003e\u003ccode\u003eassembly-repl\u003c/code\u003e: ARM64 Self-Contained Function Library 📚\u003c/h4\u003e\u003c/summary\u003e\n\nUse the REPL like a live assembly notebook. Define a few reusable routines, then\ncompose them interactively.\n\n```asm\nadd3:                   // Define add3(x0, x1, x2).\n  add x0, x0, x1        // Add x1 into x0.\n  add x0, x0, x2        // Add x2 into x0.\n  ret                   // Return with the sum in x0.\n\nclamp_min:              // Define clamp_min(value=x0, minimum=x1).\n  cmp x0, x1            // Compare value with minimum.\n  b.ge clamp_min_done   // Keep value if it is already high enough.\n  mov x0, x1            // Otherwise return the minimum.\nclamp_min_done:         // Shared return point.\n  ret                   // Return with the clamped value in x0.\n\nmov x0, #5              // First add input.\nmov x1, #10             // Second add input.\nmov x2, #20             // Third add input.\nbl add3                 // x0 becomes 35.\nmov x1, #40             // Set the minimum to 40.\nbl clamp_min            // Raise x0 to 40.\n```\n\n`add3` produces `35`; `clamp_min` then raises that to `40`.\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\u003csummary\u003e\u003ch4\u003e\u003ccode\u003eassembly-repl\u003c/code\u003e: ARM64 Instruction Equivalence ⚖️\u003c/h4\u003e\u003c/summary\u003e\n\nSome instructions produce the same register result but differ in side effects.\n\n```asm\nmov x0, #41             // Put 41 into x0.\nadd x0, x0, #1          // Add 1 without updating NZCV.\n```\n\nNow reset and try the flag-setting form:\n\n```asm\n:reset                  // Reset registers and flags.\nmov x0, #41             // Put 41 into x0 again.\nadds x0, x0, #1         // Add 1 and update NZCV.\n```\n\nBoth versions leave `x0` as `42`, but only `adds` updates `NZCV`.\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\u003csummary\u003e\u003ch4\u003e\u003ccode\u003eassembly-repl\u003c/code\u003e: ARM64 macOS Syscalls 🧬\u003c/h4\u003e\u003c/summary\u003e\n\nOn macOS ARM64, a Unix syscall uses this basic convention:\n\n- `x0`, `x1`, `x2`, ... hold arguments\n- `x16` holds the syscall number\n- Unix syscall numbers are encoded as `0x2000000 | SYS_number`\n- `svc #0x80` enters the kernel\n- `x0` receives the return value\n- on error, carry is set and `x0` contains `errno`\n\nThe examples below use `movz` + `movk` to build syscall numbers like\n`0x2000005`, because those constants are too large for a single `mov` immediate.\n\n#### open\n\nThis calls `open(path, O_WRONLY | O_CREAT | O_TRUNC, 0644)`. The returned file\ndescriptor is left in `x0`.\n\n```asm\nopen_demo:                         // Define a routine that calls open(...).\n  adr x0, open_path                // x0 points at the path string.\n  mov x1, #0x601                   // x1 = O_WRONLY | O_CREAT | O_TRUNC.\n  mov x2, #420                     // x2 = 0644 file mode.\n  movz x16, #5                     // Load SYS_open low bits.\n  movk x16, #0x200, lsl #16        // Add Darwin Unix syscall class bits.\n  svc #0x80                        // Enter the kernel.\n  ret                              // Return with fd or errno in x0.\n\nopen_path:                         // Store the file path beside the code.\n  .asciz \".asmrepl-open-demo.txt\"   // Null-terminated path string.\n\nbl open_demo                       // Call the open demo.\n```\n\nThe flags are `O_WRONLY` (`0x1`), `O_CREAT` (`0x200`), and `O_TRUNC` (`0x400`).\n\n#### mmap\n\nThis calls `mmap(NULL, 4096, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON,\n-1, 0)`, writes `42` into the returned mapping, and loads it back into `x2`.\n\n```asm\nmmap_demo:                    // Define a routine that calls mmap(...).\n  mov x0, #0                  // addr = NULL.\n  mov x1, #4096               // length = 4096.\n  mov x2, #3                  // prot = PROT_READ | PROT_WRITE.\n  mov x3, #0x1002             // flags = MAP_PRIVATE | MAP_ANON.\n  mov x4, #-1                 // fd = -1.\n  mov x5, #0                  // offset = 0.\n  movz x16, #197              // Load SYS_mmap low bits.\n  movk x16, #0x200, lsl #16   // Add Darwin Unix syscall class bits.\n  svc #0x80                   // Enter the kernel.\n  mov x21, x0                 // Save the mapped address.\n  mov x1, #42                 // Prepare a test value.\n  str x1, [x21]               // Store 42 into the mapping.\n  ldr x2, [x21]               // Load the value back into x2.\n  ret                         // Return to the REPL wrapper.\n\nbl mmap_demo                  // Call the mmap demo.\n```\n\nAfter the call, `x21` contains the mapped address and `x2` contains `42`.\n\n#### fork\n\nThis calls `fork()`. On Darwin, the parent returns with the child pid in `x0`\nand `x1 = 0`; the child returns with `x1 = 1`. The child immediately calls\n`exit(0)` so it does not become a second REPL reading from the same terminal.\n\n```asm\nfork_demo:                    // Define a routine that calls fork().\n  movz x16, #2                // Load SYS_fork low bits.\n  movk x16, #0x200, lsl #16   // Add Darwin Unix syscall class bits.\n  svc #0x80                   // Enter the kernel.\n  cbnz x1, fork_child         // Child returns with x1 = 1.\n  ret                         // Parent returns to the REPL.\n\nfork_child:                   // Child-process path.\n  mov x0, #0                  // Exit status 0.\n  movz x16, #1                // Load SYS_exit low bits.\n  movk x16, #0x200, lsl #16   // Add Darwin Unix syscall class bits.\n  svc #0x80                   // Terminate the child process.\n  ret                         // Unreached unless exit fails.\n\nbl fork_demo                  // Call the fork demo.\n```\n\n#### exit\n\nThis terminates the REPL process with exit status `42`.\n\n```asm\nexit_demo:                    // Define a routine that calls exit(42).\n  mov x0, #42                 // Exit status.\n  movz x16, #1                // Load SYS_exit low bits.\n  movk x16, #0x200, lsl #16   // Add Darwin Unix syscall class bits.\n  svc #0x80                   // Terminate the process.\n  ret                         // Unreached unless exit fails.\n\nbl exit_demo                  // Call exit_demo; this ends the REPL.\n```\n\nRun this one last. It does exactly what it says.\n\n#### execve\n\nThis calls `execve(\"/bin/bash\", argv, NULL)` and replaces the REPL process with\nBash. The `argv` array is built in scratch memory at `x19`.\n\n```asm\nexec_bash_demo:                         // Define a routine that calls execve(...).\n  adr x0, bash_path                     // x0 points at \"/bin/bash\".\n\n  adr x3, bash_path                     // Load argv[0] address.\n  str x3, [x19]                         // Store argv[0] in scratch.\n  adr x3, bash_arg_c                    // Load argv[1] address.\n  str x3, [x19, #8]                     // Store argv[1] in scratch.\n  adr x3, bash_script                   // Load argv[2] address.\n  str x3, [x19, #16]                    // Store argv[2] in scratch.\n  str xzr, [x19, #24]                   // Store the terminating NULL pointer.\n\n  mov x1, x19                           // x1 points at argv.\n  mov x2, #0                            // x2 = envp NULL.\n  movz x16, #59                         // Load SYS_execve low bits.\n  movk x16, #0x200, lsl #16             // Add Darwin Unix syscall class bits.\n  svc #0x80                             // Replace this process with bash.\n  ret                                   // Unreached unless execve fails.\n\nbash_path:                              // Store argv[0] string.\n  .asciz \"/bin/bash\"                    // Null-terminated bash path.\n\nbash_arg_c:                             // Store argv[1] string.\n  .asciz \"-c\"                           // Ask bash to run a command string.\n\nbash_script:                            // Store argv[2] string.\n  .asciz \"echo hello from assembly exec; uname -m\"  // Command run by bash.\n\nbl exec_bash_demo                       // Call execve; this replaces the REPL.\n```\n\nExpected output:\n\n```text\nhello from assembly exec\narm64\n```\n\nLike `exit`, this replaces the REPL process. Run it last.\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\u003csummary\u003e\u003ch4\u003e\u003ccode\u003eassembly-repl\u003c/code\u003e: x86_64 Linux Syscalls 🐧\u003c/h4\u003e\u003c/summary\u003e\n\nOn Linux x86_64 the syscall convention is:\n\n- `rax` holds the syscall number\n- `rdi`, `rsi`, `rdx`, `r10`, `r8`, `r9` hold the first six arguments\n- `syscall` enters the kernel\n- `rax` receives the return value (negative `errno` on error)\n- `rcx` and `r11` are clobbered (the kernel uses them for return state)\n\nA quick `getpid` looks like this:\n\n```asm\nmov rax, 39                   // Load the Linux x86_64 getpid syscall number.\nsyscall                       // Enter the kernel; pid returns in rax.\n```\n\nAfter the call, `rax` contains the REPL's pid.\n\n#### Real-time scheduling: SCHED_FIFO\n\nLinux lets you switch a process to real-time scheduling with one syscall:\n`sched_setscheduler(pid, policy, \u0026param)` (syscall `144`). With `policy =\nSCHED_FIFO (1)` and a non-zero priority, the task runs ahead of every normal\n`SCHED_OTHER` task on its CPU and is never preempted by them.\n\nThis is the same mechanism JACK, PipeWire, and other audio stacks use to keep\ntheir callback threads from being interrupted by the rest of the system.\n\nSharp edge: a real-time `SCHED_FIFO` task with a tight `while (1)` and no\n`sched_yield` can starve normal tasks on its CPU and make the system feel\nfrozen. Linux's RT bandwidth throttle (see `/proc/sys/kernel/sched_rt_*`)\nlimits this to ~95% of CPU time per second by default, but it is still rude.\nRequires `CAP_SYS_NICE` (or root).\n\n```asm\nmov rax, 50       // Use priority 50 for struct sched_param.sched_priority.\nmov [r15], rax    // Store the priority at the start of scratch memory.\n\nmov rdi, 0        // pid = 0 means the current process.\nmov rsi, 1        // policy = SCHED_FIFO.\nmov rdx, r15      // param points at scratch memory.\nmov rax, 144      // syscall number = sched_setscheduler.\nsyscall           // Enter the kernel.\n```\n\n`rax` should be `0`. A non-zero negative value (e.g. `-1` = `-EPERM`) means\nthe process lacked `CAP_SYS_NICE`.\n\nRead it back with `sched_getscheduler(0)` (syscall `145`):\n\n```asm\nmov rdi, 0        // pid = 0 means the current process.\nmov rax, 145      // syscall number = sched_getscheduler.\nsyscall           // Enter the kernel; policy returns in rax.\n```\n\n`rax` is now `1`, which is `SCHED_FIFO`. From outside the REPL you can confirm\nwith `chrt -p \u003cpid\u003e`:\n\n```text\npid 9228's current scheduling policy: SCHED_FIFO\npid 9228's current scheduling priority: 50\n```\n\nTo go back to normal scheduling, repeat the call with `policy = 0`\n(`SCHED_OTHER`) and `priority = 0`.\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\u003csummary\u003e\u003ch4\u003e\u003ccode\u003eassembly-repl\u003c/code\u003e: Crash-As-A-Lesson Mode 💥\u003c/h4\u003e\u003c/summary\u003e\n\nThis REPL is intentionally unsafe. You can use that to learn why valid memory,\nbalanced stack changes, and correct return addresses matter.\n\nThis may crash the REPL:\n\n```asm\nmov x0, #0        // Put a null pointer in x0.\nldr x1, [x0]      // Try to read through it, usually crashing.\n```\n\nSo can this:\n\n```asm\nsub sp, sp, #16   // Move the stack pointer without restoring it.\n```\n\nThose failures are useful when you want to see what bad assembly does to a real\nprocess instead of an emulator.\n\n\u003c/details\u003e\n\n### `assembly-repl`: Reference\n\n#### `assembly-repl`: Commands 🕹️\n\n- `:help` shows commands and notes\n- `:help \u003cinstruction\u003e` shows built-in help for an instruction\n- `:instructions` lists instruction help topics for the current architecture\n- `:regs` prints the current register context\n- `:reset` zeroes registers and restores scratch pointers\n- `:scratch` prints the scratch memory address and size\n- `:defs` prints persisted labels, directives, and routines\n- `:clear` clears persisted labels, directives, and routines\n- `:quit` exits\n\nYou can also add `?` after an instruction mnemonic to show help without\nexecuting anything:\n\n```text\nasm\u003e mov?                 // Show help for move instructions.\nasm\u003e ldr?                 // Show help for ARM64 loads.\nasm\u003e add x0, x0, #1?      // Show help for the instruction at the start of the line.\n```\n\nShort aliases:\n\n- `:h` for `:help`\n- `:inst` or `:i` for `:instructions`\n- `:r` for `:regs`\n- `:q` for `:quit`\n\n#### `assembly-repl`: Sharp Edges ⚠️\n\nThis program runs native instructions in the current process.\n\nThings that may crash or hang the REPL:\n\n- Unbalanced changes to `sp`\n- Branching away from the generated wrapper\n- Calling arbitrary addresses\n- Infinite loops\n- Invalid loads or stores\n- Trap instructions\n- Overwriting process memory\n\nThat is intentional. The goal is to keep the tool small, direct, and useful for\nlearning what instructions actually do.\n\n## `llvmir-repl`\n\n`llvmir-repl` appends each non-command line to a generated LLVM IR function body,\nthen recompiles and executes the whole body. It exposes `%state`, whose type is\n`%repl_state`, so you can load, store, and compute directly in LLVM IR.\n\n### `llvmir-repl`: Quickstart\n\n```bash\nnpm i -g assembly-repl  # Install the package globally.\nllvmir-repl             # Start the LLVM IR REPL.\n\nir\u003e :help                                                       ; Show commands and LLVM IR help topics.\nir\u003e %x = add i64 40, 2                                         ; Compute 40 + 2.\nir\u003e %result = getelementptr %repl_state, ptr %state, i32 0, i32 4 ; Point at state-\u003eresult.\nir\u003e store i64 %x, ptr %result                                  ; Store 42 as the printed result.\nresult 0x000000000000002a (42)\n```\n\n### `llvmir-repl`: Examples\n\n\u003cdetails\u003e\u003csummary\u003e\u003ch4\u003e\u003ccode\u003ellvmir-repl\u003c/code\u003e: Basics\u003c/h4\u003e\u003c/summary\u003e\n\nDo inline integer arithmetic, then store into field 4 of `%repl_state` to update\nthe printed result:\n\n```text\nir\u003e %x = add i64 40, 2                                         ; Compute 40 + 2.\nir\u003e %result = getelementptr %repl_state, ptr %state, i32 0, i32 4 ; Point at state-\u003eresult.\nir\u003e store i64 %x, ptr %result                                  ; Store 42 as the printed result.\nresult 0x000000000000002a (42)\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\u003csummary\u003e\u003ch4\u003e\u003ccode\u003ellvmir-repl\u003c/code\u003e: Making a System Call\u003c/h4\u003e\u003c/summary\u003e\n\nThis calls the platform C library's `getpid` entry point, avoiding OS-specific raw\nsyscall numbers in the IR:\n\n```text\nir\u003e declare i32 @getpid()                                      ; Declare the C library getpid function.\ndefinition block committed\nir\u003e %pid32 = call i32 @getpid()                                ; Call getpid and receive an i32 pid.\nir\u003e %pid = zext i32 %pid32 to i64                              ; Widen the pid to i64.\nir\u003e %result = getelementptr %repl_state, ptr %state, i32 0, i32 4 ; Point at state-\u003eresult.\nir\u003e store i64 %pid, ptr %result                                ; Store the pid as the printed result.\nresult 0x0000000000001234 (4660)\n```\n\nThe exact process id will be different on your machine.\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\u003csummary\u003e\u003ch4\u003e\u003ccode\u003ellvmir-repl\u003c/code\u003e: Defining a Reusable Function\u003c/h4\u003e\u003c/summary\u003e\n\n```text\nir\u003e define i64 @twice(i64 %x) {                                ; Define twice(x).\nir| entry:                                                     ; Start the function entry block.\nir|   %r = mul i64 %x, 2                                       ; Multiply the argument by 2.\nir|   ret i64 %r                                               ; Return the doubled value.\nir| }                                                          ; End the function definition.\ndefinition block committed\nir\u003e %v = call i64 @twice(i64 21)                               ; Call twice(21).\nir\u003e %result = getelementptr %repl_state, ptr %state, i32 0, i32 4 ; Point at state-\u003eresult.\nir\u003e store i64 %v, ptr %result                                  ; Store 42 as the printed result.\nresult 0x000000000000002a (42)\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\u003csummary\u003e\u003ch4\u003e\u003ccode\u003ellvmir-repl\u003c/code\u003e: Full Calculator\u003c/h4\u003e\u003c/summary\u003e\n\nThis computes:\n\n```text\n(7 + 35) * 2 = 84\n```\n\n```text\nir\u003e define i64 @calc_add(i64 %a, i64 %b) {                     ; Define calc_add(a, b).\nir| entry:                                                     ; Start calc_add's entry block.\nir|   %r = add i64 %a, %b                                      ; Add the two arguments.\nir|   ret i64 %r                                               ; Return the sum.\nir| }                                                          ; End calc_add.\ndefinition block committed\nir\u003e define i64 @calc_mul(i64 %a, i64 %b) {                     ; Define calc_mul(a, b).\nir| entry:                                                     ; Start calc_mul's entry block.\nir|   %r = mul i64 %a, %b                                      ; Multiply the two arguments.\nir|   ret i64 %r                                               ; Return the product.\nir| }                                                          ; End calc_mul.\ndefinition block committed\nir\u003e %sum = call i64 @calc_add(i64 7, i64 35)                   ; Compute 7 + 35.\nir\u003e %product = call i64 @calc_mul(i64 %sum, i64 2)             ; Multiply the sum by 2.\nir\u003e %result = getelementptr %repl_state, ptr %state, i32 0, i32 4 ; Point at state-\u003eresult.\nir\u003e store i64 %product, ptr %result                            ; Store 84 as the printed result.\nresult 0x0000000000000054 (84)\n```\n\n\u003c/details\u003e\n\n### `llvmir-repl`: Reference\n\nPersistent state:\n\n```llvm\n%repl_state = type { [16 x i64], [16 x double], [4096 x i8], [4096 x i8], i64 } ; Persistent REPL state layout.\n```\n\nField 4 of `%repl_state` updates the printed result.\n\nCommands:\n\n- `:help` shows commands and execution notes\n- `:help \u003ctopic\u003e` shows built-in help for a topic\n- `:topics` lists built-in topic help\n- `:instructions` discovers LLVM IR instructions from the installed LLVM/Clang\n  toolchain and prints small generated summaries\n- `:state` prints persistent slots, result, and output\n- `:reset` resets persistent state\n- `:scratch` prints scratch memory details\n- `:defs` prints persisted definitions\n- `:def` starts an explicit persisted definition block\n- `:end` commits the explicit definition block\n- `:clear` clears definitions and LLVM IR body\n- `:source` prints the last generated IR file path\n- `:quit` exits\n\nTop-level declarations and definitions are persisted automatically. Body\ninstructions are appended to `repl_entry` and recompiled after each accepted\nline.\n\n## `c-repl`\n\n`c-repl` compiles each input as C inside:\n\n```c\nvoid repl_entry(repl_state_t *state) {  /* Generated entry point for one C snippet. */\n    /* your snippet */  /* Each c-repl line runs inside this function. */\n}  /* Returning hands control back to the REPL. */\n```\n\nUse it for C expressions, pointer experiments, small helper functions, and\nshared-library-level behavior while keeping persistent state between snippets.\n\n### `c-repl`: Quickstart\n\n```bash\nnpm i -g assembly-repl  # Install the package globally.\nc-repl                  # Start the C REPL.\n\nc\u003e :help                                      // Show commands and C help topics.\nc\u003e U(0) = 40 + 2; state-\u003eresult = U(0);       // Compute 42 and store it as the printed result.\nresult 0x000000000000002a (42)\n```\n\n### `c-repl`: Examples\n\n\u003cdetails\u003e\u003csummary\u003e\u003ch4\u003e\u003ccode\u003ec-repl\u003c/code\u003e: Basics\u003c/h4\u003e\u003c/summary\u003e\n\n```text\nc\u003e U(0) = 41;                                 // Store 41 in persistent integer slot 0.\nc\u003e U(0) += 1; state-\u003eresult = U(0);           // Increment the slot and publish the result.\nresult 0x000000000000002a (42)\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\u003csummary\u003e\u003ch4\u003e\u003ccode\u003ec-repl\u003c/code\u003e: Making a System Call\u003c/h4\u003e\u003c/summary\u003e\n\n```text\nc\u003e #include \u003cunistd.h\u003e                        // Persist the getpid declaration.\ndirective persisted\nc\u003e state-\u003eresult = (uint64_t)getpid();        // Call getpid and publish the pid.\nresult 0x0000000000001234 (4660)\n```\n\nThe exact process id will be different on your machine.\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\u003csummary\u003e\u003ch4\u003e\u003ccode\u003ec-repl\u003c/code\u003e: Defining a Reusable Function\u003c/h4\u003e\u003c/summary\u003e\n\nTop-level function definitions are persisted after the closing brace:\n\n```text\nc\u003e static uint64_t twice(uint64_t x) {        // Start a persisted helper function.\nc|   return x * 2;                            // Return double the input.\nc| }                                          // Close and commit the function.\ndefinition block committed\nc\u003e state-\u003eresult = twice(21);                 // Call the helper and publish 42.\nresult 0x000000000000002a (42)\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\u003csummary\u003e\u003ch4\u003e\u003ccode\u003ec-repl\u003c/code\u003e: Full Calculator\u003c/h4\u003e\u003c/summary\u003e\n\nThis computes:\n\n```text\n(7 + 35) * 2 = 84\n```\n\n```text\nc\u003e static uint64_t calc_add(uint64_t a, uint64_t b) {  // Start a reusable add helper.\nc|   return a + b;                                     // Return a + b.\nc| }                                                   // Close and commit calc_add.\ndefinition block committed\nc\u003e static uint64_t calc_mul(uint64_t a, uint64_t b) {  // Start a reusable multiply helper.\nc|   return a * b;                                     // Return a * b.\nc| }                                                   // Close and commit calc_mul.\ndefinition block committed\nc\u003e state-\u003eresult = calc_mul(calc_add(7, 35), 2);       // Compute (7 + 35) * 2.\nresult 0x0000000000000054 (84)\n```\n\n\u003c/details\u003e\n\n### `c-repl`: Reference\n\nPersistent state:\n\n```c\nstate-\u003eresult        /* uint64_t result value printed after each run */\nstate-\u003eu64[n]        /* 16 persistent integer slots */\nstate-\u003ef64[n]        /* 16 persistent double slots */\nstate-\u003escratch[n]    /* 4096 bytes of persistent scratch memory */\nstate-\u003eout           /* 4096-byte output buffer used by print(...) */\n```\n\nConvenience helpers:\n\n```c\nU(n), F(n), SCRATCH(n)                         /* Shorthand for persistent slots and scratch bytes. */\nprint(\"value=%llu\\n\", (unsigned long long)U(0)) /* Append formatted text to state-\u003eout. */\n```\n\nCommands:\n\n- `:help` shows commands and execution notes\n- `:help \u003ctopic\u003e` shows built-in help for a topic\n- `:topics` lists built-in topic help\n- `:instructions` lists built-in topic help\n- `:state` prints persistent slots, result, and output\n- `:reset` resets persistent state\n- `:scratch` prints scratch memory details\n- `:defs` prints persisted definitions\n- `:def` starts an explicit persisted definition block\n- `:end` commits the explicit definition block\n- `:clear` clears definitions\n- `:source` prints the last generated source file path\n- `:quit` exits\n\nMulti-line input is collected until the compiler accepts it. Top-level\ndefinitions are persisted automatically; accepted statements run inside\n`repl_entry`. Press Enter on an empty continuation line to force diagnostics.\n\n## `cpp-repl`\n\n`cpp-repl` compiles snippets as C++20 with `clang++`. Use it for templates,\nlambdas, overloads, classes, and standard C++ experiments.\n\n### `cpp-repl`: Quickstart\n\n```bash\nnpm i -g assembly-repl  # Install the package globally.\ncpp-repl                # Start the C++ REPL.\n\ncpp\u003e :help                                    // Show commands and C++ help topics.\ncpp\u003e U(0) = 40 + 2; state-\u003eresult = U(0);     // Compute 42 and store it as the printed result.\nresult 0x000000000000002a (42)\n```\n\n### `cpp-repl`: Examples\n\n\u003cdetails\u003e\u003csummary\u003e\u003ch4\u003e\u003ccode\u003ecpp-repl\u003c/code\u003e: Basics\u003c/h4\u003e\u003c/summary\u003e\n\n```text\ncpp\u003e U(0) = 40 + 2; state-\u003eresult = U(0);     // Compute 42 and publish it.\nresult 0x000000000000002a (42)\n```\n\nLocal lambdas work too:\n\n```text\ncpp\u003e auto sq = [](uint64_t x) { return x * x; }; state-\u003eresult = sq(12);  // Define a local lambda and publish 12 squared.\nresult 0x0000000000000090 (144)\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\u003csummary\u003e\u003ch4\u003e\u003ccode\u003ecpp-repl\u003c/code\u003e: Making a System Call\u003c/h4\u003e\u003c/summary\u003e\n\n```text\ncpp\u003e #include \u003cunistd.h\u003e                      // Persist the getpid declaration.\ndirective persisted\ncpp\u003e state-\u003eresult = static_cast\u003cuint64_t\u003e(::getpid());  // Call getpid and publish the pid.\nresult 0x0000000000001234 (4660)\n```\n\nThe exact process id will be different on your machine.\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\u003csummary\u003e\u003ch4\u003e\u003ccode\u003ecpp-repl\u003c/code\u003e: Defining a Reusable Function\u003c/h4\u003e\u003c/summary\u003e\n\nTop-level definitions work the same way:\n\n```text\ncpp\u003e template \u003ctypename T\u003e                    // Start a reusable template definition.\ncpp| T triple(T x) {                          // Define triple(x).\ncpp|   return x * 3;                          // Return three times the input.\ncpp| }                                        // Close and commit the template.\ndefinition block committed\ncpp\u003e state-\u003eresult = triple\u003cuint64_t\u003e(14);    // Instantiate the template and publish 42.\nresult 0x000000000000002a (42)\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\u003csummary\u003e\u003ch4\u003e\u003ccode\u003ecpp-repl\u003c/code\u003e: Full Calculator\u003c/h4\u003e\u003c/summary\u003e\n\nThis computes:\n\n```text\n(7 + 35) * 2 = 84\n```\n\n```text\ncpp\u003e static uint64_t calc_add(uint64_t a, uint64_t b) {  // Start a reusable add helper.\ncpp|   return a + b;                                     // Return a + b.\ncpp| }                                                   // Close and commit calc_add.\ndefinition block committed\ncpp\u003e static uint64_t calc_mul(uint64_t a, uint64_t b) {  // Start a reusable multiply helper.\ncpp|   return a * b;                                     // Return a * b.\ncpp| }                                                   // Close and commit calc_mul.\ndefinition block committed\ncpp\u003e auto value = calc_mul(calc_add(7, 35), 2); state-\u003eresult = value;  // Compute (7 + 35) * 2 and publish it.\nresult 0x0000000000000054 (84)\n```\n\n\u003c/details\u003e\n\n### `cpp-repl`: Reference\n\nPersistent state:\n\n```c\nstate-\u003eresult        /* uint64_t result value printed after each run */\nstate-\u003eu64[n]        /* 16 persistent integer slots */\nstate-\u003ef64[n]        /* 16 persistent double slots */\nstate-\u003escratch[n]    /* 4096 bytes of persistent scratch memory */\nstate-\u003eout           /* 4096-byte output buffer used by print(...) */\n```\n\nConvenience helpers:\n\n```c\nU(n), F(n), SCRATCH(n)                         /* Shorthand for persistent slots and scratch bytes. */\nprint(\"value=%llu\\n\", (unsigned long long)U(0)) /* Append formatted text to state-\u003eout. */\n```\n\nCommands:\n\n- `:help` shows commands and execution notes\n- `:help \u003ctopic\u003e` shows built-in help for a topic\n- `:topics` lists built-in topic help\n- `:instructions` lists built-in topic help\n- `:state` prints persistent slots, result, and output\n- `:reset` resets persistent state\n- `:scratch` prints scratch memory details\n- `:defs` prints persisted definitions\n- `:def` starts an explicit persisted definition block\n- `:end` commits the explicit definition block\n- `:clear` clears definitions\n- `:source` prints the last generated source file path\n- `:quit` exits\n\nMulti-line input is collected until the compiler accepts it. Top-level\ndefinitions are persisted automatically; accepted statements run inside\n`repl_entry`. Press Enter on an empty continuation line to force diagnostics.\n\n## `objc-repl`\n\n`objc-repl` compiles Objective-C snippets on macOS with Foundation available.\nUse it for message sends, Objective-C classes, ARC behavior, and small Cocoa or\nFoundation experiments. Foundation is imported by the generated wrapper.\n\n### `objc-repl`: Quickstart\n\n```bash\nnpm i -g assembly-repl  # Install the package globally.\nobjc-repl               # Start the Objective-C REPL.\n\nobjc\u003e :help                                   // Show commands and Objective-C help topics.\nobjc\u003e U(0) = 40 + 2; state-\u003eresult = U(0);    // Compute 42 and store it as the printed result.\nresult 0x000000000000002a (42)\n```\n\n### `objc-repl`: Examples\n\n\u003cdetails\u003e\u003csummary\u003e\u003ch4\u003e\u003ccode\u003eobjc-repl\u003c/code\u003e: Basics\u003c/h4\u003e\u003c/summary\u003e\n\n```text\nobjc\u003e U(0) = 40 + 2; state-\u003eresult = U(0);    // Compute 42 and publish it.\nresult 0x000000000000002a (42)\n```\n\nFoundation values work too:\n\n```text\nobjc\u003e NSString *s = @\"hello\"; state-\u003eresult = [s length];  // Create a string and publish its length.\nresult 0x0000000000000005 (5)\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\u003csummary\u003e\u003ch4\u003e\u003ccode\u003eobjc-repl\u003c/code\u003e: Making a System Call\u003c/h4\u003e\u003c/summary\u003e\n\n```text\nobjc\u003e #include \u003cunistd.h\u003e                     // Persist the getpid declaration.\ndirective persisted\nobjc\u003e state-\u003eresult = (uint64_t)getpid();     // Call getpid and publish the pid.\nresult 0x0000000000001234 (4660)\n```\n\nThe exact process id will be different on your machine.\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\u003csummary\u003e\u003ch4\u003e\u003ccode\u003eobjc-repl\u003c/code\u003e: Defining a Reusable Class\u003c/h4\u003e\u003c/summary\u003e\n\nYou can persist Objective-C classes by entering interface and implementation\nblocks:\n\n```text\nobjc\u003e @interface Counter : NSObject           // Start the Counter class interface.\nobjc| - (uint64_t)add:(uint64_t)a to:(uint64_t)b;  // Declare an add method.\nobjc| @end                                    // Close and commit the interface.\ndefinition block committed\nobjc\u003e @implementation Counter                 // Start the Counter implementation.\nobjc| - (uint64_t)add:(uint64_t)a to:(uint64_t)b { return a + b; }  // Implement add.\nobjc| @end                                    // Close and commit the implementation.\ndefinition block committed\nobjc\u003e Counter *c = [Counter new]; state-\u003eresult = [c add:40 to:2];  // Create a Counter and publish 42.\nresult 0x000000000000002a (42)\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\u003csummary\u003e\u003ch4\u003e\u003ccode\u003eobjc-repl\u003c/code\u003e: Full Calculator\u003c/h4\u003e\u003c/summary\u003e\n\nThis computes:\n\n```text\n(7 + 35) * 2 = 84\n```\n\n```text\nobjc\u003e @interface Calculator : NSObject        // Start the Calculator interface.\nobjc| - (uint64_t)add:(uint64_t)a to:(uint64_t)b;       // Declare add.\nobjc| - (uint64_t)multiply:(uint64_t)a by:(uint64_t)b;  // Declare multiply.\nobjc| @end                                    // Close and commit the interface.\ndefinition block committed\nobjc\u003e @implementation Calculator              // Start the Calculator implementation.\nobjc| - (uint64_t)add:(uint64_t)a to:(uint64_t)b { return a + b; }       // Implement add.\nobjc| - (uint64_t)multiply:(uint64_t)a by:(uint64_t)b { return a * b; }  // Implement multiply.\nobjc| @end                                    // Close and commit the implementation.\ndefinition block committed\nobjc\u003e Calculator *calc = [Calculator new]; state-\u003eresult = [calc multiply:[calc add:7 to:35] by:2];  // Compute (7 + 35) * 2.\nresult 0x0000000000000054 (84)\n```\n\n\u003c/details\u003e\n\n### `objc-repl`: Reference\n\nPersistent state:\n\n```c\nstate-\u003eresult        /* uint64_t result value printed after each run */\nstate-\u003eu64[n]        /* 16 persistent integer slots */\nstate-\u003ef64[n]        /* 16 persistent double slots */\nstate-\u003escratch[n]    /* 4096 bytes of persistent scratch memory */\nstate-\u003eout           /* 4096-byte output buffer used by print(...) */\n```\n\nConvenience helpers:\n\n```c\nU(n), F(n), SCRATCH(n)                         /* Shorthand for persistent slots and scratch bytes. */\nprint(\"value=%llu\\n\", (unsigned long long)U(0)) /* Append formatted text to state-\u003eout. */\n```\n\nCommands:\n\n- `:help` shows commands and execution notes\n- `:help \u003ctopic\u003e` shows built-in help for a topic\n- `:topics` lists built-in topic help\n- `:instructions` lists built-in topic help\n- `:state` prints persistent slots, result, and output\n- `:reset` resets persistent state\n- `:scratch` prints scratch memory details\n- `:defs` prints persisted definitions\n- `:def` starts an explicit persisted definition block\n- `:end` commits the explicit definition block\n- `:clear` clears definitions\n- `:source` prints the last generated source file path\n- `:quit` exits\n\nMulti-line input is collected until the compiler accepts it. Top-level\ndefinitions are persisted automatically; accepted statements run inside\n`repl_entry`. Press Enter on an empty continuation line to force diagnostics.\n\n## `wasm-repl`\n\n`wasm-repl` accepts flat WebAssembly text instructions, emits a small Wasm\nmodule in memory, and executes it through Node's built-in `WebAssembly` API.\nIt is useful for learning the Wasm operand stack, numeric instructions,\nglobals, and linear memory without installing `wat2wasm` or a separate runtime.\n\nEach accepted line is appended to a generated `repl_entry` function body. The\nwhole body is recompiled and executed after each accepted line. If the body\nleaves values on the operand stack, the REPL-generated epilogue stores the top\n`i32`/`i64` value into `$result`, stores the top `f32`/`f64` value into `$f0`,\nand drops older stack values so the generated function validates.\n\n### `wasm-repl`: Quickstart\n\n```bash\nnpm i -g assembly-repl  # Install the package globally.\nwasm-repl               # Start the WebAssembly REPL.\n\nwasm\u003e :help             ;; Show commands and WebAssembly help topics.\nwasm\u003e i64.const 40      ;; Push an i64 constant.\nresult 0x0000000000000028 (40)\nwasm\u003e i64.const 2       ;; Push another i64 constant.\nresult 0x0000000000000002 (2)\nwasm\u003e i64.add           ;; Add the two constants from the accumulated body.\nresult 0x000000000000002a (42)\n```\n\n### `wasm-repl`: Examples\n\n\u003cdetails\u003e\u003csummary\u003e\u003ch4\u003e\u003ccode\u003ewasm-repl\u003c/code\u003e: Persistent Globals\u003c/h4\u003e\u003c/summary\u003e\n\nStore a value in an imported mutable global and read it back:\n\n```text\nwasm\u003e i64.const 42\nresult 0x000000000000002a (42)\nwasm\u003e global.set $u0\nresult 0x000000000000002a (42)\nu0  0x000000000000002a\nwasm\u003e global.get $u0\nresult 0x000000000000002a (42)\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\u003csummary\u003e\u003ch4\u003e\u003ccode\u003ewasm-repl\u003c/code\u003e: Linear Memory\u003c/h4\u003e\u003c/summary\u003e\n\nUse the imported memory as scratch storage:\n\n```text\nwasm\u003e i32.const 0\nwasm\u003e i64.const 0xfeedface\nwasm\u003e i64.store\nscratch[0..31] ce fa ed fe 00 00 00 00 ...\nwasm\u003e i32.const 0\nwasm\u003e i64.load\nresult 0x00000000feedface (4277009102)\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\u003csummary\u003e\u003ch4\u003e\u003ccode\u003ewasm-repl\u003c/code\u003e: Full Calculator\u003c/h4\u003e\u003c/summary\u003e\n\nThis computes:\n\n```text\n(7 + 35) * 2 = 84\n```\n\n```text\nwasm\u003e i64.const 7\nwasm\u003e i64.const 35\nwasm\u003e i64.add\nwasm\u003e i64.const 2\nwasm\u003e i64.mul\nresult 0x0000000000000054 (84)\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\u003csummary\u003e\u003ch4\u003e\u003ccode\u003ewasm-repl\u003c/code\u003e: Host Call Timer\u003c/h4\u003e\u003c/summary\u003e\n\n`$host_time_ms` is an imported host function that returns the host wall clock as\nUnix milliseconds. This stores one timestamp in `$u0`, then computes elapsed\ntime with a second host call:\n\n```text\nwasm\u003e call $host_time_ms\nwasm\u003e global.set $u0\nu0  0x0000019ad5f1d2a0\nwasm\u003e call $host_time_ms\nwasm\u003e global.get $u0\nwasm\u003e i64.sub\nresult 0x0000000000000037 (55)\n```\n\nThe exact timestamp and elapsed millisecond value will be different on your\nmachine.\n\n\u003c/details\u003e\n\n### `wasm-repl`: Reference\n\nPersistent imports:\n\n```wat\n(import \"repl\" \"host_time_ms\" (func $host_time_ms (result i64)))\n(import \"repl\" \"memory\" (memory 1))\n(import \"repl\" \"result\" (global $result (mut i64)))\n(import \"repl\" \"u0\"     (global $u0     (mut i64)))  ;; through $u15\n(import \"repl\" \"f0\"     (global $f0     (mut f64)))  ;; through $f15\n```\n\nBuilt-in host calls:\n\n```wat\ncall $print_i64\ncall $print_i32\ncall $print_f64\ncall $host_time_ms\n```\n\nCommands:\n\n- `:help` shows commands and execution notes\n- `:help \u003ctopic-or-instruction\u003e` shows built-in help\n- `:topics` lists built-in topic help\n- `:instructions` lists supported WebAssembly instructions\n- `:state` prints persistent globals, result, scratch, and output\n- `:reset` resets persistent state\n- `:scratch` prints scratch memory details\n- `:defs` prints the current instruction block\n- `:def` starts an optional multi-line instruction block\n- `:end` commits the optional instruction block\n- `:body` prints accumulated WebAssembly instructions\n- `:clear` clears the accumulated WebAssembly body\n- `:source` prints the last generated `.wat` file path\n- `:wasm` prints the last generated `.wasm` file path\n- `:quit` exits\n\nInstruction help:\n\n```text\nwasm\u003e i64.add?          ;; Show help for one instruction.\nwasm\u003e :instructions     ;; List supported instructions.\nwasm\u003e :help memory      ;; Show memory/load/store notes.\n```\n\nEach accepted instruction line is appended and run immediately. `:def ... :end`\nis only needed when you want to batch several instructions before running them.\n\n## `rust-repl`\n\n`rust-repl` compiles snippets with `rustc` as Rust 2021 shared libraries and\nloads them into the REPL process. Each executable snippet runs inside:\n\n```rust\npub unsafe extern \"C\" fn repl_entry(state: *mut ReplState) {\n    let state = unsafe { \u0026mut *state };\n    /* your snippet */\n}\n```\n\nUse it for small Rust experiments, unsafe code, FFI calls, and helper functions\nwhile keeping persistent state between snippets.\n\n### `rust-repl`: Quickstart\n\n```bash\nnpm i -g assembly-repl  # Install the package globally.\nrust-repl               # Start the Rust REPL.\n\nrust\u003e :help                            // Show commands and Rust help topics.\nrust\u003e state.result = 40 + 2;           // Compute 42 and store it as the printed result.\nresult 0x000000000000002a (42)\n```\n\n### `rust-repl`: Examples\n\n\u003cdetails\u003e\u003csummary\u003e\u003ch4\u003e\u003ccode\u003erust-repl\u003c/code\u003e: Basics\u003c/h4\u003e\u003c/summary\u003e\n\n```text\nrust\u003e state.u64[0] = 41;               // Store 41 in persistent integer slot 0.\nrust\u003e state.u64[0] += 1; state.result = state.u64[0];  // Increment and publish the result.\nresult 0x000000000000002a (42)\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\u003csummary\u003e\u003ch4\u003e\u003ccode\u003erust-repl\u003c/code\u003e: Making a System Call\u003c/h4\u003e\u003c/summary\u003e\n\n```text\nrust\u003e unsafe extern \"C\" { fn getpid() -\u003e i32; }\ndefinition block committed\nrust\u003e state.result = unsafe { getpid() as u64 };\nresult 0x0000000000001234 (4660)\n```\n\nThe exact process id will be different on your machine.\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\u003csummary\u003e\u003ch4\u003e\u003ccode\u003erust-repl\u003c/code\u003e: Full Calculator\u003c/h4\u003e\u003c/summary\u003e\n\nThis computes:\n\n```text\n(7 + 35) * 2 = 84\n```\n\n```text\nrust\u003e fn calc_add(a: u64, b: u64) -\u003e u64 { a + b }\ndefinition block committed\nrust\u003e fn calc_mul(a: u64, b: u64) -\u003e u64 { a * b }\ndefinition block committed\nrust\u003e state.result = calc_mul(calc_add(7, 35), 2);\nresult 0x0000000000000054 (84)\n```\n\n\u003c/details\u003e\n\n### `rust-repl`: Reference\n\nPersistent state:\n\n```rust\nstate.result       /* u64 result value printed after each run */\nstate.u64[n]       /* 16 persistent integer slots */\nstate.f64[n]       /* 16 persistent f64 slots */\nstate.scratch[n]   /* 4096 bytes of persistent scratch memory */\nstate.out          /* 4096-byte output buffer used by repl_print!(...) */\n```\n\nConvenience helper:\n\n```rust\nrepl_print!(state, \"value={}\\n\", state.u64[0]);  /* Append formatted text to state.out. */\n```\n\nCommands:\n\n- `:help` shows commands and execution notes\n- `:help \u003ctopic\u003e` shows built-in help for a topic\n- `:topics` lists built-in topic help\n- `:instructions` lists built-in topic help\n- `:state` prints persistent slots, result, and output\n- `:reset` resets persistent state\n- `:scratch` prints scratch memory details\n- `:defs` prints persisted definitions\n- `:def` starts an explicit persisted definition block\n- `:end` commits the explicit definition block\n- `:clear` clears definitions\n- `:source` prints the last generated source file path\n- `:quit` exits\n\nMulti-line input is collected until `rustc` accepts it. Top-level definitions\nare persisted automatically; accepted statements run inside `repl_entry`. Press\nEnter on an empty continuation line to force diagnostics.\n\n## `zig-repl`\n\n`zig-repl` compiles snippets with `zig` as dynamic libraries and loads them into\nthe REPL process. Each executable snippet runs inside:\n\n```zig\nexport fn repl_entry(state: *ReplState) callconv(.c) void {\n    /* your snippet */\n}\n```\n\nUse it for Zig expressions, pointer experiments, C ABI calls, and small helper\nfunctions with persistent state between snippets.\n\n### `zig-repl`: Quickstart\n\n```bash\nnpm i -g assembly-repl  # Install the package globally.\nzig-repl                # Start the Zig REPL.\n\nzig\u003e :help                             // Show commands and Zig help topics.\nzig\u003e state.result = 40 + 2;            // Compute 42 and store it as the printed result.\nresult 0x000000000000002a (42)\n```\n\n### `zig-repl`: Examples\n\n\u003cdetails\u003e\u003csummary\u003e\u003ch4\u003e\u003ccode\u003ezig-repl\u003c/code\u003e: Basics\u003c/h4\u003e\u003c/summary\u003e\n\n```text\nzig\u003e state.u[0] = 41;                  // Store 41 in persistent integer slot 0.\nzig\u003e state.u[0] += 1; state.result = state.u[0];  // Increment and publish the result.\nresult 0x000000000000002a (42)\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\u003csummary\u003e\u003ch4\u003e\u003ccode\u003ezig-repl\u003c/code\u003e: Making a System Call\u003c/h4\u003e\u003c/summary\u003e\n\n```text\nzig\u003e extern fn getpid() c_int;\ndefinition block committed\nzig\u003e state.result = @as(u64, @intCast(getpid()));\nresult 0x0000000000001234 (4660)\n```\n\nThe exact process id will be different on your machine.\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\u003csummary\u003e\u003ch4\u003e\u003ccode\u003ezig-repl\u003c/code\u003e: Full Calculator\u003c/h4\u003e\u003c/summary\u003e\n\nThis computes:\n\n```text\n(7 + 35) * 2 = 84\n```\n\n```text\nzig\u003e fn calcAdd(a: u64, b: u64) u64 { return a + b; }\ndefinition block committed\nzig\u003e fn calcMul(a: u64, b: u64) u64 { return a * b; }\ndefinition block committed\nzig\u003e state.result = calcMul(calcAdd(7, 35), 2);\nresult 0x0000000000000054 (84)\n```\n\n\u003c/details\u003e\n\n### `zig-repl`: Reference\n\nPersistent state:\n\n```zig\nstate.result       /* u64 result value printed after each run */\nstate.u[n]         /* 16 persistent integer slots */\nstate.f[n]         /* 16 persistent f64 slots */\nstate.scratch[n]   /* 4096 bytes of persistent scratch memory */\nstate.out          /* 4096-byte output buffer used by print(...) */\n```\n\nConvenience helper:\n\n```zig\nprint(state, \"value={}\\n\", .{state.u[0]});  /* Append formatted text to state.out. */\n```\n\nCommands:\n\n- `:help` shows commands and execution notes\n- `:help \u003ctopic\u003e` shows built-in help for a topic\n- `:topics` lists built-in topic help\n- `:instructions` lists built-in topic help\n- `:state` prints persistent slots, result, and output\n- `:reset` resets persistent state\n- `:scratch` prints scratch memory details\n- `:defs` prints persisted definitions\n- `:def` starts an explicit persisted definition block\n- `:end` commits the explicit definition block\n- `:clear` clears definitions\n- `:source` prints the last generated source file path\n- `:quit` exits\n\nMulti-line input is collected until `zig` accepts it. Top-level definitions are\npersisted automatically; accepted statements run inside `repl_entry`. Press\nEnter on an empty continuation line to force diagnostics.\n\n## `go-repl`\n\n`go-repl` uses a gore-style build/run loop: each accepted snippet is emitted as\na temporary Go program, built with `go build`, and run as a child process. The\nREPL serializes persistent state before and after each run.\n\nUse it for small Go experiments, helper functions, and low-level package calls\nwithout keeping a full source file open. Normal `package main` and `import`\ndeclarations are accepted so snippets can stay close to source-file shape.\n\n### `go-repl`: Quickstart\n\n```bash\nnpm i -g assembly-repl  # Install the package globally.\ngo-repl                 # Start the Go REPL.\n\ngo\u003e :help                              // Show commands and Go help topics.\ngo\u003e state.Result = 40 + 2              // Compute 42 and store it as the printed result.\nresult 0x000000000000002a (42)\n```\n\n### `go-repl`: Examples\n\n\u003cdetails\u003e\u003csummary\u003e\u003ch4\u003e\u003ccode\u003ego-repl\u003c/code\u003e: Basics\u003c/h4\u003e\u003c/summary\u003e\n\n```text\ngo\u003e state.U[0] = 41                    // Store 41 in persistent integer slot 0.\ngo\u003e state.U[0] += 1; state.Result = state.U[0]  // Increment and publish the result.\nresult 0x000000000000002a (42)\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\u003csummary\u003e\u003ch4\u003e\u003ccode\u003ego-repl\u003c/code\u003e: Package Imports\u003c/h4\u003e\u003c/summary\u003e\n\n```text\ngo\u003e package main\ngo\u003e import \"math\"\nimport persisted\ngo\u003e state.Result = uint64(math.Abs(-42))\nresult 0x000000000000002a (42)\n```\n\nMulti-line import blocks work too:\n\n```text\ngo\u003e import (\ngo|     m \"math\"\ngo| )\nimport block persisted\ngo\u003e state.Result = uint64(m.Abs(-42))\nresult 0x000000000000002a (42)\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\u003csummary\u003e\u003ch4\u003e\u003ccode\u003ego-repl\u003c/code\u003e: Making a System Call\u003c/h4\u003e\u003c/summary\u003e\n\n```text\ngo\u003e package main\ngo\u003e import \"syscall\"\nimport persisted\ngo\u003e pid, _, errno := syscall.RawSyscall(syscall.SYS_GETPID, 0, 0, 0)\ngo| if errno == 0 { state.Result = uint64(pid) }\nresult 0x0000000000001234 (4660)\n```\n\nThe exact process id will be different on your machine.\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\u003csummary\u003e\u003ch4\u003e\u003ccode\u003ego-repl\u003c/code\u003e: Full Calculator\u003c/h4\u003e\u003c/summary\u003e\n\nThis computes:\n\n```text\n(7 + 35) * 2 = 84\n```\n\n```text\ngo\u003e func calcAdd(a, b uint64) uint64 { return a + b }\ndefinition block committed\ngo\u003e func calcMul(a, b uint64) uint64 { return a * b }\ndefinition block committed\ngo\u003e state.Result = calcMul(calcAdd(7, 35), 2)\nresult 0x0000000000000054 (84)\n```\n\n\u003c/details\u003e\n\n### `go-repl`: Reference\n\nPersistent state:\n\n```go\nstate.Result      /* uint64 result value printed after each run */\nstate.U[n]        /* 16 persistent integer slots */\nstate.F[n]        /* 16 persistent float64 slots */\nstate.Scratch[n]  /* 4096 bytes of persistent scratch memory */\nstate.Out         /* 4096-byte output buffer used by Print(...) */\n```\n\nConvenience helper:\n\n```go\nPrint(state, \"value=%d\\n\", state.U[0])  /* Append formatted text to state.Out. */\n```\n\nCommands:\n\n- `:help` shows commands and execution notes\n- `:help \u003ctopic\u003e` shows built-in help for a topic\n- `:topics` lists built-in topic help\n- `:instructions` lists built-in topic help\n- `:import \u003cpackage\u003e` is a shortcut for a Go import declaration\n- `:state` prints persistent slots, result, and output\n- `:reset` resets persistent state\n- `:scratch` prints scratch memory details\n- `:defs` prints persisted imports and definitions\n- `:def` starts an explicit persisted definition block\n- `:end` commits the explicit definition block\n- `:clear` clears imports and definitions\n- `:source` prints the last generated source file path\n- `:quit` exits\n\nMulti-line input is collected until `go build` accepts it. Package declarations\nare accepted as file boilerplate and ignored. Import declarations and top-level\ndefinitions are persisted automatically; accepted statements run inside\n`replEntry`. Press Enter on an empty continuation line to force diagnostics.\n\n## Runtime Internals 🛠️\n\n### `assembly-repl`: How It Works\n\nFor each executable input, the REPL writes a tiny wrapper assembly file into\n`.repl-build/`, like this conceptually:\n\n```asm\n_asmrepl_entry:                                   // Generated wrapper entry point.\n  ; save host registers the C ABI cares about     // Preserve the host process state.\n  ; load persisted user registers from reg_context_t // Restore the REPL register state.\n\n  \u003cyour instruction here\u003e                         // The instruction or branch you typed.\n\n  ; store user registers and NZCV flags back into reg_context_t // Persist the result.\n  ; restore host registers                         // Put the host ABI state back.\n  ret                                             // Return to the C runner.\n\n  ; persisted labels/directives/routines live down here // User definitions are appended.\n  _some_routine:                                  // Example persisted routine.\n    ret                                          // Return to its caller.\n```\n\nThen it runs:\n\n```sh\nclang -c -arch arm64 .repl-build/line-N.s -o .repl-build/line-N.o  # Assemble one generated snippet.\n```\n\nThe C code extracts the `__TEXT,__text` bytes from that object file, maps them\nwith `mmap`, flips the mapping to executable with `mprotect`, clears the\ninstruction cache, and calls the resulting function pointer.\n\n### Source-Language, LLVM IR, And WebAssembly REPLs\n\nThe source-language REPLs share one native runner, `language-repl`. The public\nentrypoints (`c-repl`, `cpp-repl`, `objc-repl`, `llvmir-repl`, `rust-repl`,\n`zig-repl`, and `go-repl`) are Node wrappers that choose a language mode and\nlaunch that native runner.\n\nFor C, C++, Objective-C, LLVM IR, Rust, and Zig, each accepted snippet is written\ninto `.repl-build/`, compiled into a shared library, loaded into the REPL\nprocess with `dlopen`, and called through a common `repl_entry` function. State\nlives in a persistent `repl_state_t` struct that is passed to each snippet.\n\n`go-repl` writes a temporary Go program instead of a shared library. The native\nrunner serializes the REPL state to a `.bin` file, runs the compiled Go child\nprocess, then reads the state file back after the child exits.\n\n`wasm-repl` is implemented as a Node runner instead of a native runner. It emits\nWebAssembly binaries directly, instantiates them with Node's `WebAssembly` API,\nand writes the generated `.wat` and `.wasm` artifacts into `.repl-build/`.\n\n## Debugger Flag 🔎\n\nPass `--debugger` to any REPL command to open a debugger with the right target\nselected. With no value, the wrapper tries LLDB first, then GDB. You can also\nuse `--lldb`, `--gdb`, or choose an explicit debugger:\n\n```sh\nassembly-repl --debugger\nwasm-repl --debugger=lldb-gui\n```\n\nAllowed debugger names:\n\n- `lldb`\n- `lldb-gui` 🌈\n- `gdb`\n- `gdb-tui` 🌈\n- `cgdb` 🌈\n- `pwnbg` 🌈\n- `pwndbg` 🌈\n\nIf the selected debugger is missing, the wrapper prints install hints for that\ndependency. On macOS, `pwnbg`/`pwndbg` uses `pwndbg-lldb` attach mode.\n\n## Development 🛠️\n\nThis section is for working on `assembly-repl` itself. Normal users should only\nneed the install, runtime requirements, commands, examples, runtime internals,\nand debugging notes above.\n\n### Development Requirements\n\n- `make` only if building local native runners from source\n- Docker buildx if refreshing all packaged prebuilds with `pnpm build`\n\n### Refresh Packaged Prebuilds\n\n```sh\npnpm build  # Rebuild and vendor packaged native prebuilds.\n```\n\nThis rebuilds the macOS arm64 native runners locally, rebuilds the Linux x64 and\nLinux arm64 native runners with Docker buildx, and vendors all of them into\n`prebuilds/`.\n\n### Local Native Build\n\nFor a local-only native build:\n\n```sh\nmake       # Build local native runners.\n./asmrepl  # Run the local assembly runner directly.\n```\n\nOr:\n\n```sh\nmake run   # Build and run the local assembly runner.\n```\n\nClean generated files:\n\n```sh\nmake clean # Remove generated native build outputs.\n```\n\n## Further Reading\n\n- https://imtomt.github.io/ymawky/\n- https://mariokartwii.com/arm64/\n- https://hrishim.github.io/llvl_prog1_book/starting_assembly.html\n- https://github.com/pirate/polyglot-agent\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpirate%2Fassembly-repl","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpirate%2Fassembly-repl","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpirate%2Fassembly-repl/lists"}