adding a new opcode

This commit is contained in:
Chris Wanstrath 2025-10-07 12:56:55 -07:00
parent 060fa064fe
commit c4bd5219f8

170
CLAUDE.md
View File

@ -161,6 +161,176 @@ HALT
- Prefer Bun APIs over Node.js equivalents when available - 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 - 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: <type> | 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**: `<type>`
**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 ## 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. **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.