Advertisement
Guest User

Untitled

a guest
Dec 16th, 2014
60
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Scala 4.00 KB | None | 0 0
  1. package detective
  2.  
  3. import scala.collection.mutable.ArrayBuffer
  4. import scala.collection.mutable.HashMap
  5. import scala.collection.mutable.HashSet
  6.  
  7. import Knowledge._
  8. import parsing._
  9.  
  10. class Detective(semantics: KarelSemantics) {
  11.  
  12.   private val visited = new HashSet[Def]
  13.   private val postcondition = new HashMap[Def, Knowledge]
  14.  
  15.   private var hints = new ArrayBuffer[Diagnostic]
  16.  
  17.   private def warnAbout(msg: String, node: Node) {
  18.     hints += Diagnostic(node.pos, msg, 2)
  19.   }
  20.  
  21.   private def stopWithBug(msg: String, node: Node): Knowledge = {
  22.     hints += new Diagnostic(node.pos, msg, 1)
  23.     CONTRADICTION
  24.   }
  25.  
  26.   val result: Seq[Diagnostic] = {
  27.     semantics.defs.values.foreach(check)
  28.     hints.sortWith(_.pos < _.pos)
  29.   }
  30.  
  31.   private def check(deF: Def): Knowledge = postcondition.getOrElseUpdate(deF, {
  32.     if (visited.add(deF)) {
  33.       check(deF.body, TAUTOLOGY)
  34.     } else {
  35.       // TODO How do we deal with recursive calls?
  36.       TAUTOLOGY
  37.     }
  38.   })
  39.  
  40.   private def check(block: Block, initial: Knowledge): Knowledge = {
  41.     var knowledge = initial
  42.     for (statement <- block.statements) {
  43.       if (knowledge == CONTRADICTION) {
  44.         warnAbout("dead code", statement)
  45.         return CONTRADICTION
  46.       }
  47.       knowledge = check(statement, knowledge)
  48.     }
  49.     knowledge
  50.   }
  51.  
  52.   private def check(statement: Statement, above: Knowledge): Knowledge = statement match {
  53.  
  54.     case x @ Call("moveForward") =>
  55.       if (above implies FRONT_IS_BLOCKED) stopWithBug("cannot move through wall", x)
  56.       else above.moveForward
  57.  
  58.     case Call("turnLeft") =>
  59.       above.turnLeft
  60.     case Call("turnAround") =>
  61.       above.turnAround
  62.     case Call("turnRight") =>
  63.       above.turnRight
  64.  
  65.     case x @ Call("pickBeeper") =>
  66.       if (above implies NO_BEEPER) stopWithBug("there is no beeper to pick", x)
  67.       else above.pickBeeper
  68.  
  69.     case x @ Call("dropBeeper") =>
  70.       if (above implies ON_BEEPER) stopWithBug("cannot drop another beeper", x)
  71.       else above.dropBeeper
  72.  
  73.     // TODO How do we deal with preconditions?
  74.     // Should we simply check each function again for each client?
  75.     // That would probably require a static "stack trace" to be readable.
  76.     // TODO Recursive functions yield TAUTOLOGY as of now;
  77.     // Can we do better for tail-recursive functions?
  78.     case Call(target) => check(semantics.defs(target))
  79.  
  80.     case x @ IfThen(condition, th3n) =>
  81.       val p = learn(condition)
  82.       if (above implies p) {
  83.         warnAbout("condition is always true", x)
  84.         check(th3n, above)
  85.       } else if (above implies !p) {
  86.         warnAbout("condition is always false", x)
  87.         above
  88.       } else {
  89.         check(th3n, above && p) || (above && !p)
  90.       }
  91.  
  92.     case x @ IfThenElse(condition, th3n, e1se) =>
  93.       val p = learn(condition)
  94.       if (above implies p) {
  95.         warnAbout("condition is always true", x)
  96.         check(th3n, above)
  97.       } else if (above implies !p) {
  98.         warnAbout("condition is always false", x)
  99.         check(e1se, above)
  100.       } else {
  101.         check(th3n, above && p) || check(e1se, above && !p)
  102.       }
  103.  
  104.     case x @ While(condition, body) =>
  105.       val p = learn(condition)
  106.       if (above implies !p) {
  107.         warnAbout("loop is never entered", x)
  108.         above
  109.       } else if (check(body, p) implies p) {
  110.         stopWithBug("infinite loop", x)
  111.       } else {
  112.         !p
  113.       }
  114.  
  115.     case Repeat(times, body) =>
  116.       Stream.iterate(above)(check(body, _)).drop(times).head
  117.   }
  118.  
  119.   private def learn(condition: Condition): Knowledge = condition match {
  120.  
  121.     case False() => CONTRADICTION
  122.     case True() => TAUTOLOGY
  123.  
  124.     case OnBeeper() => ON_BEEPER
  125.     case BeeperAhead() => BEEPER_AHEAD
  126.     case FrontIsClear() => FRONT_IS_CLEAR
  127.     case LeftIsClear() => LEFT_IS_CLEAR
  128.     case RightIsClear() => RIGHT_IS_CLEAR
  129.  
  130.     case Not(_, p) => !learn(p)
  131.     case Conjunction(p, _, q) => learn(p) && learn(q)
  132.     case Disjunction(p, _, q) => learn(p) || learn(q)
  133.     case Parenthesized(p) => learn(p)
  134.   }
  135. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement