adding a new opcode
This commit is contained in:
parent
060fa064fe
commit
c4bd5219f8
170
CLAUDE.md
170
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: <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
|
||||
|
||||
**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.
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user