Go to file
2025-10-29 15:28:34 -07:00
.cursor/rules it's alive 2025-10-05 13:43:13 -07:00
bin show natives in debugger/repl 2025-10-25 07:56:06 -07:00
examples dicts, too 2025-10-29 15:28:34 -07:00
src dicts, too 2025-10-29 15:28:34 -07:00
tests dicts, too 2025-10-29 15:28:34 -07:00
.gitignore ignore dev dir 2025-10-06 15:55:55 -07:00
bun.lock it's alive 2025-10-05 13:43:13 -07:00
CLAUDE.md vm.set(), new VM(bytecode, globalVars) 2025-10-28 13:05:24 -07:00
GUIDE.md vm.set(), new VM(bytecode, globalVars) 2025-10-28 13:05:24 -07:00
package.json Modern way to do exports (works with bun workspaces) 2025-10-10 15:33:30 -07:00
README.md vm.call(name, ...args) 2025-10-24 10:53:00 -07:00
SPEC.md dicts, too 2025-10-29 15:28:34 -07:00
tsconfig.json lib exports 2025-10-06 09:11:22 -07:00

🪸 ReefVM

It's where Shrimp live.

Quickstart

bun install
bun test

Use it

Execute text bytecode:

./bin/reef examples/loop.reef

Validate bytecode:

./bin/validate examples/loop.reef

Run the simple debugger to see what the instructions are doing:

./bin/debug examples/loop.reef
./bin/debug -h examples/loop.reef

Interactive REPL for exploring instructions:

./bin/repl

Type opcodes interactively and see the stack and variables update in real-time.

Commands: clear, reset, exit.

Features

  • Stack operations (PUSH, POP, DUP)
  • Arithmetic operations (ADD, SUB, MUL, DIV, MOD)
  • Comparison operations (EQ, NEQ, LT, GT, LTE, GTE)
  • Logical operations (NOT, AND/OR patterns with short-circuiting)
  • Variable operations (LOAD, STORE) with emoji and Unicode support (💎 = 5)
  • Control flow with relative jumps (JUMP, JUMP_IF_FALSE, JUMP_IF_TRUE, BREAK, CONTINUE)
  • Array operations (MAKE_ARRAY, ARRAY_GET, ARRAY_SET, ARRAY_PUSH, ARRAY_LEN)
  • Dictionary operations (MAKE_DICT, DICT_GET, DICT_SET, DICT_HAS)
  • Function operations (MAKE_FUNCTION, CALL, TAIL_CALL, RETURN) with parameter binding
  • Variadic functions with positional rest parameters (...rest)
  • Named arguments (named) that collect unmatched named args into a dict (@named)
  • Mixed positional and named arguments with proper priority binding
  • Tail call optimization with unbounded recursion (10,000+ iterations without stack overflow)
  • Exception handling (PUSH_TRY, PUSH_FINALLY, POP_TRY, THROW) with nested try/finally blocks and call stack unwinding
  • Native function interop with auto-wrapping for native TypeScript types
  • Native functions stored in scope, called via LOAD + CALL
  • Native functions support atXxx parameters (e.g., atOptions) to collect unmatched named args
  • Pass functions directly to run(bytecode, { fnName: fn }) or new VM(bytecode, { fnName: fn })
  • Call Reef functions from TypeScript with vm.call(name, ...args) with automatic type conversion

Design Decisions

  • Relative jumps: All JUMP instructions use PC-relative offsets instead of absolute addresses, making bytecode position-independent
  • Truthiness: Only null and false are falsy (unlike JavaScript where 0, "", etc. are also falsy)
  • Short-circuiting via compiler: No AND/OR opcodes—compilers use JUMP patterns for proper short-circuit evaluation
  • Variadic parameters: Functions can collect remaining positional arguments into an array using ...rest syntax
  • Named parameters: Functions can collect unmatched named arguments into a dict using @named syntax
  • Argument binding priority: Named args bind to regular params first, with unmatched ones going to @named