ecma262-0.0.0: src/Language/JavaScript/Parser.hs
module Language.JavaScript.Parser
( parseJavaScript ) where
import Control.Applicative ((<*), (*>))
import Text.Parsec
import Language.JavaScript.AST
import Language.JavaScript.Lexer (lexJavaScript)
import Language.JavaScript.Prim
import Language.JavaScript.Util
chainl1' :: (Stream s m t) =>
ParsecT s u m a -> ParsecT s u m b -> ParsecT s u m (a -> b -> a) -> ParsecT s u m a
chainl1' pa pb op = do
a <- pa
rest a
where
rest a = do { f <- op; b <- pb; rest (f a b) } <|> return a
primExpr :: JSParser PrimExpr
primExpr =
do { identName "this" ; return PrimExprThis } <|>
do { name <- getIdent; return $ PrimExprIdent name} <|>
do { l <- getLiteral; return $ PrimExprLiteral l } <|>
do { a <- arrayLit; return $ PrimExprArray a } <|>
do { o <- objectLit; return $ PrimExprObject o } <|>
do { punctuator "("; e <- expr; punctuator ")"; return $ PrimExprParens e }
arrayLit :: JSParser ArrayLit
arrayLit =
try (do { punctuator "["; me <- optionMaybe elision; punctuator "]"; return $ ArrayLitH me }) <|>
try (do { punctuator "["; el <- elementList; punctuator "]"; return $ ArrayLit el }) <|>
do { punctuator "[";
el <- elementList;
punctuator ",";
me <- optionMaybe elision;
punctuator "]";
return $ ArrayLitT el me }
elementList :: JSParser ElementList
elementList =
do { me <- optionMaybe elision; ae <- assignExpr; applyRest elementListRest (ElementList me ae) }
elementListRest :: JSParser (ElementList -> JSParser ElementList)
elementListRest =
do { punctuator ","; me <- optionMaybe elision; ae <- assignExpr; return $ \el -> applyRest elementListRest (ElementListCons el me ae) }
elision :: JSParser Elision
elision =
do { punctuator ","; applyRest elisionRest ElisionComma }
elisionRest :: JSParser (Elision -> JSParser Elision)
elisionRest =
do { punctuator ","; return $ \e -> applyRest elisionRest (ElisionCons e) }
objectLit :: JSParser ObjectLit
objectLit =
try (do { punctuator "{"; punctuator "}"; return ObjectLitEmpty }) <|>
do { punctuator "{"; pl <- propList; optional $ punctuator ","; punctuator "}"; return $ ObjectLit pl }
propList :: JSParser PropList
propList =
do { pa <- propAssign; applyRest propListRest (PropListAssign pa) }
propListRest :: JSParser (PropList -> JSParser PropList)
propListRest =
do { punctuator ","; pa <- propAssign; return $ \pl -> applyRest propListRest (PropListCons pl pa) }
propAssign :: JSParser PropAssign
propAssign =
do { pn <- propName; punctuator ":"; ae <- assignExpr; return $ PropAssignField pn ae } <|>
do { identName "get"; pn <- propName; punctuator "("; punctuator ")"; punctuator "{"; fb <- funcBody; punctuator "}"; return $ PropAssignGet pn fb } <|>
do { identName "set"; pn <- propName; punctuator "("; pl <- propSetParamList; punctuator ")"; punctuator "{"; fb <- funcBody; punctuator "}"; return $ PropAssignSet pn pl fb }
propName :: JSParser PropName
propName =
do { name <- getIdentName; return $ PropNameId name } <|>
do { sl <- getStringLit; return $ PropNameStr sl } <|>
do { nl <- getNumLit; return $ PropNameNum nl }
propSetParamList :: JSParser PropSetParamList
propSetParamList =
do { i <- getIdent; return $ PropSetParamList i }
memberExpr :: JSParser MemberExpr
memberExpr =
do { identName "new"; me <- memberExpr; args <- arguments; applyRest memberExprRest (MemberExprNew me args) } <|>
do { pe <- primExpr; applyRest memberExprRest (MemberExprPrim pe) } <|>
do { fe <- funcExpr; applyRest memberExprRest (MemberExprFunc fe) }
memberExprRest :: JSParser (MemberExpr -> JSParser MemberExpr)
memberExprRest =
do { punctuator "["; e <- expr; punctuator "]"; return $ \me -> applyRest memberExprRest (MemberExprArray me e) } <|>
do { punctuator "."; name <- getIdentName; return $ \me -> applyRest memberExprRest (MemberExprDot me name) }
newExpr :: JSParser NewExpr
newExpr =
try (do { me <- memberExpr; return $ NewExprMember me }) <|>
do { identName "new"; ne <- newExpr; return $ NewExprNew ne }
callExpr :: JSParser CallExpr
callExpr =
do { me <- memberExpr; args <- arguments; applyRest callExprRest (CallExprMember me args) }
callExprRest :: JSParser (CallExpr -> JSParser CallExpr)
callExprRest =
do { args <- arguments; return $ \ce -> applyRest callExprRest (CallExprCall ce args) } <|>
do { punctuator "["; e <- expr; punctuator "]"; return $ \ce -> applyRest callExprRest (CallExprArray ce e) } <|>
do { punctuator "."; name <- getIdentName; return $ \ce -> applyRest callExprRest (CallExprDot ce name) }
arguments :: JSParser Arguments
arguments =
try (do { punctuator "("; punctuator ")"; return ArgumentsEmpty }) <|>
do { punctuator "("; al <- argumentList; punctuator ")"; return $ Arguments al }
argumentList :: JSParser ArgumentList
argumentList =
chainl1'
(do { ae <- assignExpr; return $ ArgumentList ae })
assignExpr
(do { punctuator ","; return ArgumentListCons })
leftExpr :: JSParser LeftExpr
leftExpr =
try (do { ce <- callExpr; return $ LeftExprCallExpr ce }) <|>
do { ne <- newExpr; return $ LeftExprNewExpr ne }
postFixExpr :: JSParser PostFixExpr
postFixExpr = do
le <- leftExpr
do { punctuator "++"; return $ PostFixExprPostInc le } <|>
do { punctuator "--"; return $ PostFixExprPostDec le } <|>
do { return $ PostFixExprLeftExpr le }
uExpr :: JSParser UExpr
uExpr =
do { identName "delete"; u <- uExpr; return $ UExprDelete u } <|>
do { identName "void"; u <- uExpr; return $ UExprVoid u } <|>
do { identName "typeof"; u <- uExpr; return $ UExprTypeOf u } <|>
do { punctuator "++"; u <- uExpr; return $ UExprDoublePlus u } <|>
do { punctuator "--"; u <- uExpr; return $ UExprDoubleMinus u } <|>
do { punctuator "+"; u <- uExpr; return $ UExprUnaryPlus u } <|>
do { punctuator "-"; u <- uExpr; return $ UExprUnaryMinus u } <|>
do { punctuator "~"; u <- uExpr; return $ UExprBitNot u } <|>
do { punctuator "!"; u <- uExpr; return $ UExprNot u } <|>
do { pe <- postFixExpr; return $ UExprPostFix pe }
multExpr :: JSParser MultExpr
multExpr =
chainl1'
(do { u <- uExpr; return $ MultExpr u })
uExpr
(do { punctuator "*"; return MultExprMult } <|>
do { punctuator "/"; return MultExprDiv } <|>
do { punctuator "%"; return MultExprMod })
addExpr :: JSParser AddExpr
addExpr =
chainl1'
(do { m <- multExpr; return $ AddExpr m })
multExpr
(do { punctuator "+"; return AddExprAdd } <|>
do { punctuator "-"; return AddExprSub })
shiftExpr :: JSParser ShiftExpr
shiftExpr =
chainl1'
(do { a <- addExpr; return $ ShiftExpr a })
addExpr
(do { punctuator "<<"; return ShiftExprLeft } <|>
do { punctuator ">>"; return ShiftExprRight } <|>
do { punctuator ">>>"; return ShiftExprRightZero })
relExpr :: JSParser RelExpr
relExpr =
chainl1'
(do { s <- shiftExpr; return $ RelExpr s })
shiftExpr
(do { punctuator "<"; return RelExprLess } <|>
do { punctuator ">"; return RelExprGreater } <|>
do { punctuator "<="; return RelExprLessEq } <|>
do { punctuator ">="; return RelExprGreaterEq } <|>
do { identName "instanceof"; return RelExprInstanceOf } <|>
do { identName "in"; return RelExprIn })
relExprNoIn :: JSParser RelExprNoIn
relExprNoIn =
chainl1'
(do { s <- shiftExpr; return $ RelExprNoIn s })
shiftExpr
(do { punctuator "<"; return RelExprNoInLess } <|>
do { punctuator ">"; return RelExprNoInGreater } <|>
do { punctuator "<="; return RelExprNoInLessEq } <|>
do { punctuator ">="; return RelExprNoInGreaterEq } <|>
do { identName "instanceof"; return RelExprNoInInstanceOf })
eqExpr :: JSParser EqExpr
eqExpr =
chainl1'
(do { r <- relExpr; return $ EqExpr r })
relExpr
(do { punctuator "=="; return EqExprEq } <|>
do { punctuator "!="; return EqExprNotEq } <|>
do { punctuator "==="; return EqExprStrictEq } <|>
do { punctuator "!=="; return EqExprStrictNotEq })
eqExprNoIn :: JSParser EqExprNoIn
eqExprNoIn =
chainl1'
(do { r <- relExprNoIn; return $ EqExprNoIn r })
relExprNoIn
(do { punctuator "=="; return EqExprNoInEq } <|>
do { punctuator "!="; return EqExprNoInNotEq } <|>
do { punctuator "==="; return EqExprNoInStrictEq } <|>
do { punctuator "!=="; return EqExprNoInStrictNotEq })
bitAndExpr :: JSParser BitAndExpr
bitAndExpr =
chainl1'
(do { e <- eqExpr; return $ BitAndExpr e })
eqExpr
(do { punctuator "&"; return $ BitAndExprAnd })
bitAndExprNoIn :: JSParser BitAndExprNoIn
bitAndExprNoIn =
chainl1'
(do { e <- eqExprNoIn; return $ BitAndExprNoIn e })
eqExprNoIn
(do { punctuator "&"; return $ BitAndExprNoInAnd })
bitXorExpr :: JSParser BitXorExpr
bitXorExpr =
chainl1'
(do { bae <- bitAndExpr; return $ BitXorExpr bae })
bitAndExpr
(do { punctuator "^"; return $ BitXorExprXor })
bitXorExprNoIn :: JSParser BitXorExprNoIn
bitXorExprNoIn =
chainl1'
(do { bae <- bitAndExprNoIn; return $ BitXorExprNoIn bae })
bitAndExprNoIn
(do { punctuator "^"; return $ BitXorExprNoInXor })
bitOrExpr :: JSParser BitOrExpr
bitOrExpr =
chainl1'
(do { bxe <- bitXorExpr; return $ BitOrExpr bxe })
bitXorExpr
(do { punctuator "|"; return $ BitOrExprOr })
bitOrExprNoIn :: JSParser BitOrExprNoIn
bitOrExprNoIn =
chainl1'
(do { bxe <- bitXorExprNoIn; return $ BitOrExprNoIn bxe })
bitXorExprNoIn
(do { punctuator "|"; return $ BitOrExprNoInOr })
logicalAndExpr :: JSParser LogicalAndExpr
logicalAndExpr =
chainl1'
(do { boe <- bitOrExpr; return $ LogicalAndExpr boe })
bitOrExpr
(do { punctuator "&&"; return $ LogicalAndExprAnd })
logicalAndExprNoIn :: JSParser LogicalAndExprNoIn
logicalAndExprNoIn =
chainl1'
(do { boe <- bitOrExprNoIn; return $ LogicalAndExprNoIn boe })
bitOrExprNoIn
(do { punctuator "&&"; return $ LogicalAndExprNoInAnd })
logicalOrExpr :: JSParser LogicalOrExpr
logicalOrExpr =
chainl1'
(do { lae <- logicalAndExpr; return $ LogicalOrExpr lae })
logicalAndExpr
(do { punctuator "||"; return $ LogicalOrExprOr })
logicalOrExprNoIn :: JSParser LogicalOrExprNoIn
logicalOrExprNoIn =
chainl1'
(do { lae <- logicalAndExprNoIn; return $ LogicalOrExprNoIn lae })
logicalAndExprNoIn
(do { punctuator "||"; return $ LogicalOrExprNoInOr })
condExpr :: JSParser CondExpr
condExpr = do
loe <- logicalOrExpr
do { try $ do { punctuator "?"; }; ae1 <- assignExpr; punctuator ":"; ae2 <- assignExpr; return $ CondExprIf loe ae1 ae2 } <|>
do { return $ CondExpr loe }
condExprNoIn :: JSParser CondExprNoIn
condExprNoIn = do
loe <- logicalOrExprNoIn;
do { try $ do { punctuator "?"; }; ae1 <- assignExpr; punctuator ":"; ae2 <- assignExpr; return $ CondExprNoInIf loe ae1 ae2 } <|>
do { return $ CondExprNoIn loe }
assignExpr :: JSParser AssignExpr
assignExpr =
try (do { le <- leftExpr; ao <- assignOp; ae <- assignExpr; return $ AssignExprAssign le ao ae }) <|>
do { ce <- condExpr; return $ AssignExprCondExpr ce }
assignExprNoIn :: JSParser AssignExprNoIn
assignExprNoIn =
try (do { le <- leftExpr; ao <- assignOp; ae <- assignExprNoIn; return $ AssignExprNoInAssign le ao ae }) <|>
do { ce <- condExprNoIn; return $ AssignExprNoInCondExpr ce }
assignOp :: JSParser AssignOp
assignOp =
do { punctuator "="; return AssignOpNormal } <|>
do { punctuator "*="; return AssignOpMult } <|>
do { punctuator "/="; return AssignOpDiv } <|>
do { punctuator "%="; return AssignOpMod } <|>
do { punctuator "+="; return AssignOpPlus } <|>
do { punctuator "-="; return AssignOpMinus } <|>
do { punctuator "<<="; return AssignOpShiftLeft } <|>
do { punctuator ">>="; return AssignOpShiftRight } <|>
do { punctuator ">>>="; return AssignOpShiftRightZero } <|>
do { punctuator "&="; return AssignOpBitAnd } <|>
do { punctuator "^="; return AssignOpBitXor } <|>
do { punctuator "|="; return AssignOpBitOr }
expr :: JSParser Expr
expr =
chainl1'
(do { ae <- assignExpr; return $ Expr ae })
assignExpr
(do { punctuator ","; return ExprCons })
exprNoIn :: JSParser ExprNoIn
exprNoIn =
chainl1'
(do { ae <- assignExprNoIn; return $ ExprNoIn ae })
assignExprNoIn
(do { punctuator ","; return ExprNoInCons })
stmt :: JSParser Stmt
stmt =
do { b <- block; return $ StmtBlock b } <|>
do { vs <- varStmt; return $ StmtVar vs } <|>
do { es <- emptyStmt; return $ StmtEmpty es } <|>
try (do { es <- exprStmt; return $ StmtExpr es }) <|>
do { ic <- contStmt; return $ StmtCont ic } <|>
do { is <- ifStmt; return $ StmtIf is } <|>
do { is <- itStmt; return $ StmtIt is } <|>
do { bs <- breakStmt; return $ StmtBreak bs } <|>
do { rs <- returnStmt; return $ StmtReturn rs } <|>
do { ws <- withStmt; return $ StmtWith ws } <|>
do { ss <- switchStmt; return $ StmtSwitch ss } <|>
do { ts <- throwStmt; return $ StmtThrow ts } <|>
do { ts <- tryStmt; return $ StmtTry ts } <|>
do { ds <- dbgStmt; return $ StmtDbg ds } <|>
do { ls <- labelledStmt; return $ StmtLabelled ls }
block :: JSParser Block
block =
do { punctuator "{"; msl <- optionMaybe stmtList; punctuator "}"; return $ Block msl }
stmtList :: JSParser StmtList
stmtList =
chainl1'
(do { s <- stmt; return $ StmtList s })
stmt
(do { return StmtListCons })
varStmt :: JSParser VarStmt
varStmt =
do { identName "var"; vdl <- varDeclList; return $ VarStmt vdl }
varDeclList :: JSParser VarDeclList
varDeclList =
chainl1'
(do { vd <- varDecl; return $ VarDeclList vd})
varDecl
(do { punctuator ","; return $ VarDeclListCons })
varDeclListNoIn :: JSParser VarDeclListNoIn
varDeclListNoIn =
chainl1'
(do { vd <- varDeclNoIn; return $ VarDeclListNoIn vd})
varDeclNoIn
(do { punctuator ","; return $ VarDeclListNoInCons})
varDecl :: JSParser VarDecl
varDecl =
do { i <- getIdent; mInit <- optionMaybe initialiser; return $ VarDecl i mInit }
varDeclNoIn :: JSParser VarDeclNoIn
varDeclNoIn =
do { i <- getIdent; mInit <- optionMaybe initialiserNoIn; return $ VarDeclNoIn i mInit }
initialiser :: JSParser Initialiser
initialiser =
do { punctuator "="; ae <- assignExpr; return $ Initialiser ae }
initialiserNoIn :: JSParser InitialiserNoIn
initialiserNoIn =
do { punctuator "="; ae <- assignExprNoIn; return $ InitialiserNoIn ae }
emptyStmt :: JSParser EmptyStmt
emptyStmt =
do { punctuator ";"; return EmptyStmt }
exprStmt :: JSParser ExprStmt
exprStmt =
do { notFollowedBy (try $ punctuator "{" <|> identName "function"); e <- expr; autoSemi; return $ ExprStmt e }
ifStmt :: JSParser IfStmt
ifStmt =
try (do { identName "if"; punctuator "("; e <- expr; punctuator ")"; s1 <- stmt; identName "else"; s2 <- stmt; return $ IfStmtIfElse e s1 s2 }) <|>
do { identName "if"; punctuator "("; e <- expr; punctuator ")"; s <- stmt; return $ IfStmtIf e s }
itStmt :: JSParser ItStmt
itStmt =
try (do { identName "do"; s <- stmt; identName "while"; punctuator "("; e <- expr; punctuator ")"; return $ ItStmtDoWhile s e }) <|>
try (do { identName "while"; punctuator "("; e <- expr; punctuator ")"; s <- stmt; return $ ItStmtWhile e s }) <|>
try (do { identName "for"; punctuator "("; me1 <- optionMaybe exprNoIn; punctuator ";"; me2 <- optionMaybe expr; punctuator ";"; me3 <- optionMaybe expr; punctuator ")"; s <- stmt; return $ ItStmtFor me1 me2 me3 s }) <|>
try (do { identName "for"; punctuator "("; identName "var"; vdl <- varDeclListNoIn; punctuator ";"; me1 <- optionMaybe expr; punctuator ";"; me2 <- optionMaybe expr; punctuator ")"; s <- stmt; return $ ItStmtForVar vdl me1 me2 s }) <|>
do { identName "for"; punctuator "("; le <- leftExpr; identName "in"; e <- expr; punctuator ")"; s <- stmt; return $ ItStmtForIn le e s } <|>
do { identName "for"; punctuator "("; identName "var"; vd <- varDeclNoIn; identName "in"; e <- expr; punctuator ")"; s <- stmt; return $ ItStmtForVarIn vd e s }
contStmt :: JSParser ContStmt
contStmt =
try (do { identName "continue"; autoSemi; return ContStmt }) <|>
do { identName "continue"; noLineTerminatorHere; i <- getIdent; autoSemi; return $ ContStmtLabelled i }
breakStmt :: JSParser BreakStmt
breakStmt =
try (do { identName "break"; autoSemi; return BreakStmt }) <|>
do { identName "break"; noLineTerminatorHere; i <- getIdent; autoSemi; return $ BreakStmtLabelled i }
returnStmt :: JSParser ReturnStmt
returnStmt =
try (do { identName "return"; autoSemi; return ReturnStmt }) <|>
do { identName "return"; noLineTerminatorHere; e <- expr; autoSemi; return $ ReturnStmtExpr e }
withStmt :: JSParser WithStmt
withStmt =
do { identName "with"; punctuator "("; e <- expr; punctuator ")"; s <- stmt; return $ WithStmt e s }
switchStmt :: JSParser SwitchStmt
switchStmt =
do { identName "switch"; punctuator "("; e <- expr; punctuator ")"; cb <- caseBlock; return $ SwitchStmt e cb }
caseBlock :: JSParser CaseBlock
caseBlock =
try (do { punctuator "{"; mcc <- optionMaybe caseClauses; punctuator "}"; return $ CaseBlock mcc }) <|>
do { punctuator "{"; mcc1 <- optionMaybe caseClauses; dc <- defaultClause; mcc2 <- optionMaybe caseClauses; punctuator "}"; return $ CaseBlockDefault mcc1 dc mcc2 }
caseClauses :: JSParser CaseClauses
caseClauses =
chainl1'
(do { cc <- caseClause; return $ CaseClauses cc })
caseClause
(do { return $ CaseClausesCons })
caseClause :: JSParser CaseClause
caseClause =
do { identName "case"; e <- expr; punctuator ":"; msl <- optionMaybe stmtList; return $ CaseClause e msl }
defaultClause :: JSParser DefaultClause
defaultClause =
do { identName "default"; punctuator ":"; msl <- optionMaybe stmtList; return $ DefaultClause msl }
labelledStmt :: JSParser LabelledStmt
labelledStmt =
do { i <- getIdent; punctuator ":"; s <- stmt; return $ LabelledStmt i s }
throwStmt :: JSParser ThrowStmt
throwStmt =
do { identName "throw"; noLineTerminatorHere; e <- expr; autoSemi; return $ ThrowStmt e }
tryStmt :: JSParser TryStmt
tryStmt = do
identName "try"
b <- block
do { f <- finally; return $ TryStmtBF b f } <|>
do { c <- catch;
do { f <- finally; return $ TryStmtBCF b c f } <|>
do { return $ TryStmtBC b c }
}
catch :: JSParser Catch
catch =
do { identName "catch"; punctuator "("; i <- getIdent; punctuator ")"; b <- block; return $ Catch i b }
finally :: JSParser Finally
finally =
do { identName "finally"; b <- block; return $ Finally b }
dbgStmt :: JSParser DbgStmt
dbgStmt =
do { identName "debugger"; autoSemi; return DbgStmt }
funcDecl :: JSParser FuncDecl
funcDecl =
do { identName "function"; i <- getIdent; punctuator "("; mfpl <- optionMaybe formalParamList; punctuator ")"; punctuator "{"; fb <- funcBody; punctuator "}"; return $ FuncDecl i mfpl fb }
funcExpr :: JSParser FuncExpr
funcExpr =
do { identName "function"; mi <- optionMaybe getIdent; punctuator "("; mfpl <- optionMaybe formalParamList; punctuator ")"; punctuator "{"; fb <- funcBody; punctuator "}"; return $ FuncExpr mi mfpl fb }
formalParamList :: JSParser FormalParamList
formalParamList =
chainl1'
(do { i <- getIdent; return $ FormalParamList i })
getIdent
(do { punctuator ","; return $ FormalParamListCons })
funcBody :: JSParser FuncBody
funcBody =
do { mse <- optionMaybe sourceElements; return $ FuncBody mse }
program :: JSParser Program
program =
do { mse <- optionMaybe sourceElements; return $ Program mse }
sourceElements :: JSParser SourceElements
sourceElements =
chainl1'
(do { se <- sourceElement; return $ SourceElements se })
sourceElement
(do { return SourceElementsCons })
sourceElement :: JSParser SourceElement
sourceElement =
do { s <- stmt; return $ SourceElementStmt s } <|>
do { fd <- funcDecl; return $ SourceElementFuncDecl fd }
parseJavaScript :: String -> Either ParseError Program
parseJavaScript input =
let p = many lineTerminator *> program <* many lineTerminator <* eof
in runParser p newJSPState "" $ lexJavaScript input