forked from defunkt/ReefVM
SWAP opcode
This commit is contained in:
parent
c69b172c78
commit
4b2fd61554
25
GUIDE.md
25
GUIDE.md
|
|
@ -185,6 +185,7 @@ CALL
|
|||
- `PUSH <const>` - Push constant
|
||||
- `POP` - Remove top
|
||||
- `DUP` - Duplicate top
|
||||
- `SWAP` - Swap top two values
|
||||
|
||||
### Variables
|
||||
- `LOAD <name>` - Push variable value (throws if not found)
|
||||
|
|
@ -360,6 +361,30 @@ POP
|
|||
.end: ; Result on stack
|
||||
```
|
||||
|
||||
### Reversing Operand Order
|
||||
Use SWAP to reverse operand order for non-commutative operations:
|
||||
|
||||
```
|
||||
; Compute 10 / 2 when values are in reverse order
|
||||
PUSH 2
|
||||
PUSH 10
|
||||
SWAP ; Now: [10, 2]
|
||||
DIV ; 10 / 2 = 5
|
||||
```
|
||||
|
||||
```
|
||||
; Compute "hello" - "world" (subtraction with strings coerced to numbers)
|
||||
PUSH "world"
|
||||
PUSH "hello"
|
||||
SWAP ; Now: ["hello", "world"]
|
||||
SUB ; Result based on operand order
|
||||
```
|
||||
|
||||
**Common Use Cases**:
|
||||
- Division and subtraction when operands are in wrong order
|
||||
- String concatenation with specific order
|
||||
- Preparing arguments for functions that care about position
|
||||
|
||||
### Try-Catch
|
||||
```
|
||||
PUSH_TRY .catch
|
||||
|
|
|
|||
5
SPEC.md
5
SPEC.md
|
|
@ -138,6 +138,11 @@ type ExceptionHandler = {
|
|||
**Effect**: Duplicate top of stack
|
||||
**Stack**: [value] → [value, value]
|
||||
|
||||
#### SWAP
|
||||
**Operand**: None
|
||||
**Effect**: Swap the top two values on the stack
|
||||
**Stack**: [value1, value2] → [value2, value1]
|
||||
|
||||
### Variable Operations
|
||||
|
||||
#### LOAD
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ export enum OpCode {
|
|||
PUSH, // operand: constant index (number) | stack: [] → [value]
|
||||
POP, // operand: none | stack: [value] → []
|
||||
DUP, // operand: none | stack: [value] → [value, value]
|
||||
SWAP, // operand: none | stack: [value1, value2] → [value2, value1]
|
||||
|
||||
// variables
|
||||
LOAD, // operand: variable name (identifier) | stack: [] → [value]
|
||||
|
|
|
|||
|
|
@ -144,6 +144,13 @@ export class VM {
|
|||
this.stack.push(this.stack[this.stack.length - 1]!)
|
||||
break
|
||||
|
||||
case OpCode.SWAP:
|
||||
const first = this.stack.pop()!
|
||||
const second = this.stack.pop()!
|
||||
this.stack.push(first)
|
||||
this.stack.push(second)
|
||||
break
|
||||
|
||||
case OpCode.ADD:
|
||||
const b = this.stack.pop()!
|
||||
const a = this.stack.pop()!
|
||||
|
|
|
|||
|
|
@ -538,6 +538,36 @@ describe("DUP", () => {
|
|||
})
|
||||
})
|
||||
|
||||
describe("SWAP", () => {
|
||||
test("swaps two numbers", async () => {
|
||||
const str = `
|
||||
PUSH 10
|
||||
PUSH 20
|
||||
SWAP
|
||||
`
|
||||
expect(await run(toBytecode(str))).toEqual({ type: 'number', value: 10 })
|
||||
})
|
||||
|
||||
test("swap and use in subtraction", async () => {
|
||||
const str = `
|
||||
PUSH 5
|
||||
PUSH 10
|
||||
SWAP
|
||||
SUB
|
||||
`
|
||||
expect(await run(toBytecode(str))).toEqual({ type: 'number', value: 5 })
|
||||
})
|
||||
|
||||
test("swap different types", async () => {
|
||||
const str = `
|
||||
PUSH "hello"
|
||||
PUSH 42
|
||||
SWAP
|
||||
`
|
||||
expect(await run(toBytecode(str))).toEqual({ type: 'string', value: 'hello' })
|
||||
})
|
||||
})
|
||||
|
||||
describe("EQ", () => {
|
||||
test("equality comparison", async () => {
|
||||
const str = `
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user