module Parse.LexStr(tab,lexStr,lexChr) where

import Char

import Error(errorLC)
import Parse.LexLow

tab :: Int -> Int
tab l = (m*8+1) where m = (l+7)`div`8

lexStr :: Int->Int->[Char] -> (Int,Int,[Char],[Char])
lexStr r c xs = pS '"' (r,c) r c [] xs

lexChr :: Int->Int->[Char] -> (Int,Int,Char,[Char])
lexChr r c xs = case pS '\'' (r,c) r c [] xs of
                (r',c',[ch],xs') -> (r',c',ch,xs')
                (_,_,[] ,_) -> errorLC r c "Empty character literal."
                (_,_,cs ,_) -> errorLC r c ("Character literal with length>1 '"
                                            ++ cs ++ "'.")

---- local


pS :: Char -> (Int,Int) -> Int -> Int -> [Char] -> [Char]
      -> (Int,Int,[Char],[Char])
pS d (ro,co) r c a []  = errorLC ro co "Unterminated literal string/character."
pS d  roco   r c a ('\n':_) = errorLC r c ("Newline in literal string/char."
                                           ++"\nUse \\n instead.")
pS d  roco   r c a ('\t':_) = errorLC r c ("Tab in literal string/char."
                                           ++"\nUse \\t instead.")
pS d  roco   r c a ('\f':_) = errorLC r c ("Linefeed in literal string/char."
                                           ++"\nUse \\f instead.")
pS d  roco   r c a ('\v':_) = errorLC r c ("Vertical tab in literal string/char"
                                           ++".\nUse \\v instead.")
pS d  roco   r c a ('\\':'&':xs) = pS d roco r (c+2) a xs
pS d  roco   r c a ('\\':'a':xs) = pS d roco r (c+2) ('\a':a) xs
pS d  roco   r c a ('\\':'b':xs) = pS d roco r (c+2) ('\b':a) xs
pS d  roco   r c a ('\\':'f':xs) = pS d roco r (c+2) ('\f':a) xs
pS d  roco   r c a ('\\':'n':xs) = pS d roco r (c+2) ('\n':a) xs
pS d  roco   r c a ('\\':'r':xs) = pS d roco r (c+2) ('\r':a) xs
pS d  roco   r c a ('\\':'t':xs) = pS d roco r (c+2) ('\t':a) xs
pS d  roco   r c a ('\\':'v':xs) = pS d roco r (c+2) ('\v':a) xs
pS d  roco   r c a ('\\':'\\':xs) = pS d roco r (c+2) ('\\':a) xs
pS d  roco   r c a ('\\':'"':xs) = pS d roco r (c+2) ('"':a) xs
pS d  roco   r c a ('\\':'\'':xs)= pS d roco r (c+2) ('\'':a) xs
pS d  roco   r c a ('\\':'N':'U':'L':xs) = pS d roco r (c+4) ('\NUL':a) xs
pS d  roco   r c a ('\\':'S':'O':'H':xs) = pS d roco r (c+4) ('\SOH':a) xs
pS d  roco   r c a ('\\':'S':'T':'X':xs) = pS d roco r (c+4) ('\STX':a) xs
pS d  roco   r c a ('\\':'E':'T':'X':xs) = pS d roco r (c+4) ('\ETX':a) xs
pS d  roco   r c a ('\\':'E':'O':'T':xs) = pS d roco r (c+4) ('\EOT':a) xs
pS d  roco   r c a ('\\':'E':'N':'Q':xs) = pS d roco r (c+4) ('\ENQ':a) xs
pS d  roco   r c a ('\\':'A':'C':'K':xs) = pS d roco r (c+4) ('\ACK':a) xs
pS d  roco   r c a ('\\':'B':'E':'L':xs) = pS d roco r (c+4) ('\BEL':a) xs
pS d  roco   r c a ('\\':'B':'S':xs)     = pS d roco r (c+3) ('\BS':a) xs
pS d  roco   r c a ('\\':'H':'T':xs)     = pS d roco r (c+3) ('\HT':a) xs
pS d  roco   r c a ('\\':'L':'F':xs)     = pS d roco r (c+3) ('\LF':a) xs
pS d  roco   r c a ('\\':'V':'T':xs)     = pS d roco r (c+3) ('\VT':a) xs
pS d  roco   r c a ('\\':'F':'F':xs)     = pS d roco r (c+3) ('\FF':a) xs
pS d  roco   r c a ('\\':'C':'R':xs)     = pS d roco r (c+3) ('\CR':a) xs
pS d  roco   r c a ('\\':'S':'O':xs)     = pS d roco r (c+3) ('\SO':a) xs
pS d  roco   r c a ('\\':'S':'I':xs)     = pS d roco r (c+3) ('\SI':a) xs
pS d  roco   r c a ('\\':'D':'L':'E':xs) = pS d roco r (c+4) ('\DLE':a) xs
pS d  roco   r c a ('\\':'D':'C':'1':xs) = pS d roco r (c+4) ('\DC1':a) xs
pS d  roco   r c a ('\\':'D':'C':'2':xs) = pS d roco r (c+4) ('\DC2':a) xs
pS d  roco   r c a ('\\':'D':'C':'3':xs) = pS d roco r (c+4) ('\DC3':a) xs
pS d  roco   r c a ('\\':'D':'C':'4':xs) = pS d roco r (c+4) ('\DC4':a) xs
pS d  roco   r c a ('\\':'N':'A':'K':xs) = pS d roco r (c+4) ('\NAK':a) xs
pS d  roco   r c a ('\\':'S':'Y':'N':xs) = pS d roco r (c+4) ('\SYN':a) xs
pS d  roco   r c a ('\\':'E':'T':'B':xs) = pS d roco r (c+4) ('\ETB':a) xs
pS d  roco   r c a ('\\':'C':'A':'N':xs) = pS d roco r (c+4) ('\CAN':a) xs
pS d  roco   r c a ('\\':'E':'M':xs)     = pS d roco r (c+3) ('\EM':a) xs
pS d  roco   r c a ('\\':'S':'U':'B':xs) = pS d roco r (c+4) ('\SUB':a) xs
pS d  roco   r c a ('\\':'E':'S':'C':xs) = pS d roco r (c+4) ('\ESC':a) xs
pS d  roco   r c a ('\\':'F':'S':xs)     = pS d roco r (c+3) ('\FS':a) xs
pS d  roco   r c a ('\\':'G':'S':xs)     = pS d roco r (c+3) ('\GS':a) xs
pS d  roco   r c a ('\\':'R':'S':xs)     = pS d roco r (c+3) ('\RS':a) xs
pS d  roco   r c a ('\\':'U':'S':xs)     = pS d roco r (c+3) ('\US':a) xs
pS d  roco   r c a ('\\':'S':'P':xs)     = pS d roco r (c+3) ('\SP':a) xs
pS d  roco   r c a ('\\':'D':'E':'L':xs) = pS d roco r (c+4) ('\DEL':a) xs
pS d  roco   r c a ('\\':'^':x:xs) =
      if ox >= 64 && ox <96 then     -- Fusk ?
          pS d roco r (c+3) (toEnum (ox-64):a) xs 
      else
          errorLC r c ("Illegal control character '\\^" ++ [x]
                        ++ "' in string or character literal.")
      where ox = fromEnum x
