packages feed

hjs-0.1: src/HJS/Parser/LexerM.hs

{-

     The Monadic Lexer.
     Provides a monadic wrapper around the Alex lexer and handles nasties

-}

module HJS.Parser.LexerM(lexer,lexerM,autoSemiInsert) where

import Data.Char
import qualified Data.ByteString.Char8 as BS
import Control.Monad.State
import Control.Monad.Error
import Debug.Trace

import HJS.Parser.ParserMonad
import HJS.Parser.Lexer
import HJS.Parser.Regex

-- Cut down lexer for parsing comments. Cannot just skip over as we want to count the lines
lexerComment :: (Token -> P a) -> P a
lexerComment cont  = do
                       st  <- get 
                       case (rest st) of 
                         ('\n':cs) -> do put st { rest = cs, lineno = 1 + (lineno st) }; lexerComment cont
                         ('*':'/':cs) -> do put st { rest = cs }; lexerM 0 cont
                         (_:cs) ->  do put st { rest = cs}; lexerComment cont



lexerM :: Int -> (Token -> P a) -> P a
lexerM action cont = do
                  st <- get
                  put st { nl = False }
                  case action of 
                        46 -> case parseRegex ('/':(rest st)) of 
                                                    Left s -> throwError s
                                                    Right (s,r) -> do  
								     put st { rest = r, lastToken=Just $ TokenRegex ""}
                                                                     cont (TokenRegex s)
                        _ -> lexerM' action cont
 {-                 case expectRegex st && ((lastToken st) == (Just $ TokenROP "/")) of
                        True -> do 
                                                  case parseRegex ('/':(rest st)) of 
                                                    Left s -> throwError s
                                                    Right (s,r) -> do  
                                                          put st { rest = r, lastToken=Just $ TokenRegex ""}
                                                          cont (TokenRegex s)
                        False -> lexerM' cont -}
 


lexerM' :: Int -> (Token -> P a) -> P a
lexerM' action cont = do
                   st <- get
                   case (rest st) of 
                            ('\n':cs) -> do put st { rest = cs, lineno = 1 + (lineno st),nl=True }; lexerM' 0 cont
                            ('/':'*':cs) -> do put st { rest = cs }; lexerComment cont
                            _ -> do let (token, cs) = lexer (rest st) 
                                    put st { rest=cs,rest2= (rest st),lastToken= Just token }
                                    cont token

lexerRegex :: String -> (Token,String)
lexerRegex s = case span (\c -> c /= '/') s of 
                       (regex, rest) -> (TokenRegex regex, rest)

lexer :: String -> (Token,String)
lexer str =  go ('\n',str)
  where go inp@(_,str) =
          case alexScan inp 0 of
                AlexEOF -> (TokenEof, [])
                AlexError (c,cs) -> error ("lexical error on " ++ cs)
                AlexSkip  inp' len     -> go inp'
                AlexToken inp'@(c,cs) len act -> case act (take len str) of 
                                               TokenWhite -> go inp'
                                               tok -> (tok, cs)



-- Handle automatic semicolon insertion. This will get passed the current 
-- lookahead token which will get discard so even if we have found a ';' we
-- need to put it backonto the stream so that it gets found again.
-- autoSemiInsert :: Token -> String -> P String
autoSemiInsert tok res = do 
		   s <- get 
	           case tok == (TokenROP ";") || tok == (TokenROP "}" ) || (nl s) of 
                      True -> do 
                                 let r = if tok == (TokenROP ";") then 
                                               rest2 s
                                         else (';':(rest2 s))
                                 put s { rest= r }
                                 return res
		      _ -> throwError $ "Expecting Semi or NL " ++ (show tok) ++ (show s)


showToken tok = do
		  Debug.Trace.trace ("Token is " ++ (show tok)) ""