|  | @@ -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
 |