module Language.ArrayForth.Parse (ParseError (..), isNumber, readWord) where
import           Text.Printf                       (printf)
data ParseError = BadOpcode String
                | NotSlot3 String
                | NotJump String
                | NoAddr String
                | BadNumber String
instance Show ParseError where
  show (BadOpcode op) = printf "Invalid opcode `%s'." op
  show (NotSlot3 op)  = printf "`%s' cannot go into the last slot." op
  show (NotJump op)   =
    printf "`%s' is not a jump instruction and cannot get an address." op
  show (NoAddr op)    = printf "Missing a jump address for `%s'" op
  show (BadNumber n)  = printf "`%s' is not a valid number." n
isNumber :: String -> Bool
isNumber str = let asNumber = reads str :: [(Integer, String)] in
          not (null asNumber) && (null . snd $ head asNumber)
readWord :: Read a => String -> Either ParseError a
readWord str = case reads str of
          (x, _) : _ -> Right x
          []         -> Left $ BadNumber str