Browse Source

Start from the old code but rework error-handling to be not gross

Getty Ritter 4 years ago
parent
commit
b1eed9bb19
1 changed files with 195 additions and 0 deletions
  1. 195 0
      05/main.pony

+ 195 - 0
05/main.pony

@@ -0,0 +1,195 @@
+use "collections"
+use "files"
+use "format"
+
+interface Value
+  fun value(): I64
+
+
+class Position
+  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 Immediate
+  let _value: I64
+
+  new create(__value: I64) =>
+    _value = __value
+
+  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 val OutOfBounds is Error
+  let _loc: USize
+  new val create(loc: USize) => _loc = loc
+  fun message(): String =>
+    "Memory access out of bounds: " + Format.int[USize](_loc)
+
+class val UnknownOperand is Error
+  let _op: I64
+  new val 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
+  var errors: Array[Error val]
+
+  new create(s: Array[I64]) =>
+    storage = s
+    errors = Array[Error val]()
+
+  new from_file(file: File) =>
+    storage = Array[I64](0)
+    for line in file.lines() do
+      for chunk in line.split(",").values() do
+        try
+          storage.push(chunk.i64()?)
+        end
+      end
+    end
+    errors = Array[Error val]()
+
+
+  fun print(env: Env) =>
+    env.out.write("[")
+    for x in storage.values() do
+      env.out.write(Format.int[I64](x))
+      env.out.write(" ")
+    end
+    env.out.print("]")
+
+  fun ref read_storage(addr: USize): I64 ? =>
+    try
+      storage(addr)?
+    else
+      errors.push(OutOfBounds(addr))
+      error
+    end
+
+  fun ref write_storage(addr: USize, value: I64) ? =>
+    try
+      storage(addr)? = value
+    else
+      errors.push(OutOfBounds(addr))
+      error
+    end
+
+
+  fun ref get_immediate(addr_loc: USize): Immediate ? =>
+    let value = read_storage(addr_loc)?
+    Immediate(value)
+
+  fun ref get_position(addr_loc: USize): Position ? =>
+    let addr = read_storage(addr_loc)?
+    let value = read_storage(addr.usize())?
+    Position(addr, value)
+
+
+  fun ref get_op_data(): Operands ? =>
+    let lhs = get_position(pc+1)?
+    let rhs = get_position(pc+2)?
+    let tgt = read_storage(pc+3)?
+    Operands(lhs, rhs, tgt)
+
+  fun ref do_add() ? =>
+    let data = get_op_data()?
+    write_storage(data.tgt(), data.val1() + data.val2())?
+    pc = pc + 4
+    None
+
+  fun ref do_mul() ? =>
+    let data = get_op_data()?
+    write_storage(data.tgt(), data.val1() * data.val2())?
+    pc = pc + 4
+    None
+
+  fun ref run() ? =>
+    match read_storage(pc)?
+      | 1 => do_add()?
+      | 2 => do_mul()?
+      | 99 => return None
+      | let x: I64 =>
+        errors.push(UnknownOperand(x))
+        error
+    end
+    run()?
+
+  fun make_trial(a: I64, b: I64): Program ? =>
+    var arr = storage.clone()
+    arr(1)? = a
+    arr(2)? = b
+    Program(arr)
+
+  fun ref run_trial(env: Env): Bool =>
+    try
+      run()?
+    else
+      for err in errors.values() do
+        env.out.print(err.message())
+      end
+    end
+    try
+      storage(0)? == 19690720
+    else
+      false
+    end
+
+actor Main
+  new create(env: Env) =>
+    let caps = recover val FileCaps.>set(FileRead).>set(FileStat) end
+
+    try
+      with
+        file = OpenFile(FilePath(env.root as AmbientAuth, "input.txt", caps)?) as File
+      do
+        let program = Program.from_file(file)
+        program.print(env)
+        for a in Range[I64](0, 100) do
+          for b in Range[I64](0, 100) do
+            let trial = program.make_trial(a, b)?
+            if trial.run_trial(env) then
+              env.out.print("noun=" + Format.int[I64](a) + ", verb=" + Format.int[I64](b))
+              env.out.print("result=" + Format.int[I64]((a * 100) + b))
+            end
+          end
+        end
+      end
+    else
+      // if something failed, then print an error message of some kind and exit
+      env.err.print("Couldn't read expected file `input.txt'")
+      env.exitcode(99)
+    end