matchPointsTos ::
  Options          {- ^ saw script print out opts -} ->
  SharedContext    {- ^ term construction context -} ->
  JVMCrucibleContext  {- ^ simulator context     -}     ->
  CrucibleMethodSpecIR                               ->
  PrePost                                            ->
  [JVMPointsTo]       {- ^ points-tos                -} ->
  OverrideMatcher CJ.JVM w ()
matchPointsTos opts sc cc spec prepost = go False []
  where
    go ::
      Bool       {- progress indicator -} ->
      [JVMPointsTo] {- delayed conditions -} ->
      [JVMPointsTo] {- queued conditions  -} ->
      OverrideMatcher CJ.JVM w ()

    -- all conditions processed, success
    go _ [] [] = return ()

    -- not all conditions processed, no progress, failure
    go False delayed [] = failure (spec ^. MS.csLoc) (AmbiguousPointsTos delayed)

    -- not all conditions processed, progress made, resume delayed conditions
    go True delayed [] = go False [] delayed

    -- progress the next points-to in the work queue
    go progress delayed (c:cs) =
      do ready <- checkPointsTo c
         if ready then
           do learnPointsTo opts sc cc spec prepost c
              go True delayed cs
         else
           do go progress (c:delayed) cs

    -- determine if a precondition is ready to be checked
    checkPointsTo :: JVMPointsTo -> OverrideMatcher CJ.JVM w Bool
    checkPointsTo (JVMPointsToField _loc p _ _) = checkAllocIndex p
    checkPointsTo (JVMPointsToStatic _loc _ _) = pure True
    checkPointsTo (JVMPointsToElem _loc p _ _) = checkAllocIndex p
    checkPointsTo (JVMPointsToArray _loc p _) = checkAllocIndex p

    checkAllocIndex :: AllocIndex -> OverrideMatcher CJ.JVM w Bool
    checkAllocIndex i =
      do m <- OM (use setupValueSub)
         return (Map.member i m)


------------------------------------------------------------------------
matchPointsTos ::
  Options          {- ^ saw script print out opts -} ->
  SharedContext    {- ^ term construction context -} ->
  JVMCrucibleContext  {- ^ simulator context     -}     ->
  CrucibleMethodSpecIR                               ->
  PrePost                                            ->
  [JVMPointsTo]       {- ^ points-tos                -} ->
  OverrideMatcher CJ.JVM w ()
matchPointsTos opts sc cc spec prepost = go False []
  where
    go ::
      Bool       {- progress indicator -} ->
      [JVMPointsTo] {- delayed conditions -} ->
      [JVMPointsTo] {- queued conditions  -} ->
      OverrideMatcher CJ.JVM w ()

    -- all conditions processed, success
    go _ [] [] = return ()

    -- not all conditions processed, no progress, failure
    go False delayed [] = failure (spec ^. MS.csLoc) (AmbiguousPointsTos delayed)

    -- not all conditions processed, progress made, resume delayed conditions
    go True delayed [] = go False [] delayed

    -- progress the next points-to in the work queue
    go progress delayed (c:cs) =
      do ready <- checkPointsTo c
         if ready then
           do learnPointsTo opts sc cc spec prepost c
              go True delayed cs
         else
           do go progress (c:delayed) cs

    -- determine if a precondition is ready to be checked
    checkPointsTo :: JVMPointsTo -> OverrideMatcher CJ.JVM w Bool
    checkPointsTo (JVMPointsToField _loc p _ _) = checkAllocIndex p
    checkPointsTo (JVMPointsToStatic _loc _ _) = pure True
    checkPointsTo (JVMPointsToElem _loc p _ _) = checkAllocIndex p
    checkPointsTo (JVMPointsToArray _loc p _) = checkAllocIndex p

    checkAllocIndex :: AllocIndex -> OverrideMatcher CJ.JVM w Bool
    checkAllocIndex i =
      do m <- OM (use setupValueSub)
         return (Map.member i m)


------------------------------------------------------------------------
matchPointsTos opts sc cc spec prepost = go False []
  where
    go ::
      Bool       {- progress indicator -} ->
      [JVMPointsTo] {- delayed conditions -} ->
      [JVMPointsTo] {- queued conditions  -} ->
      OverrideMatcher CJ.JVM w ()

    -- all conditions processed, success
    go _ [] [] = return ()

    -- not all conditions processed, no progress, failure
    go False delayed [] = failure (spec ^. MS.csLoc) (AmbiguousPointsTos delayed)

    -- not all conditions processed, progress made, resume delayed conditions
    go True delayed [] = go False [] delayed

    -- progress the next points-to in the work queue
    go progress delayed (c:cs) =
      do ready <- checkPointsTo c
         if ready then
           do learnPointsTo opts sc cc spec prepost c
              go True delayed cs
         else
           do go progress (c:delayed) cs

    -- determine if a precondition is ready to be checked
    checkPointsTo :: JVMPointsTo -> OverrideMatcher CJ.JVM w Bool
    checkPointsTo (JVMPointsToField _loc p _ _) = checkAllocIndex p
    checkPointsTo (JVMPointsToStatic _loc _ _) = pure True
    checkPointsTo (JVMPointsToElem _loc p _ _) = checkAllocIndex p
    checkPointsTo (JVMPointsToArray _loc p _) = checkAllocIndex p

    checkAllocIndex :: AllocIndex -> OverrideMatcher CJ.JVM w Bool
    checkAllocIndex i =
      do m <- OM (use setupValueSub)
         return (Map.member i m)


------------------------------------------------------------------------