Browse Source

Add some comments and cleanup

Getty Ritter 4 years ago
parent
commit
35ac29fce1
1 changed files with 107 additions and 6 deletions
  1. 107 6
      05/main.pony

+ 107 - 6
05/main.pony

@@ -3,10 +3,17 @@ use "files"
 use "format"
 
 interface Value
+  """
+  Values referred to by opcodes in instructions should all be things
+  that implement this interface
+  """
   fun value(): I64
 
 
 class Position
+  """
+  A positional operand (i.e. one whose value is fetched from a memory cell
+  """
   let _addr: I64
   let _value: I64
 
@@ -18,6 +25,9 @@ class Position
   fun value(): I64 => _value
 
 class Immediate
+  """
+  An immediate operand (i.e. one whose value is a verbatim argument)
+  """
   let _value: I64
 
   new create(__value: I64) =>
@@ -26,6 +36,10 @@ class Immediate
   fun value(): I64 => _value
 
 class Operands
+  """
+  The operands to a typical binary operator: two values and a target
+  that will always be in positional (i.e. non-immediate) mode
+  """
   let _lhs: Value
   let _rhs: Value
   let _tgt: I64
@@ -40,6 +54,10 @@ class Operands
   fun tgt(): USize => _tgt.usize()
 
 trait Error
+  """
+  The errors we can raise will all implement this so we can give
+  nice informative error messages
+  """
   fun message(): String
 
 class val OutOfBounds is Error
@@ -61,24 +79,46 @@ class val NotEnoughInput is Error
     "Not enough input when running instruction at " + Format.int[USize](_pc)
 
 
+// I should wrap this but I haven't, so, uh, yeah
 type Opcode is I64
+// a Mode is true if immediate, false if positional
 type Modes is (Bool, Bool, Bool)
 
 
 class Program
+  """
+  All the logic we need for running programs
+  """
+
+  // an array of memory cells
   var storage: Array[I64]
+  // the current instruction we're running
   var pc: USize = 0
+
+  // 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?)
   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
   var debug: Array[String] = Array[String]()
 
-  new create(s: Array[I64], i: Array[I64]) =>
+  new create(s: Array[I64], i: Array[I64] = Array[I64]()) =>
+    """
+    Create a Program from a verbatim storage and input array
+    """
     storage = s
     input = i
 
-  new from_file(file: File, i: Array[I64]) =>
+  new from_file(file: File, i: Array[I64] = Array[I64]()) =>
+    """
+    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
+    might not be what we want!
+    """
     storage = Array[I64](0)
     for line in file.lines() do
       for chunk in line.split(",").values() do
@@ -91,6 +131,9 @@ class Program
 
 
   fun print(env: Env) =>
+    """
+    Print out the current state of memory
+    """
     env.out.write("[")
     for x in storage.values() do
       env.out.write(Format.int[I64](x))
@@ -99,10 +142,17 @@ class Program
     env.out.print("]")
 
   fun ref dbg(msg: String) =>
+    """
+    Log a debug message
+    """
     debug.push(msg)
 
 
   fun ref read_storage(addr: USize): I64 ? =>
+    """
+    Attempt to read a word from storage, logging an error message
+    if we fail to do so
+    """
     try
       storage(addr)?
     else
@@ -111,6 +161,10 @@ class Program
     end
 
   fun ref write_storage(addr: USize, value: I64) ? =>
+    """
+    Attempt to write a word to storage, logging an error message
+    if we fail to do so
+    """
     try
       storage(addr)? = value
     else
@@ -120,15 +174,25 @@ class Program
 
 
   fun ref get_immediate(addr_loc: USize): Immediate ? =>
+    """
+    Read a single immediate value at the provided loc
+    """
     let value = read_storage(addr_loc)?
     Immediate(value)
 
   fun ref get_position(addr_loc: USize): Position ? =>
+    """
+    Read a positional value whose address is stored at the provided loc
+    """
     let addr = read_storage(addr_loc)?
     let value = read_storage(addr.usize())?
     Position(addr, value)
 
   fun ref get_value(addr_loc: USize, mode: Bool): Value ? =>
+    """
+    Read a value at the provided loc based on the mode: if true, then
+    treat it as an immediate, otherwise treat it as a positional
+    """
     if mode then
       get_immediate(addr_loc)?
     else
@@ -137,6 +201,9 @@ class Program
 
 
   fun ref get_op_data(modes: Modes): Operands ? =>
+    """
+    Get the data that a binary op needs based on the provided modes
+    """
     (let lm, let rm, _) = modes
     let lhs = get_value(pc+1, lm)?
     let rhs = get_value(pc+2, rm)?
@@ -144,6 +211,11 @@ class Program
     Operands(lhs, rhs, tgt)
 
   fun ref parse_op(n: I64): (Opcode, Modes) =>
+    """
+    Parse out an opcode and set of modes. This hard-codes modes
+    for three operands; it might be worth it in the future to generalize
+    to any N operands
+    """
     let opcode = n % 100
     let mode1 =   (n / 100) % 10
     let mode2 =  (n / 1000) % 10
@@ -152,11 +224,21 @@ class Program
 
 
   fun ref do_binop(modes: Modes, op: {(I64, I64): I64}) ? =>
+    """
+    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
+    provided location
+    """
     let data = get_op_data(modes)?
     write_storage(data.tgt(), op(data.val1(), data.val2()))?
     pc = pc + 4
 
   fun ref do_jump(modes: Modes, jump_cond: {(I64): Bool}) ? =>
+    """
+    Get the value indicated by the modes at [pc+1], and the function
+    `jump_cond` returns true on that value, then jump to the location
+    indicated by [pc+2], otherwise move ahead as usual
+    """
     (let cond, let tgt, _) = modes
     if jump_cond(get_value(pc+1, cond)?.value()) then
       pc = get_value(pc+2, tgt)?.value().usize()
@@ -165,6 +247,10 @@ class Program
     end
 
   fun ref do_input(modes: Modes) ? =>
+    """
+    Read a value from the input and put it into storage. This logs an
+    error if there are not enough values in the input queue.
+    """
     let i = try
       input.shift()?
     else
@@ -175,12 +261,20 @@ class Program
     pc = pc + 2
 
   fun ref do_output(modes: Modes) ? =>
+    """
+    Write the value indicated according to the mode to the output queue.
+    """
     (let m, _, _) = modes
     output.push(get_value(pc+1, m)?.value())
     pc = pc + 2
 
 
-  fun ref run() ? =>
+  fun ref run_loop() ? =>
+    """
+    This continues running the VM until it encounters a halt instruction
+    or it encounters some other error
+    """
+
     while true do
       (let opcode, let modes) = parse_op(read_storage(pc)?)
       dbg("running op " + Format.int[I64](opcode))
@@ -200,9 +294,16 @@ class Program
       end
     end
 
-  fun ref run_trial(env: Env) =>
+  fun ref run(env: Env) =>
+    """
+    This runs the VM and prints output: if an error occurs, it prints
+    the error message(s) and any debug messages that happened during
+    program execution, and then it prints everything printed via an
+    output instruction.
+    """
+
     try
-      run()?
+      run_loop()?
     else
       for err in errors.values() do
         env.out.print(err.message())
@@ -224,7 +325,7 @@ actor Main
         file = OpenFile(FilePath(env.root as AmbientAuth, "input.txt", caps)?) as File
       do
         let program = Program.from_file(file, [5])
-        program.run_trial(env)
+        program.run(env)
         program.print(env)
       end
     else