uniqify :: ([Instruction], SymbolTable) -> Int -> ([Instruction], SymbolTable)
uniqify (code, table) increment =
  let exportedGlobals = M.elems $ M.filter (isInternalVariable . fst) table
      addresses = map snd exportedGlobals
      newAddresses = map (+increment) addresses
      fixedProgram = doRecurse code addresses newAddresses
      newExportedGlobals = map (updateEntry (M.fromList $ zip addresses newAddresses)) exportedGlobals
      names = map (getName . fst) newExportedGlobals
      newTableEntries = M.fromList $ zip names newExportedGlobals
      fixedTable = M.union newTableEntries table
  in (fixedProgram, fixedTable)
  where
    doRecurse code [] [] = code
    doRecurse code old new =
      doRecurse (replaceLoadsAndStores code
                  (B.pack $ show $ head old)
                  (B.pack $ show $ head new))
                (tail old)
                (tail new)

    updateEntry mapping (a, i) = (a, (mapping M.! i))


{-
  The reason we do (tail linkFiles) in here is that we don't want to uniqify
  the first linkFile, because we assume that is the point of origin of the
  increments, so we can't change any addresses in there. We also discard the
  first increment, which is always going to be zero for the same reason.
-}
uniqify :: ([Instruction], SymbolTable) -> Int -> ([Instruction], SymbolTable)
uniqify (code, table) increment =
  let exportedGlobals = M.elems $ M.filter (isInternalVariable . fst) table
      addresses = map snd exportedGlobals
      newAddresses = map (+increment) addresses
      fixedProgram = doRecurse code addresses newAddresses
      newExportedGlobals = map (updateEntry (M.fromList $ zip addresses newAddresses)) exportedGlobals
      names = map (getName . fst) newExportedGlobals
      newTableEntries = M.fromList $ zip names newExportedGlobals
      fixedTable = M.union newTableEntries table
  in (fixedProgram, fixedTable)
  where
    doRecurse code [] [] = code
    doRecurse code old new =
      doRecurse (replaceLoadsAndStores code
                  (B.pack $ show $ head old)
                  (B.pack $ show $ head new))
                (tail old)
                (tail new)

    updateEntry mapping (a, i) = (a, (mapping M.! i))


{-
  The reason we do (tail linkFiles) in here is that we don't want to uniqify
  the first linkFile, because we assume that is the point of origin of the
  increments, so we can't change any addresses in there. We also discard the
  first increment, which is always going to be zero for the same reason.
-}
uniqify (code, table) increment =
  let exportedGlobals = M.elems $ M.filter (isInternalVariable . fst) table
      addresses = map snd exportedGlobals
      newAddresses = map (+increment) addresses
      fixedProgram = doRecurse code addresses newAddresses
      newExportedGlobals = map (updateEntry (M.fromList $ zip addresses newAddresses)) exportedGlobals
      names = map (getName . fst) newExportedGlobals
      newTableEntries = M.fromList $ zip names newExportedGlobals
      fixedTable = M.union newTableEntries table
  in (fixedProgram, fixedTable)
  where
    doRecurse code [] [] = code
    doRecurse code old new =
      doRecurse (replaceLoadsAndStores code
                  (B.pack $ show $ head old)
                  (B.pack $ show $ head new))
                (tail old)
                (tail new)

    updateEntry mapping (a, i) = (a, (mapping M.! i))


{-
  The reason we do (tail linkFiles) in here is that we don't want to uniqify
  the first linkFile, because we assume that is the point of origin of the
  increments, so we can't change any addresses in there. We also discard the
  first increment, which is always going to be zero for the same reason.
-}