pS d  roco   r c a ('\\':'o':xs) = pS d roco r c' (toEnum (fromInteger n):a) xs'
      where (c',n,xs') = lexInteger  8 (c+2) xs
pS d  roco   r c a ('\\':'x':xs) = pS d roco r c' (toEnum (fromInteger n):a) xs'
      where (c',n,xs') = lexInteger (8+8) (c+2) xs
pS d  roco   r c a ('\\':' ':xs)  = pS d roco r' c' a xs'
      where (r',c',xs') = pW r (c+2) xs
pS d  roco   r c a ('\\':'\t':xs) = pS d roco r' c' a xs'
      where (r',c',xs') = pW r (tab(c+1)) xs
pS d  roco   r c a ('\\':'\n':xs) = pS d roco r' c' a xs'
      where (r',c',xs') = pW (r+1) 1 xs
pS d  roco   r c a ('\\':x:xs) =
      if isDigit x then
          case lexInteger 10 (c+1) (x:xs) of
                 (c',i,xs') -> pS d roco r c' (toEnum (fromInteger i):a) xs'
      else
          errorLC r c ("Illegal escape character '" ++ x: "'.")
pS d  roco   r c a (x:xs) =
      if d == x then
          (r,c+1,reverse a,xs)
      else
          pS d roco r (c+1) (x:a) xs

pW :: Int -> Int -> [Char] -> (Int,Int,[Char])
pW r c [] =    errorLC r c "End of file in string gap."
pW r c ('\\':xs) = (r,c+1,xs)
pW r c (' ':xs) =  pW r (c+1) xs
pW r c ('\t':xs) = pW r (tab c) xs
pW r c ('\n':xs) = pW (r+1) 1 xs
pW r c ('\f':xs) = pW (r+1) 1 xs
pW r c ('\v':xs) = pW (r+1) 1 xs
pW r c (x:xs) = errorLC r c ("Illegal character in string gap '" ++ x:"'.")


