Advertisement
Guest User

Karel VM

a guest
Mar 15th, 2015
31
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Scala 4.14 KB | None | 0 0
  1. package vm
  2.  
  3. import java.util.concurrent.atomic.AtomicReference
  4.  
  5. import Instruction._
  6. import logic.Karel
  7.  
  8. case class IllegalInstruction(bytecode: Int) extends Exception
  9.  
  10. object VM {
  11.   val TIMEOUT = 10000000000L
  12. }
  13.  
  14. class VM(val program: Seq[Instruction], atomicKarel: AtomicReference[Karel], onCall: (Int, Int) => Unit, onReturn: => Unit, onInfiniteLoop: => Unit) {
  15.  
  16.   private var pc = 256
  17.  
  18.   def PC = pc
  19.  
  20.   def currentInstruction = program(pc)
  21.  
  22.   private var stack = List.empty[Int]
  23.  
  24.   private var callDepth = 0
  25.  
  26.   def getStack = stack
  27.  
  28.   private def push(x: Int) {
  29.     stack = x :: stack
  30.   }
  31.  
  32.   private def pop(): Int = {
  33.     val result = stack.head
  34.     stack = stack.tail
  35.     return result
  36.   }
  37.  
  38.   def stepInto(vmVisible: Boolean) {
  39.     executeUnpausedInstructions(vmVisible)
  40.     executeOneInstruction()
  41.     executeUnpausedInstructions(vmVisible)
  42.   }
  43.  
  44.   def executeUnpausedInstructions(vmVisible: Boolean) {
  45.     while (!currentInstruction.shouldPause(vmVisible)) {
  46.       executeOneInstruction()
  47.     }
  48.   }
  49.  
  50.   def stepOver() {
  51.     if (currentInstruction.category == TAIL) {
  52.       // Tail calls don't grow the stack, so a normal "step over"
  53.       // would resemble a "step into" instead.
  54.       stepUntil(callDepth - 1)
  55.     } else {
  56.       stepUntil(callDepth)
  57.     }
  58.   }
  59.  
  60.   def stepReturn() {
  61.     stepUntil(callDepth - 1)
  62.   }
  63.  
  64.   private def stepUntil(targetDepth: Int) {
  65.     val start = System.nanoTime()
  66.     stepInto(false)
  67.     while ((callDepth > targetDepth) && (System.nanoTime() - start < VM.TIMEOUT)) {
  68.       executeOneInstruction()
  69.     }
  70.     if (callDepth > targetDepth) {
  71.       onInfiniteLoop
  72.     }
  73.   }
  74.  
  75.   def executeOneInstruction() {
  76.     val instruction = currentInstruction
  77.  
  78.     val cat = instruction.category
  79.     cat match {
  80.       case NORM => executeBasicInstruction(instruction.bytecode)
  81.       case PUSH =>
  82.         push(instruction.target)
  83.         pc += 1
  84.       case LOOP =>
  85.         executeLoop(instruction)
  86.       case CALL =>
  87.         // When tail calls are enabled, this will find the first exit
  88.         val leave = program.view.drop(instruction.target).find(_.leaves)
  89.         onCall(instruction.line, leave.getOrElse(program(instruction.target)).line)
  90.         push(pc)
  91.         pc = instruction.target
  92.         callDepth += 1
  93.       case JUMP => pc = instruction.target
  94.       case J0MP =>
  95.         pc = (if (pop() == 0) instruction.target else pc + 1)
  96.       case J1MP =>
  97.         pc = (if (pop() != 0) instruction.target else pc + 1)
  98.       case TAIL => pc = instruction.target
  99.       case illegal =>
  100.         throw new AssertionError("illegal instruction category " + cat.toHexString)
  101.     }
  102.   }
  103.  
  104.   def executeBasicInstruction(bytecode: Int) {
  105.     bytecode match {
  106.       case RETURN =>
  107.         onReturn
  108.         callDepth -= 1
  109.         pc = pop()
  110.       case MOVE_FORWARD =>
  111.         execute(_.moveForward)
  112.       case TURN_LEFT =>
  113.         execute(_.turnLeft)
  114.       case TURN_AROUND =>
  115.         execute(_.turnAround)
  116.       case TURN_RIGHT =>
  117.         execute(_.turnRight)
  118.       case PICK_BEEPER =>
  119.         execute(_.pickBeeper)
  120.       case DROP_BEEPER =>
  121.         execute(_.dropBeeper)
  122.       case ON_BEEPER =>
  123.         query(_.onBeeper)
  124.       case BEEPER_AHEAD =>
  125.         query(_.beeperAhead)
  126.       case LEFT_IS_CLEAR =>
  127.         query(_.leftIsClear)
  128.       case FRONT_IS_CLEAR =>
  129.         query(_.frontIsClear)
  130.       case RIGHT_IS_CLEAR =>
  131.         query(_.rightIsClear)
  132.       case NOT =>
  133.         push(if (pop() == 0) 1 else 0)
  134.       case AND =>
  135.         binaryOperation(_ & _)
  136.       case OR =>
  137.         binaryOperation(_ | _)
  138.       case XOR =>
  139.         binaryOperation(_ ^ _)
  140.       case _ =>
  141.         throw IllegalInstruction(bytecode)
  142.     }
  143.     pc += 1
  144.   }
  145.  
  146.   def execute(f: Karel => Karel) {
  147.     atomicKarel.set(f(karel))
  148.   }
  149.  
  150.   def query(f: Karel => Boolean) {
  151.     push(if (f(karel)) 1 else 0)
  152.   }
  153.  
  154.   def binaryOperation(f: (Int, Int) => Int) {
  155.     push(f(pop(), pop()))
  156.   }
  157.  
  158.   def executeLoop(instruction: Instruction) {
  159.     val x = pop() - 1
  160.     if (x > 0) {
  161.       push(x)
  162.       pc = instruction.target
  163.     } else {
  164.       pc += 1
  165.     }
  166.   }
  167.  
  168.   private def karel = atomicKarel.get()
  169. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement