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
|
- `PUSH <const>` - Push constant
|
||||||
- `POP` - Remove top
|
- `POP` - Remove top
|
||||||
- `DUP` - Duplicate top
|
- `DUP` - Duplicate top
|
||||||
|
- `SWAP` - Swap top two values
|
||||||
|
|
||||||
### Variables
|
### Variables
|
||||||
- `LOAD <name>` - Push variable value (throws if not found)
|
- `LOAD <name>` - Push variable value (throws if not found)
|
||||||
|
|
@ -360,6 +361,30 @@ POP
|
||||||
.end: ; Result on stack
|
.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
|
### Try-Catch
|
||||||
```
|
```
|
||||||
PUSH_TRY .catch
|
PUSH_TRY .catch
|
||||||
|
|
|
||||||
5
SPEC.md
5
SPEC.md
|
|
@ -138,6 +138,11 @@ type ExceptionHandler = {
|
||||||
**Effect**: Duplicate top of stack
|
**Effect**: Duplicate top of stack
|
||||||
**Stack**: [value] → [value, value]
|
**Stack**: [value] → [value, value]
|
||||||
|
|
||||||
|
#### SWAP
|
||||||
|
**Operand**: None
|
||||||
|
**Effect**: Swap the top two values on the stack
|
||||||
|
**Stack**: [value1, value2] → [value2, value1]
|
||||||
|
|
||||||
### Variable Operations
|
### Variable Operations
|
||||||
|
|
||||||
#### LOAD
|
#### LOAD
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ export enum OpCode {
|
||||||
PUSH, // operand: constant index (number) | stack: [] → [value]
|
PUSH, // operand: constant index (number) | stack: [] → [value]
|
||||||
POP, // operand: none | stack: [value] → []
|
POP, // operand: none | stack: [value] → []
|
||||||
DUP, // operand: none | stack: [value] → [value, value]
|
DUP, // operand: none | stack: [value] → [value, value]
|
||||||
|
SWAP, // operand: none | stack: [value1, value2] → [value2, value1]
|
||||||
|
|
||||||
// variables
|
// variables
|
||||||
LOAD, // operand: variable name (identifier) | stack: [] → [value]
|
LOAD, // operand: variable name (identifier) | stack: [] → [value]
|
||||||
|
|
|
||||||
|
|
@ -144,6 +144,13 @@ export class VM {
|
||||||
this.stack.push(this.stack[this.stack.length - 1]!)
|
this.stack.push(this.stack[this.stack.length - 1]!)
|
||||||
break
|
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:
|
case OpCode.ADD:
|
||||||
const b = this.stack.pop()!
|
const b = this.stack.pop()!
|
||||||
const a = 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", () => {
|
describe("EQ", () => {
|
||||||
test("equality comparison", async () => {
|
test("equality comparison", async () => {
|
||||||
const str = `
|
const str = `
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user