packages feed

ecma262-0.0.0: src/Language/JavaScript/Lexer.hs

{-# LANGUAGE FlexibleContexts,
             RankNTypes #-}

module Language.JavaScript.Lexer
       where

import Control.Applicative ((<$>), (<*))
import Control.Monad (void)

import Data.Char
import Data.Maybe (mapMaybe)

import Text.Parsec ((<|>),
                    SourcePos,
                    anyChar, choice, getPosition, many,
                    notFollowedBy, optionMaybe, runParser,
                    satisfy, skipMany1, string, try)
import Text.Parsec.Char (char, oneOf)
import Text.Parsec.Prim (ParsecT, Stream,
                         getState, modifyState)
import Text.Parsec.Token (GenLanguageDef(..), LanguageDef)
import Text.ParserCombinators.Parsec.Prim (GenParser)

import Language.JavaScript.AST

javaScript :: LanguageDef TokenState
javaScript = LanguageDef {
  commentStart = "/*",
  commentEnd = "*/",
  commentLine = "//",
  nestedComments = False,
  identStart = identifierStart,
  identLetter = identifierPart,
  opStart = oneOf "!%&( )*,-.:;<=>?[ ]^{|}~",
  opLetter = oneOf "=+-<>&|",
  reservedNames =
    [ "break", "case", "catch", "continue", "debugger", "default"
    , "delete", "do", "else", "finally", "for", "function", "if"
    , "in" , "instanceof", "new", "return", "this", "throw", "try"
    , "typeof", "var", "void", "while", "with"
    , "class", "const", "enum", "export", "extends", "import", "super"
    , "implements", "interface", "let", "package", "private", "protected"
    , "public", "static", "yield"
    , "null", "true", "false" ],
  reservedOpNames =
    [ "{", "}", "(", ")", "[", "]", ".", ";", ",", "<", ">", "<="
    , ">=", "==", "!=", "===", "!==", "+", "-", "*", "%", "++", "--"
    , "<<", ">>", ">>>", "&", "|", "^", "!", "~", "&&", "||", "?", ":"
    , "=", "+=", "-=", "*=", "%=", "<<=", ">>=", ">>>=", "&=", "|=", "^=" ],
  caseSensitive = True }

data InputElement
  = InputElementIdentName IdentName
  | InputElementLiteral Literal
  | InputElementPunctuator Punctuator
  | InputElementLineTerminator
  deriving (Eq, Show)

data InputElementDiv
  = InputElementDivWhiteSpace
  | InputElementDivLineTerminator
  | InputElementDivComment Comment
  | InputElementDivToken Token
  | InputElementDivDivPunctuator DivPunctuator
  deriving (Eq, Show)

data InputElementRegExp
  = InputElementRegExpWhiteSpace
  | InputElementRegExpLineTerminator
  | InputElementRegExpComment Comment
  | InputElementRegExpToken Token
  | InputElementRegExpRegExpLit RegExpLit
  deriving (Eq, Show)

data Comment
  = CommentMultiLine String
  | CommentSingleLine String
  deriving (Eq, Show)

data Token
  = TokenIdentName IdentName
  | TokenPunctuator Punctuator
  | TokenNumLit NumLit
  | TokenStringLit StringLit
  deriving (Eq, Show)

data Punctuator
  = Punctuator String
  deriving (Eq, Show)

data DivPunctuator
  = DivPunctuator String
  deriving (Eq, Show)

applyRest :: Stream s m t =>
             ParsecT s u m (b -> ParsecT s u m b) -> b -> ParsecT s u m b
applyRest pr a = do
  mr <- optionMaybe $ try pr
  case mr of
   Just r -> r a
   Nothing -> return a

data TokenState
  = TokenState
    { tokenStateLeadingDivAllowed :: Bool }

type TokenParser st a = GenParser Char st a
type TokenSTParser a = GenParser Char TokenState a

newTokenState :: TokenState
newTokenState = TokenState {
  tokenStateLeadingDivAllowed = False }

isLeadingDivAllowed :: TokenSTParser Bool
isLeadingDivAllowed = do
  s <- getState
  return $ tokenStateLeadingDivAllowed s

setLeadingDivAllowed :: TokenSTParser ()
setLeadingDivAllowed =
  modifyState $ \s -> s { tokenStateLeadingDivAllowed = True }

setLeadingDivDisallowed :: TokenSTParser ()
setLeadingDivDisallowed =
  modifyState $ \s -> s { tokenStateLeadingDivAllowed = False }

sourceCharacter :: TokenParser st Char
sourceCharacter = anyChar

inputElementDiv :: TokenSTParser InputElementDiv
inputElementDiv =
  do { void whiteSpace; return InputElementDivWhiteSpace } <|>
  do { void lineTerminator; return InputElementDivLineTerminator } <|>
  do { c <- comment; return $ InputElementDivComment c } <|>
  do { t <- token; return $ InputElementDivToken t } <|>
  do { p <- divPunctuator; return $ InputElementDivDivPunctuator p }

inputElementRegExp :: TokenSTParser InputElementRegExp
inputElementRegExp =
  do { void whiteSpace; return InputElementRegExpWhiteSpace } <|>
  do { void lineTerminator; return InputElementRegExpLineTerminator } <|>
  do { c <- comment; return $ InputElementRegExpComment c } <|>
  do { t <- token; return $ InputElementRegExpToken t } <|>
  do { re <- regularExpressionLiteral; return $ InputElementRegExpRegExpLit re }

whiteSpace :: Stream String m Char => ParsecT [Char] u m Char
whiteSpace =
  do { choice $ char <$>
       [ '\x0009', '\x000B'
       , '\x000C', '\x0020'
       , '\x00A0', '\xFEFF' ] } <|>
  satisfy (\c -> generalCategory c == Space)

lineTerminator :: TokenParser st Char
lineTerminator =
  choice $ char <$>
  [ '\x000A', '\x000D'
  , '\x2028', '\x2029' ]

lineTerminatorSequence :: TokenParser st ()
lineTerminatorSequence =
  skipMany1 $ choice
  [ void $ char '\x000A'
  , void $ try $ do { void $ char '\x000D'; (notFollowedBy $ char '\x000A') }
  , void $ char '\x2028', void $ char '\x2029'
  , void $ string "\x000D\x000A" ]

comment :: TokenParser st Comment
comment =
  multiLineComment <|>
  singleLineComment

multiLineComment :: TokenParser st Comment
multiLineComment =
  do { void . try $ string "/*"; ms <- optionMaybe multiLineCommentChars; void $ string "*/";
       case ms of
       Nothing -> return $ CommentMultiLine ""
       Just s -> return $ CommentMultiLine s }

multiLineCommentChars :: TokenParser st String
multiLineCommentChars =
  do { c <- multiLineNotAsteriskChar; ms <- optionMaybe multiLineCommentChars;
       case ms of
        Nothing -> return [c]
        Just s -> return $ c:s } <|>
  do { c <- try $ do { char '*' <* notFollowedBy (char '/') }; ms <- optionMaybe postAsteriskCommentChars;
       case ms of
        Nothing -> return [c]
        Just s -> return $ c:s }

postAsteriskCommentChars :: TokenParser st String
postAsteriskCommentChars =
  do { c <- multiLineNotForwardSlashOrAsteriskChar; ms <- optionMaybe multiLineCommentChars;
       case ms of
        Nothing -> return [c]
        Just s -> return $ c:s } <|>
  do { c <- char '*'; ms <- optionMaybe postAsteriskCommentChars;
       case ms of
        Nothing -> return [c]
        Just s -> return $ c:s }

multiLineNotAsteriskChar :: TokenParser st Char
multiLineNotAsteriskChar =
  do { notFollowedBy $ char '*'; sourceCharacter }

multiLineNotForwardSlashOrAsteriskChar :: TokenParser st Char
multiLineNotForwardSlashOrAsteriskChar =
  do { notFollowedBy $ char '/' <|> char '*'; sourceCharacter }

singleLineComment :: TokenParser st Comment
singleLineComment =
  do { void . try $ string "//"; ms <- optionMaybe singleLineCommentChars;
       case ms of
        Nothing -> return $ CommentSingleLine ""
        Just s -> return $ CommentSingleLine s }

singleLineCommentChars :: TokenParser st String
singleLineCommentChars =
  do { c <- singleLineCommentChar; ms <- optionMaybe singleLineCommentChars;
       case ms of
        Nothing -> return [c]
        Just s -> return $ c:s }

singleLineCommentChar :: TokenParser st Char
singleLineCommentChar =
  do { notFollowedBy lineTerminator; sourceCharacter }

token :: TokenSTParser Token
token =
  do { i <- identifierName; return $ TokenIdentName i } <|>
  do { p <- punctuator; return $ TokenPunctuator p } <|>
  do { n <- numericLiteral; setLeadingDivAllowed; return $ TokenNumLit n } <|>
  do { s <- stringLiteral; setLeadingDivAllowed; return $ TokenStringLit s }

identifier :: TokenSTParser Ident
identifier =
  do { notFollowedBy reservedWord; i <- identifierName; setLeadingDivAllowed; return $ Ident i; }

identifierName :: TokenSTParser IdentName
identifierName =
  do { c <- identifierStart; applyRest identifierNameRest $ IdentName [c];  }

identifierNameRest :: TokenSTParser (IdentName -> TokenSTParser IdentName)
identifierNameRest =
  do { c <- identifierPart; return $ \(IdentName s) -> applyRest identifierNameRest (IdentName $ s ++ [c]) }

identifierStart :: TokenSTParser Char
identifierStart =
  unicodeLetter <|>
  char '$' <|>
  char '_' <|>
  do { void $ char '\\'; unicodeEscapeSequence }

identifierPart :: TokenSTParser Char
identifierPart =
  identifierStart <|>
  unicodeCombiningMark <|>
  unicodeDigit <|>
  unicodeConnectorPunctuation <|>
  char '\x200C' <|>
  char '\x200D'

unicodeLetter :: TokenParser st Char
unicodeLetter =
  satisfy $ \c -> let cat = generalCategory c in
                   cat == UppercaseLetter ||
                   cat == LowercaseLetter ||
                   cat == TitlecaseLetter ||
                   cat == ModifierLetter ||
                   cat == OtherLetter ||
                   cat == LetterNumber

unicodeCombiningMark :: TokenParser st Char
unicodeCombiningMark =
  satisfy $ \c -> let cat = generalCategory c in
                   cat == NonSpacingMark ||
                   cat == SpacingCombiningMark

unicodeDigit :: TokenParser st Char
unicodeDigit =
  satisfy $ \c -> let cat = generalCategory c in
                   cat == DecimalNumber

unicodeConnectorPunctuation :: TokenParser st Char
unicodeConnectorPunctuation =
  satisfy $ \c -> let cat = generalCategory c
                  in cat == ConnectorPunctuation

reservedWord :: TokenParser st ()
reservedWord =
  void keyword <|>
  void futureReservedWord <|>
  void nullLiteral <|>
  void booleanLiteral

keyword :: TokenParser st String
keyword =
  choice $ try . string <$>
  [ "break", "case", "catch", "continue", "debugger", "default", "delete"
  , "do", "else", "finally", "for", "function", "if", "in"
  , "instanceof", "new", "return", "this", "throw", "try"
  , "typeof", "var", "void", "while", "with" ]

futureReservedWord :: TokenParser st String
futureReservedWord =
  choice $ try . string <$>
  [ "class", "const", "enum", "export", "extends", "import", "super"
  , "implements", "interface", "let", "package", "private", "protected"
  , "public", "static", "yield" ]

punctuator :: TokenSTParser Punctuator
punctuator = do
  p <- choice $ try . string <$>
       [ "~", "}", "||", "|=", "|", "{"
       , "^=", "^", "]", "[", "?", ">>>="
       , ">>>", ">>=", ">>", ">=", ">", "==="
       , "==", "=", "<=", "<<=", "<<", "<"
       , ";", ":", ".", "-=", "--", "-", ","
       , "+=", "++", "+", "*=", "*", ")", "("
       , "&=", "&&", "&", "%=", "%", "!==", "!=", "!" ]
  if p `elem` ["]", "--", "++", ")"]
    then setLeadingDivAllowed
    else setLeadingDivDisallowed
  return $ Punctuator p

divPunctuator :: TokenSTParser DivPunctuator
divPunctuator = do
  dp <- try (string "/=") <|> string "/"
  setLeadingDivDisallowed
  return $ DivPunctuator dp

literal :: TokenSTParser Literal
literal =
  do { n <- nullLiteral; setLeadingDivAllowed; return $ LiteralNull n } <|>
  do { b <- booleanLiteral; setLeadingDivAllowed; return $ LiteralBool b } <|>
  do { n <- numericLiteral; setLeadingDivAllowed; setLeadingDivAllowed; return $ LiteralNum n } <|>
  do { s <- stringLiteral; setLeadingDivAllowed; return $ LiteralString s } <|>
  do { r <- regularExpressionLiteral; return $ LiteralRegExp r }

nullLiteral :: TokenParser st NullLit
nullLiteral =
  do { void $ string "null"; return NullLit }

booleanLiteral :: TokenParser st BoolLit
booleanLiteral =
  do { void $ string "true"; return $ BoolLit True } <|>
  do { void $ string "false"; return $ BoolLit False }

numericLiteral :: TokenParser st NumLit
numericLiteral =
  do { mv <- hexIntegerLiteral; return $ NumLit $ fromIntegral mv } <|>
  do { mv <- decimalLiteral; return $ NumLit mv }

decimalLiteral :: TokenParser st Double
decimalLiteral =
  do { mv <- try $ do { decimalIntegerLiteral <* char '.' };
       mdv <- optionMaybe decimalDigits; mev <- optionMaybe exponentPart;
       case mdv of
        Nothing -> do
          case mev of
           Nothing -> return $ fromIntegral mv
           Just ev -> return $ (fromIntegral mv) * 10 ^^ ev
        Just (dv, n) -> do
          case mev of
           Nothing ->
             return $ (fromIntegral mv) + (fromIntegral dv) * 10 ^^ (-n)
           Just ev ->
             return $ ((fromIntegral mv) + (fromIntegral dv) * 10 ^^ (-n)) * 10 ^^ ev } <|>
  do { void $ char '.'; (mv, n) <- decimalDigits; mev <- optionMaybe exponentPart;
       case mev of
        Nothing ->
          return $ (fromIntegral mv) * 10 ^^ (-n)
        Just ev -> do
          return $ (fromIntegral mv) * 10 ^^ (ev - n) } <|>
  do { mv <- decimalIntegerLiteral; mev <- optionMaybe exponentPart;
       case mev of
        Nothing -> return $ fromIntegral mv
        Just ev -> return $ (fromIntegral mv) * 10 ^^ ev }

decimalIntegerLiteral :: TokenParser st Int
decimalIntegerLiteral =
  do { void $ char '0'; return 0 } <|>
  do { mv <- nonZeroDigit; mdv <- optionMaybe decimalDigits;
       case mdv of
        Nothing -> return mv
        Just (dv, n) -> do
          return $ mv * 10 ^ n + dv }

decimalDigits :: TokenParser st (Int, Int)
decimalDigits =
  do { dv <- decimalDigit; applyRest decimalDigitsRest (dv, 1) }

decimalDigitsRest :: TokenParser st ((Int, Int) -> TokenParser st (Int, Int))
decimalDigitsRest =
  do { dv <- decimalDigit; return $ \(mv, n) -> applyRest decimalDigitsRest (mv * 10 + dv, n + 1) }

decimalDigit :: TokenParser st Int
decimalDigit =
  do { void $ char '0'; return 0 } <|>
  do { void $ char '1'; return 1 } <|>
  do { void $ char '2'; return 2 } <|>
  do { void $ char '3'; return 3 } <|>
  do { void $ char '4'; return 4 } <|>
  do { void $ char '5'; return 5 } <|>
  do { void $ char '6'; return 6 } <|>
  do { void $ char '7'; return 7 } <|>
  do { void $ char '8'; return 8 } <|>
  do { void $ char '9'; return 9 }

nonZeroDigit :: TokenParser st Int
nonZeroDigit =
  do { void $ char '1'; return 1 } <|>
  do { void $ char '2'; return 2 } <|>
  do { void $ char '3'; return 3 } <|>
  do { void $ char '4'; return 4 } <|>
  do { void $ char '5'; return 5 } <|>
  do { void $ char '6'; return 6 } <|>
  do { void $ char '7'; return 7 } <|>
  do { void $ char '8'; return 8 } <|>
  do { void $ char '9'; return 9 }

exponentPart :: TokenParser st Int
exponentPart =
  do { void $ exponentIndicator; mv <- signedInteger; return mv }

exponentIndicator :: TokenParser st Char
exponentIndicator =
  char 'e' <|> char 'E'

signedInteger :: TokenParser st Int
signedInteger =
  do { (mv, _) <- decimalDigits; return mv } <|>
  do { void $ char '+'; (mv, _) <- decimalDigits; return mv } <|>
  do { void $ char '-'; (mv, _) <- decimalDigits; return (-mv) }

hexIntegerLiteral :: TokenParser st Int
hexIntegerLiteral =
  do { try (void $ string "0x") <|> try (void $ string "0X"); applyRest hexIntegerLiteralRest 0 }

hexIntegerLiteralRest :: TokenParser st (Int -> TokenParser st Int)
hexIntegerLiteralRest =
  do { dv <- hexDigit; return $ \mv -> applyRest hexIntegerLiteralRest (mv * 16 + dv) }

hexDigit :: TokenParser st Int
hexDigit =
  do { void $ char '0'; return 0 } <|>
  do { void $ char '1'; return 1 } <|>
  do { void $ char '2'; return 2 } <|>
  do { void $ char '3'; return 3 } <|>
  do { void $ char '4'; return 4 } <|>
  do { void $ char '5'; return 5 } <|>
  do { void $ char '6'; return 6 } <|>
  do { void $ char '7'; return 7 } <|>
  do { void $ char '8'; return 8 } <|>
  do { void $ char '9'; return 9 } <|>
  do { void $ char 'a' <|> char 'A'; return 10 } <|>
  do { void $ char 'b' <|> char 'B'; return 11 } <|>
  do { void $ char 'c' <|> char 'C'; return 12 } <|>
  do { void $ char 'd' <|> char 'D'; return 13 } <|>
  do { void $ char 'e' <|> char 'E'; return 14 } <|>
  do { void $ char 'f' <|> char 'F'; return 15 }

stringLiteral :: TokenParser st StringLit
stringLiteral =
  do { void $ char '"'; msv <- optionMaybe doubleStringCharacters; void $ char '"';
       case msv of
        Nothing -> return $ StringLit ""
        Just sv -> return $ StringLit sv } <|>
  do { void $ char '\''; msv <- optionMaybe singleStringCharacters; void $ char '\'';
       case msv of
        Nothing -> return $ StringLit ""
        Just sv -> return $ StringLit sv }

doubleStringCharacters :: TokenParser st String
doubleStringCharacters =
  do { cv <- doubleStringCharacter; msv <- optionMaybe doubleStringCharacters;
       case msv of
        Nothing -> return cv
        Just sv -> return $ cv ++ sv }

singleStringCharacters :: TokenParser st String
singleStringCharacters =
  do { cv <- singleStringCharacter; msv <- optionMaybe singleStringCharacters;
       case msv of
        Nothing -> return cv
        Just sv -> return $ cv ++ sv}

doubleStringCharacter :: TokenParser st String
doubleStringCharacter =
  do { notFollowedBy $ char '"' <|> char '\\' <|> lineTerminator; c <- sourceCharacter; return [c] } <|>
  do { void $ char '\\'; c <- escapeSequence; return [c] } <|>
  do { void $ lineContinuation; return "" }

singleStringCharacter :: TokenParser st String
singleStringCharacter =
  do { notFollowedBy $ char '\'' <|> char '\\' <|> lineTerminator; c <- sourceCharacter; return [c] } <|>
  do { void $ char '\\'; c <- escapeSequence; return [c] } <|>
  do { void $ lineContinuation; return "" }

lineContinuation :: TokenParser st String
lineContinuation =
  do { void $ char '\\'; lineTerminatorSequence; return "" }

escapeSequence :: TokenParser st Char
escapeSequence =
  characterEscapeSequence <|>
  do { void $ char '0'; notFollowedBy decimalDigit; return '\0' } <|>
  hexEscapeSequence <|>
  unicodeEscapeSequence

characterEscapeSequence :: TokenParser st Char
characterEscapeSequence =
  do { ec <- singleEscapeCharacter;
       case ec of
        'b'  -> return '\x0008'
        't'  -> return '\x0009'
        'n'  -> return '\x000A'
        'v'  -> return '\x000B'
        'f'  -> return '\x000C'
        'r'  -> return '\x000D'
        '"'  -> return '\x0022'
        '\'' -> return '\x0027'
        '\\' -> return '\x005C'
        _ -> error "panic" {- This Should never happen! -} } <|>
  nonEscapeCharacter

singleEscapeCharacter :: TokenParser st Char
singleEscapeCharacter =
  choice $ char <$>
  [ '\'', '"', '\\', 'b', 'f', 'n', 'r', 't', 'v' ]

nonEscapeCharacter :: TokenParser st Char
nonEscapeCharacter =
  do { notFollowedBy $ escapeCharacter <|> void lineTerminator; sourceCharacter }

escapeCharacter :: TokenParser st ()
escapeCharacter =
  void singleEscapeCharacter <|>
  void decimalDigit <|>
  void (char 'x') <|>
  void (char 'u')

hexEscapeSequence :: TokenParser st Char
hexEscapeSequence =
  do { void $ char 'x'; mv1 <- hexDigit; mv2 <- hexDigit;
       return $ chr $ 16 * mv1 + mv2 }

unicodeEscapeSequence :: TokenParser st Char
unicodeEscapeSequence =
  do { void $ char 'u'; mv1 <- hexDigit; mv2 <- hexDigit; mv3 <- hexDigit; mv4 <- hexDigit;
       return $ chr $ 4096 * mv1 + 256 * mv2 + 16 * mv3 + mv4 }

regularExpressionLiteral :: TokenSTParser RegExpLit
regularExpressionLiteral =
  do { void $ char '/'; pattern <- regularExpressionBody; void $ char '/'; flags <- regularExpressionFlags;
       return $ RegExpLit (pattern, flags) }

regularExpressionBody :: TokenParser st String
regularExpressionBody =
  do { c <- regularExpressionFirstChar; s <- regularExpressionChars; return $ c ++ s }

regularExpressionChars :: TokenParser st String
regularExpressionChars =
  do { c <- regularExpressionChar; s <- regularExpressionChars; return $ c ++ s } <|>
  return ""

regularExpressionFirstChar :: TokenParser st String
regularExpressionFirstChar =
  do { notFollowedBy $ char '*' <|> char '\\' <|> char '/' <|> char '['; c <- regularExpressionNonTerminator;
       return [c] } <|>
  do { c <- regularExpressionBackslashSequence; return [c] } <|>
  regularExpressionClass

regularExpressionChar :: TokenParser st String
regularExpressionChar =
  do { notFollowedBy $ char '\\' <|> char '/' <|> char '['; c <- regularExpressionNonTerminator;
       return [c] } <|>
  do { c <- regularExpressionBackslashSequence; return [c] } <|>
  regularExpressionClass

regularExpressionBackslashSequence :: TokenParser st Char
regularExpressionBackslashSequence =
  do { void $ char '\\'; regularExpressionNonTerminator }

regularExpressionNonTerminator :: TokenParser st Char
regularExpressionNonTerminator =
  do { notFollowedBy lineTerminator; sourceCharacter }

regularExpressionClass :: TokenParser st String
regularExpressionClass =
  do { void $ char '['; s <- regularExpressionClassChars; void $ char ']'; return s }

regularExpressionClassChars :: TokenParser st String
regularExpressionClassChars =
  do { c <- regularExpressionClassChar; s <- regularExpressionClassChars; return $ c:s } <|>
  return ""

regularExpressionClassChar :: TokenParser st Char
regularExpressionClassChar =
  do { notFollowedBy $ char ']' <|> char '\\';  regularExpressionNonTerminator } <|>
  regularExpressionBackslashSequence

regularExpressionFlags :: TokenSTParser String
regularExpressionFlags =
  do { c <- identifierPart; s <- regularExpressionFlags; return $ c:s } <|>
  return ""

lexer :: TokenSTParser [(SourcePos, InputElement)]
lexer = (mapMaybe toInputElement) <$>
        (many $ do
            p <- getPosition;
            da <- isLeadingDivAllowed
            edr <- if da
                   then Left <$> inputElementDiv
                   else Right <$> inputElementRegExp
            return (p, edr))
  where
    isLineTerminator c = c `elem` [ '\x000A', '\x000D', '\x2028', '\x2029' ]
    toInputElement (p, edr) = do
      case edr of
       Left ied -> toInputElementDiv (p, ied)
       Right ier -> toInputElementRegExp (p, ier)
    toInputElementDiv (p, ied) =
      case ied of
       InputElementDivWhiteSpace -> Nothing
       InputElementDivLineTerminator ->
         Just (p, InputElementLineTerminator)
       InputElementDivComment (CommentSingleLine _) ->
         Nothing
       InputElementDivComment (CommentMultiLine s)
         | any isLineTerminator s -> Just (p, InputElementLineTerminator)
         | otherwise -> Nothing
       InputElementDivToken (TokenIdentName i) ->
         Just (p, InputElementIdentName i)
       InputElementDivToken (TokenPunctuator pu) ->
         Just (p, InputElementPunctuator pu)
       InputElementDivToken (TokenNumLit n) ->
         Just (p, InputElementLiteral $ LiteralNum n)
       InputElementDivToken (TokenStringLit s) ->
         Just (p, InputElementLiteral $ LiteralString s)
       InputElementDivDivPunctuator (DivPunctuator s) ->
         Just (p, InputElementPunctuator $  Punctuator s)
    toInputElementRegExp (p, ier) =
      case ier of
       InputElementRegExpWhiteSpace -> Nothing
       InputElementRegExpLineTerminator ->
         Just (p, InputElementLineTerminator)
       InputElementRegExpComment (CommentSingleLine _) -> Nothing
       InputElementRegExpComment (CommentMultiLine s)
         | any isLineTerminator s -> Just (p, InputElementLineTerminator)
         | otherwise -> Nothing
       InputElementRegExpToken (TokenIdentName i) ->
         Just (p, InputElementIdentName i)
       InputElementRegExpToken (TokenPunctuator pu) ->
         Just (p, InputElementPunctuator pu)
       InputElementRegExpToken (TokenNumLit n) ->
         Just (p, InputElementLiteral $ LiteralNum n)
       InputElementRegExpToken (TokenStringLit s) ->
         Just (p, InputElementLiteral $ LiteralString s)
       InputElementRegExpRegExpLit re ->
         Just (p, InputElementLiteral $ LiteralRegExp re)

runLexer :: String -> [(SourcePos, InputElement)]
runLexer s =
  case runParser lexer newTokenState "" s of
   Right l -> l
   Left _  -> []

lexJavaScript :: String -> [(SourcePos, InputElement)]
lexJavaScript input = runLexer input