--
-- Ivory concrete lexemes.
--
-- Copyright (C) 2014, Galois, Inc.
-- All rights reserved.
--

module Ivory.Language.Syntax.Concrete.Lexeme where

import Numeric (readInt)
import Data.Char (digitToInt)

import Ivory.Language.Syntax.Concrete.Location

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

type Lexeme = Located Token

-- | Token types
data Token =
    TokInteger Integer
  | TokFloat Double -- represents floats and doubles
  | TokString String
  | TokHex Integer
  | TokBitLit (Integer, Integer) -- width, value (e.g., 5b0101)
  | TokIdent String
  | TokTyIdent String
  | TokReserved String
  | TokSym String
  | TokBrack String
  | TokSep String
  | TokEOF
  | TokError String
  deriving (Show, Read, Eq)

readBitLit :: String -> Token
readBitLit s =
  let (width, val) = break (== 'b') s in
  let w = case reads width of
            [(i,"")] -> i
            _        -> error $ "Lex error on bitWidth " ++ width
  in
  TokBitLit (w, readBin (tail val))

-- If Alex calls readBin, a lex error should be impossible.
readBin :: (Show a, Eq a, Num a) => String -> a
readBin s =
  case readInt 2 (`elem` "01") digitToInt s of
    [(v,"")] -> v
    ls       -> error $ "Impossible lex error on binary integer " ++ show ls

readInteger :: String -> Token
readInteger s = case reads s of
  [(i,"")] -> TokInteger i
  _        -> error $ "Lex error on integer " ++ s

readFloat :: String -> Token
readFloat s = case reads s of
  [(f,"")] -> TokFloat f
  _        -> error $ "Lex error on float " ++ s

readStringLit :: String -> Token
readStringLit s = case reads s of
  [(s',"")] -> TokString s'
  _         -> error $ "Lex error on string " ++ s