From c4bd5219f8f4a4e984eeb3331126a2ac13df7e82 Mon Sep 17 00:00:00 2001 From: Chris Wanstrath <2+defunkt@users.noreply.github.com> Date: Tue, 7 Oct 2025 12:56:55 -0700 Subject: [PATCH] adding a new opcode --- CLAUDE.md | 170 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 170 insertions(+) diff --git a/CLAUDE.md b/CLAUDE.md index 33b0ad9..99f54aa 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -161,6 +161,176 @@ HALT - Prefer Bun APIs over Node.js equivalents when available - See .cursor/rules/use-bun-instead-of-node-vite-npm-pnpm.mdc for detailed Bun usage +## Adding a New OpCode + +When adding a new instruction to ReefVM, you must update multiple files in a specific order. Follow this checklist: + +### 1. Define the OpCode (src/opcode.ts) + +Add the new opcode to the `OpCode` enum with comprehensive documentation: + +```typescript +export enum OpCode { + // ... existing opcodes + + MY_NEW_OP, // operand: | stack: [inputs] → [outputs] + // Description of what it does + // Any important behavioral notes +} +``` + +### 2. Implement VM Execution (src/vm.ts) + +Add a case to the `execute()` method's switch statement: + +```typescript +async execute(instruction: Instruction) { + switch (instruction.op) { + // ... existing cases + + case OpCode.MY_NEW_OP: + // Implementation + // - Pop values from this.stack as needed + // - Perform the operation + // - Push results to this.stack + // - Throw errors for invalid operations + // - Use await for async operations + break + } +} +``` + +Common helper methods: +- `this.binaryOp((a, b) => ...)` - For binary arithmetic/comparison +- `toNumber(value)`, `toString(value)`, `isTrue(value)`, `isEqual(a, b)` - Type coercion +- `this.scope.get(name)`, `this.scope.set(name, value)` - Variable access + +### 3. Update Validator (src/validator.ts) + +Add the opcode to the appropriate set: + +```typescript +// If your opcode requires an operand: +const OPCODES_WITH_OPERANDS = new Set([ + // ... existing + OpCode.MY_NEW_OP, +]) + +// If your opcode takes no operand: +const OPCODES_WITHOUT_OPERANDS = new Set([ + // ... existing + OpCode.MY_NEW_OP, +]) +``` + +If your opcode has complex operand validation, add a specific check in the validation loop around line 154. + +### 4. Update Array API (src/bytecode.ts) + +Add your instruction to the `InstructionTuple` type: + +```typescript +type InstructionTuple = + // ... existing types + | ["MY_NEW_OP"] // No operand + | ["MY_NEW_OP", string] // String operand + | ["MY_NEW_OP", number] // Number operand + | ["MY_NEW_OP", string, number] // Multiple operands +``` + +If your opcode has special operand handling, add a case in `toBytecodeFromArray()` around line 241. + +### 5. Write Tests (REQUIRED) + +Create tests in the appropriate test file: + +```typescript +// tests/basic.test.ts, tests/functions.test.ts, etc. + +test("MY_NEW_OP description", async () => { + const bytecode = toBytecode([ + // Setup + ["PUSH", 42], + ["MY_NEW_OP"], + ["HALT"] + ]) + + const result = await run(bytecode) + expect(result).toEqual({ type: "number", value: 42 }) +}) + +// Test edge cases +test("MY_NEW_OP with invalid input", async () => { + // Test error conditions + await expect(run(bytecode)).rejects.toThrow() +}) +``` + +**ALWAYS write tests.** Test both success cases and error conditions. Add integration tests showing real-world usage. + +### 6. Document Specification (SPEC.md) + +Add a formal specification entry: + +```markdown +#### MY_NEW_OP + +**Operand**: `` +**Stack**: `[input] → [output]` + +Description of what the instruction does. + +**Behavior**: +- Specific behavior point 1 +- Specific behavior point 2 + +**Errors**: +- Error condition 1 +- Error condition 2 +``` + +### 7. Update Compiler Guide (GUIDE.md) + +If your opcode introduces new patterns, add examples to GUIDE.md: + +```markdown +### New Pattern Name + +\``` +PUSH value +MY_NEW_OP +STORE result +\``` + +Description of the pattern and when to use it. +``` + +### 8. Add Examples (Optional) + +If your opcode enables new functionality, add an example to `examples/`: + +```typescript +// examples/my_feature.reef or examples/my_feature.ts +const example = toBytecode([ + // Demonstrate the new opcode +]) +``` + +### Checklist Summary + +When adding an opcode, update in this order: + +- [ ] `src/opcode.ts` - Add enum value with docs +- [ ] `src/vm.ts` - Implement execution logic +- [ ] `src/validator.ts` - Add to operand requirement set +- [ ] `src/bytecode.ts` - Add to InstructionTuple type +- [ ] `tests/*.test.ts` - Write comprehensive tests (**REQUIRED**) +- [ ] `SPEC.md` - Document formal specification +- [ ] `GUIDE.md` - Add compiler patterns (if applicable) +- [ ] `examples/` - Add example code (if applicable) + +Run `bun test` to verify all tests pass before committing. + ## Common Gotchas **Jump offsets**: JUMP/JUMP_IF_FALSE/JUMP_IF_TRUE use relative offsets from the next instruction (PC + 1). PUSH_TRY/PUSH_FINALLY use absolute instruction indices.