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
|
- 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.
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user