Преглед на файлове

Solve the problem badly with too many debug messages

Getty Ritter преди 4 години
родител
ревизия
093270c8a2
променени са 1 файла, в които са добавени 140 реда и са изтрити 35 реда
  1. 140 35
      07/main.pony

+ 140 - 35
07/main.pony

@@ -85,6 +85,21 @@ type Opcode is I64
 // a Mode is true if immediate, false if positional
 // a Mode is true if immediate, false if positional
 type Modes is (Bool, Bool, Bool)
 type Modes is (Bool, Bool, Bool)
 
 
+
+class val OutputRequest
+  let _o: I64
+  new val create(_o': I64) => _o = _o'
+  fun output(): I64 => _o
+  fun string(): String =>
+    "OutputRequest(" + _o.string() + ")"
+primitive InputRequest
+  fun string(): String => "InputRequest"
+primitive Halted
+  fun string(): String => "Halted"
+
+type ProgramResult is (OutputRequest | InputRequest | Halted)
+
+
 class Program
 class Program
   """
   """
   All the logic we need for running programs
   All the logic we need for running programs
@@ -94,26 +109,23 @@ class Program
   var storage: Array[I64]
   var storage: Array[I64]
   // the current instruction we're running
   // the current instruction we're running
   var pc: USize = 0
   var pc: USize = 0
+  //
+  var input: Array[I64] = Array[I64]()
 
 
   // a list of errors that may or may not have happened. (right now,
   // a list of errors that may or may not have happened. (right now,
   // we'll only ever have one, but it's worth planning ahead, eh?)
   // we'll only ever have one, but it's worth planning ahead, eh?)
   var errors: Array[Error val] = Array[Error val]()
   var errors: Array[Error val] = Array[Error val]()
 
 
-  // the queue of input values from the user
-  var input: Array[I64]
-  // the queue of lines we intend to output
-  var output: Array[I64] = Array[I64]()
   // a queue of debug messages
   // a queue of debug messages
   var debug: Array[String] = Array[String]()
   var debug: Array[String] = Array[String]()
 
 
-  new create(s: Array[I64], i: Array[I64] = Array[I64]()) =>
+  new create(s: Array[I64]) =>
     """
     """
     Create a Program from a verbatim storage and input array
     Create a Program from a verbatim storage and input array
     """
     """
     storage = s
     storage = s
-    input = i
 
 
-  new from_file(file: File, i: Array[I64] = Array[I64]()) =>
+  new from_file(file: File) =>
     """
     """
     Create a Program by walking input from a file. This just skips any
     Create a Program by walking input from a file. This just skips any
     errors if they happen (e.g. if there are non-numbers), which
     errors if they happen (e.g. if there are non-numbers), which
@@ -127,8 +139,9 @@ class Program
         end
         end
       end
       end
     end
     end
-    input = i
 
 
+  fun ref send_input(i: I64) =>
+    input.push(i)
 
 
   fun print(env: Env) =>
   fun print(env: Env) =>
     """
     """
@@ -224,13 +237,15 @@ class Program
     (opcode, (mode1 == 1, mode2 == 1, mode3 == 1))
     (opcode, (mode1 == 1, mode2 == 1, mode3 == 1))
 
 
 
 
-  fun ref do_binop(modes: Modes, op: {(I64, I64): I64}) ? =>
+  fun ref do_binop(modes: Modes, op: {(I64, I64): I64}, op_name: String) ? =>
     """
     """
     Get the values of the first two operands by the provided modes, run
     Get the values of the first two operands by the provided modes, run
     the function `op` on them, and store the result of that at the
     the function `op` on them, and store the result of that at the
     provided location
     provided location
     """
     """
     let data = get_op_data(modes)?
     let data = get_op_data(modes)?
+    dbg("    writing " + data.val1().string() + op_name + data.val2().string()
+      + " = " + op(data.val1(), data.val2()).string() + " to *" + data.tgt().string())
     write_storage(data.tgt(), op(data.val1(), data.val2()))?
     write_storage(data.tgt(), op(data.val1(), data.val2()))?
     pc = pc + 4
     pc = pc + 4
 
 
@@ -258,19 +273,45 @@ class Program
       errors.push(NotEnoughInput(pc))
       errors.push(NotEnoughInput(pc))
       error
       error
     end
     end
-    write_storage(read_storage(pc+1)?.usize(), i)?
+    let addr = read_storage(pc+1)?.usize()
+    dbg("    writing " + i.string() + " to *" + addr.string())
+    write_storage(addr.usize(), i)?
     pc = pc + 2
     pc = pc + 2
 
 
-  fun ref do_output(modes: Modes) ? =>
+  fun ref do_output(modes: Modes): OutputRequest ? =>
     """
     """
     Write the value indicated according to the mode to the output queue.
     Write the value indicated according to the mode to the output queue.
     """
     """
     (let m, _, _) = modes
     (let m, _, _) = modes
-    output.push(get_value(pc+1, m)?.value())
+    let r = get_value(pc+1, m)?.value()
     pc = pc + 2
     pc = pc + 2
+    OutputRequest(r)
+
+  fun ref at_pc(): USize => pc
+
+  fun ref fmt_op(opcode: I64, modes: Modes): String =>
+    (let a, let b, let c) = modes
+    let op1 = try read_storage(pc+1)? else -99 end
+    let op2 = try read_storage(pc+2)? else -99 end
+    let op3 = try read_storage(pc+3)? else -99 end
+    let arg1 = if not a then "*" else "" end + op1.string()
+    let arg2 = if not b then "*" else "" end + op2.string()
+    let arg3 = if not c then "*" else "" end + op3.string()
+    match opcode
+      | 1 => "add " + arg1 + " " + arg2 + " -> " + arg3
+      | 2 => "sub " + arg1 + " " + arg2 + " -> " + arg3
+      | 3 => "input " + arg1
+      | 4 => "output " + arg1
+      | 5 => "jnz " + arg1 + " to " + arg2
+      | 6 => "jez " + arg1 + " to " + arg2
+      | 7 => "lt " + arg1 + " " + arg2 + " -> " + arg3
+      | 8 => "eq " + arg1 + " " + arg2 + " -> " + arg3
+      | 99 => "halt"
+    else
+      "unknown op(" + opcode.string() + ")"
+    end
 
 
-
-  fun ref run_loop() ? =>
+  fun ref run_loop(): ProgramResult ? =>
     """
     """
     This continues running the VM until it encounters a halt instruction
     This continues running the VM until it encounters a halt instruction
     or it encounters some other error
     or it encounters some other error
@@ -278,33 +319,43 @@ class Program
 
 
     while true do
     while true do
       (let opcode, let modes) = parse_op(read_storage(pc)?)
       (let opcode, let modes) = parse_op(read_storage(pc)?)
-      dbg("running op " + Format.int[I64](opcode))
+      dbg("  " + pc.string() + " -> " + fmt_op(opcode, modes))
       match opcode
       match opcode
-        | 1 => do_binop(modes, {(x, y) => x + y})?
-        | 2 => do_binop(modes, {(x, y) => x * y})?
-        | 3 => do_input(modes)?
-        | 4 => do_output(modes)?
+        | 1 => do_binop(modes, {(x, y) => x + y}, "+")?
+        | 2 => do_binop(modes, {(x, y) => x * y}, "*")?
+        | 3 => try do_input(modes)? else return InputRequest end
+        | 4 => return do_output(modes)?
         | 5 => do_jump(modes, {(x) => x != 0})?
         | 5 => do_jump(modes, {(x) => x != 0})?
         | 6 => do_jump(modes, {(x) => x == 0})?
         | 6 => do_jump(modes, {(x) => x == 0})?
-        | 7 => do_binop(modes, {(x, y) => if x < y then 1 else 0 end})?
-        | 8 => do_binop(modes, {(x, y) => if x == y then 1 else 0 end})?
-        | 99 => return None
+        | 7 => do_binop(modes, {(x, y) => if x < y then 1 else 0 end}, "<")?
+        | 8 => do_binop(modes, {(x, y) => if x == y then 1 else 0 end}, "==")?
+        | 99 => return Halted
         | let x: I64 =>
         | let x: I64 =>
           errors.push(UnknownOperand(x))
           errors.push(UnknownOperand(x))
           error
           error
       end
       end
     end
     end
+    Halted
 
 
-  fun ref run(env: Env): Array[I64] =>
+  fun ref run_with(env: Env, i: Array[I64]): Array[I64] =>
     """
     """
     This runs the VM and prints output: if an error occurs, it prints
     This runs the VM and prints output: if an error occurs, it prints
     the error message(s) and any debug messages that happened during
     the error message(s) and any debug messages that happened during
     program execution, and then it prints everything printed via an
     program execution, and then it prints everything printed via an
     output instruction.
     output instruction.
     """
     """
+    input.append(i)
 
 
+    var output = Array[I64]()
+    var is_done = false
     try
     try
-      run_loop()?
+      repeat
+        match run_loop()?
+          | Halted => is_done = true
+          | InputRequest => env.err.print("Not enough input for program"); is_done = true
+          | let o: OutputRequest => output.push(o.output())
+        end
+      until is_done end
     else
     else
       for err in errors.values() do
       for err in errors.values() do
         env.out.print(err.message())
         env.out.print(err.message())
@@ -318,12 +369,24 @@ class Program
     end
     end
     output
     output
 
 
-  fun ref clone(): Program =>
-    Program(storage, input)
+  fun ref run_step(env: Env): ProgramResult =>
+    try
+      env.out.print("restarting from " + pc.string())
+      let r = run_loop()?
+      for msg in debug.values() do
+        env.out.print(msg)
+      end
+      debug.clear()
+      r
+    else
+      for err in errors.values() do
+        env.out.print(err.message())
+      end
+      Halted
+    end
 
 
-  fun ref set_input(i: Array[I64]): Program =>
-    input = i
-    this
+  fun ref clone(): Program =>
+    Program(storage.clone())
 
 
 actor Main
 actor Main
   new create(env: Env) =>
   new create(env: Env) =>
@@ -334,12 +397,12 @@ actor Main
       with
       with
         file = OpenFile(FilePath(env.root as AmbientAuth, target_file, caps)?) as File
         file = OpenFile(FilePath(env.root as AmbientAuth, target_file, caps)?) as File
       do
       do
-        let program = Program.from_file(file, [0;1])
+        let program = Program.from_file(file)
         var max: (I64 | None) = None
         var max: (I64 | None) = None
         var choice = Array[I64]()
         var choice = Array[I64]()
-        for p in permutations([0;1;2;3;4]).values() do
-          env.out.print("\ntesting")
-          let res = test_phases(env, program, p)
+        for p in permutations([5;6;7;8;9]).values() do
+          env.out.print(".")
+          let res = test_phases_pt2(env, program, p)
           if try (res as I64) > (max as I64) else true end then
           if try (res as I64) > (max as I64) else true end then
             max = res
             max = res
             choice = p
             choice = p
@@ -358,10 +421,10 @@ actor Main
       env.exitcode(99)
       env.exitcode(99)
     end
     end
 
 
-  fun test_phases(env: Env, program: Program, phases: Array[I64]): (I64 | None) =>
+  fun test_phases_pt1(env: Env, program: Program, phases: Array[I64]): (I64 | None) =>
     var input: I64 = 0
     var input: I64 = 0
     for i in phases.values() do
     for i in phases.values() do
-      let output = program.clone().set_input([i; input]).run(env)
+      let output = program.clone().run_with(env, [i;input])
       input = try output(0)? else
       input = try output(0)? else
         env.out.print("Not enough output returned")
         env.out.print("Not enough output returned")
         return None
         return None
@@ -370,6 +433,48 @@ actor Main
     end
     end
     input
     input
 
 
+  fun test_phases_pt2(env: Env, program: Program, phases: Array[I64]): (I64 | None) =>
+    var input: (I64 | None) = 0
+    var programs = Array[(I64, Program)]()
+    var n: I64 = 0
+    for i in phases.values() do
+      let p = program.clone()
+      env.out.print("first step on " + n.string() + " produces " + p.run_step(env).string())
+      env.out.print("  (pc = " + p.at_pc().string() + ")")
+      env.out.print("sending input " + i.string())
+      p.send_input(i)
+      env.out.print("second step on " + n.string() + " produces " + p.run_step(env).string())
+      env.out.print("  (pc = " + p.at_pc().string() + ")")
+      programs.push((n, p))
+      n = n + 1
+    end
+
+    var programs_left = phases.size()
+    while programs_left > 0 do
+      for (n', p) in programs.values() do
+        env.out.print("running program " + n'.string() + " at " + p.at_pc().string() + " with " + input.string() + ": ")
+        try
+          p.send_input((input = None) as I64)
+        else
+          env.out.print("used input more than once!")
+          return None
+        end
+        var running = true
+        repeat
+          let r = p.run_step(env)
+          match r
+            | Halted => programs_left = programs_left - 1; running = false
+            | InputRequest => running = false
+            | let o: OutputRequest =>
+            input = o.output()
+            env.out.print("produced " + input.string() + ", ")
+          end
+        until not running end
+        env.out.print("")
+      end
+    end
+    input
+
   fun permutations(array: Array[I64]): Array[Array[I64]] =>
   fun permutations(array: Array[I64]): Array[Array[I64]] =>
     if array.size() == 0 then
     if array.size() == 0 then
       [[]]
       [[]]