|
@@ -2,6 +2,54 @@ use "collections"
|
|
|
use "files"
|
|
|
use "format"
|
|
|
|
|
|
+class Value
|
|
|
+ let _addr: I64
|
|
|
+ let _value: I64
|
|
|
+
|
|
|
+ new create(__addr: I64, __value: I64) =>
|
|
|
+ _addr = __addr
|
|
|
+ _value = __value
|
|
|
+
|
|
|
+ fun addr(): I64 => _addr
|
|
|
+ fun value(): I64 => _value
|
|
|
+
|
|
|
+class Operands
|
|
|
+ let _lhs: Value
|
|
|
+ let _rhs: Value
|
|
|
+ let _tgt: I64
|
|
|
+
|
|
|
+ new create(__lhs: Value, __rhs: Value, __tgt: I64) =>
|
|
|
+ _lhs = __lhs
|
|
|
+ _rhs = __rhs
|
|
|
+ _tgt = __tgt
|
|
|
+
|
|
|
+ fun val1(): I64 => _lhs.value()
|
|
|
+ fun val2(): I64 => _rhs.value()
|
|
|
+ fun tgt(): USize => _tgt.usize()
|
|
|
+
|
|
|
+trait Error
|
|
|
+ fun message(): String
|
|
|
+
|
|
|
+class OutOfBounds is Error
|
|
|
+ let _loc: USize
|
|
|
+
|
|
|
+ new create(loc: USize) => _loc = loc
|
|
|
+ fun message(): String =>
|
|
|
+ "Memory access out of bounds: " + Format.int[USize](_loc)
|
|
|
+
|
|
|
+class UnknownOperand is Error
|
|
|
+ let _op: I64
|
|
|
+ new create(op: I64) => _op = op
|
|
|
+ fun message(): String =>
|
|
|
+ "Unknown operand: " + Format.int[I64](_op)
|
|
|
+
|
|
|
+primitive Handler
|
|
|
+ fun run(env: Env, result: (None | Error)) =>
|
|
|
+ match result
|
|
|
+ | None => None
|
|
|
+ | let e: Error => env.err.print(e.message())
|
|
|
+ end
|
|
|
+
|
|
|
class Program
|
|
|
var storage: Array[I64]
|
|
|
var pc: USize = 0
|
|
@@ -27,47 +75,70 @@ class Program
|
|
|
end
|
|
|
env.out.print("]")
|
|
|
|
|
|
- fun ref get_op_data(env: Env): (I64, I64, I64, I64, I64) ? =>
|
|
|
- let addr1 = storage(pc+1)?
|
|
|
- let addr2 = storage(pc+2)?
|
|
|
- let tgt = storage(pc+3)?
|
|
|
+ fun ref get_value(addr_loc: USize): (Value | Error) =>
|
|
|
+ let addr = try storage(addr_loc)? else return OutOfBounds(addr_loc) end
|
|
|
+ let value = try storage(addr.usize())? else return OutOfBounds(addr.usize()) end
|
|
|
+ Value(addr, value)
|
|
|
|
|
|
- let val1 = storage(addr1.usize())?
|
|
|
- let val2 = storage(addr2.usize())?
|
|
|
- (addr1, val1, addr2, val2, tgt)
|
|
|
+ fun ref get_op_data(): (Operands | Error) =>
|
|
|
+ let lhs = match get_value(pc+1)
|
|
|
+ | let v: Value => v
|
|
|
+ | let e: Error => return e
|
|
|
+ end
|
|
|
+ let rhs = match get_value(pc+2)
|
|
|
+ | let v: Value => v
|
|
|
+ | let e: Error => return e
|
|
|
+ end
|
|
|
+ let tgt = try storage(pc+3)? else return OutOfBounds(pc+1) end
|
|
|
+ Operands(lhs, rhs, tgt)
|
|
|
|
|
|
- fun ref do_add(env: Env) ? =>
|
|
|
- (let x1, let op1, let x2, let op2, let tgt) = get_op_data(env)?
|
|
|
- storage.update(tgt.usize(), op1 + op2)?
|
|
|
+ fun ref do_add(): (None | Error) =>
|
|
|
+ let data = match get_op_data()
|
|
|
+ | let o: Operands => o
|
|
|
+ | let e: Error => return e
|
|
|
+ end
|
|
|
+ try
|
|
|
+ storage(data.tgt())? = data.val1() + data.val2()
|
|
|
+ else
|
|
|
+ return OutOfBounds(data.tgt())
|
|
|
+ end
|
|
|
pc = pc + 4
|
|
|
- run(env)
|
|
|
+ None
|
|
|
|
|
|
- fun ref do_mul(env: Env) ? =>
|
|
|
- (let x1, let op1, let x2, let op2, let tgt) = get_op_data(env)?
|
|
|
- storage.update(tgt.usize(), op1 * op2)?
|
|
|
+ fun ref do_mul(): (None | Error) =>
|
|
|
+ let data = match get_op_data()
|
|
|
+ | let o: Operands => o
|
|
|
+ | let e: Error => return e
|
|
|
+ end
|
|
|
+ try
|
|
|
+ storage(data.tgt())? = data.val1() * data.val2()
|
|
|
+ else
|
|
|
+ return OutOfBounds(data.tgt())
|
|
|
+ end
|
|
|
pc = pc + 4
|
|
|
- run(env)
|
|
|
+ None
|
|
|
|
|
|
- fun ref run(env: Env) =>
|
|
|
+ fun ref run(): (None | Error) =>
|
|
|
try
|
|
|
match storage(pc)?
|
|
|
- | 1 => do_add(env)?
|
|
|
- | 2 => do_mul(env)?
|
|
|
- | 99 => None
|
|
|
- | let x: I64 => env.err.print("Unknown opcode " + Format.int[I64](x))
|
|
|
+ | 1 => do_add()
|
|
|
+ | 2 => do_mul()
|
|
|
+ | 99 => return None
|
|
|
+ | let x: I64 => return UnknownOperand(x)
|
|
|
end
|
|
|
else
|
|
|
- env.err.print("PC " + Format.int[USize](pc) + " out of bounds")
|
|
|
- end
|
|
|
+ return OutOfBounds(pc)
|
|
|
+ end
|
|
|
+ run()
|
|
|
|
|
|
fun make_trial(a: I64, b: I64): Program ? =>
|
|
|
var arr = storage.clone()
|
|
|
- arr.update(1, a)?
|
|
|
- arr.update(2, b)?
|
|
|
+ arr(1)? = a
|
|
|
+ arr(2)? = b
|
|
|
Program(arr)
|
|
|
|
|
|
fun ref run_trial(env: Env): Bool =>
|
|
|
- run(env)
|
|
|
+ Handler.run(env, run())
|
|
|
try
|
|
|
storage(0)? == 19690720
|
|
|
else
|