packages feed

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

module Language.JavaScript.Prim where

import Control.Monad (guard, void)

import Text.Parsec ((<|>),
                    SourcePos,
                    eof, many)
import Text.Parsec.Prim (getState, lookAhead, modifyState)
import Text.Parsec.Token (GenLanguageDef(..))
import Text.ParserCombinators.Parsec.Prim (GenParser)
import qualified Text.ParserCombinators.Parsec.Prim as Parsec (token)

import Language.JavaScript.AST
import Language.JavaScript.Lexer hiding (token, lineTerminator, punctuator)

data JSPState
  = JSPState
    { jspStateNLFlag :: Bool }

getNLFlag :: JSParser Bool
getNLFlag = do { s <- getState; return $ jspStateNLFlag s }
setNLFlag :: JSParser ()
setNLFlag = modifyState $ \s -> s { jspStateNLFlag = True }
unsetNLFlag :: JSParser ()
unsetNLFlag = modifyState $ \s -> s { jspStateNLFlag = False }

newJSPState :: JSPState
newJSPState = JSPState {
  jspStateNLFlag = False }

type JSParser a = GenParser (SourcePos, InputElement) JSPState a

lexeme :: JSParser a -> JSParser a
lexeme p =
  do { x <- p; unsetNLFlag; void $ many lineTerminator; return x }

mytoken :: (InputElement -> Maybe a) -> JSParser a
mytoken test =
  Parsec.token showTok posFromTok testTok
  where
    showTok (pos, t)    = show t
    posFromTok (pos, t) = pos
    testTok (pos, t)    = test t

equal :: InputElement -> JSParser ()
equal test = mytoken (\tok -> if tok == test then Just () else Nothing)

lineTerminator :: JSParser ()
lineTerminator =
  do { equal InputElementLineTerminator; setNLFlag }

noLineTerminatorHere :: JSParser ()
noLineTerminatorHere =
  do { nl <- getNLFlag; guard (not nl) }

priorNL :: JSParser ()
priorNL =
  do { nl <- getNLFlag; guard nl }

autoSemi :: JSParser ()
autoSemi =
  punctuator ";" <|>
  priorNL <|>
  void (lookAhead $ punctuator "}") <|>
  eof

identName :: String -> JSParser ()
identName s = lexeme $ equal $ InputElementIdentName $ IdentName s

getIdentName :: JSParser IdentName
getIdentName = lexeme $ mytoken get
  where
    get (InputElementIdentName i) = Just i
    get _ = Nothing

getIdent :: JSParser Ident
getIdent = lexeme $ mytoken get
  where
    get (InputElementIdentName i@(IdentName n)) =
      if n `elem` reservedNames javaScript
      then Nothing
      else Just $ Ident i
    get _ = Nothing

punctuator :: String -> JSParser ()
punctuator p = lexeme $ equal $ InputElementPunctuator $ Punctuator p

getLiteral :: JSParser Literal
getLiteral = lexeme $ mytoken get
  where
    get (InputElementLiteral l) = Just l
    get (InputElementIdentName (IdentName "null")) = Just $ LiteralNull NullLit
    get (InputElementIdentName (IdentName "true")) = Just $ LiteralBool $ BoolLit True
    get (InputElementIdentName (IdentName "false")) = Just $ LiteralBool $ BoolLit False
    get _ = Nothing

getNumLit :: JSParser NumLit
getNumLit = lexeme $ mytoken get
  where
    get (InputElementLiteral (LiteralNum n)) = Just n
    get _ = Nothing

getStringLit :: JSParser StringLit
getStringLit = lexeme $ mytoken get
  where
    get (InputElementLiteral (LiteralString s)) = Just s
    get _ = Nothing