language-ecmascript 0.10 → 0.11.1
raw patch · 7 files changed
+220/−122 lines, 7 filesdep +charsetdep +template-haskelldep ~QuickCheckdep ~data-defaultPVP ok
version bump matches the API change (PVP)
Dependencies added: charset, template-haskell
Dependency ranges changed: QuickCheck, data-default
API changes (from Hackage documentation)
+ Language.ECMAScript3.Parser: parseObjectLit :: Stream s Identity Char => ExpressionParser s
+ Language.ECMAScript3.Parser: type Parser s a = ParsecT s ParserState Identity a
+ Language.ECMAScript3.Parser.State: type ParserState = [String]
+ Language.ECMAScript3.Parser.Type: type Parser s a = ParsecT s ParserState Identity a
+ Language.ECMAScript3.Syntax.QuasiQuote: js :: QuasiQuoter
+ Language.ECMAScript3.Syntax.QuasiQuote: jsexpr :: QuasiQuoter
+ Language.ECMAScript3.Syntax.QuasiQuote: jsstmt :: QuasiQuoter
- Language.ECMAScript3.Lexer: braces :: ParsecT String u Identity a -> ParsecT String u Identity a
+ Language.ECMAScript3.Lexer: braces :: Stream s Identity Char => Parser s a -> Parser s a
- Language.ECMAScript3.Lexer: brackets :: ParsecT String u Identity a -> ParsecT String u Identity a
+ Language.ECMAScript3.Lexer: brackets :: Stream s Identity Char => Parser s a -> Parser s a
- Language.ECMAScript3.Lexer: charLiteral :: ParsecT String u Identity Char
+ Language.ECMAScript3.Lexer: charLiteral :: Stream s Identity Char => Parser s Char
- Language.ECMAScript3.Lexer: colon :: ParsecT String u Identity String
+ Language.ECMAScript3.Lexer: colon :: Stream s Identity Char => Parser s String
- Language.ECMAScript3.Lexer: comma :: ParsecT String u Identity String
+ Language.ECMAScript3.Lexer: comma :: Stream s Identity Char => Parser s String
- Language.ECMAScript3.Lexer: decimal :: ParsecT String u Identity Integer
+ Language.ECMAScript3.Lexer: decimal :: Stream s Identity Char => Parser s Integer
- Language.ECMAScript3.Lexer: dot :: ParsecT String u Identity String
+ Language.ECMAScript3.Lexer: dot :: Stream s Identity Char => Parser s String
- Language.ECMAScript3.Lexer: float :: ParsecT String u Identity Double
+ Language.ECMAScript3.Lexer: float :: Stream s Identity Char => Parser s Double
- Language.ECMAScript3.Lexer: hexadecimal :: ParsecT String u Identity Integer
+ Language.ECMAScript3.Lexer: hexadecimal :: Stream s Identity Char => Parser s Integer
- Language.ECMAScript3.Lexer: identifier :: ParsecT String u Identity String
+ Language.ECMAScript3.Lexer: identifier :: Stream s Identity Char => Parser s String
- Language.ECMAScript3.Lexer: identifierStart :: ParsecT [Char] u Identity Char
+ Language.ECMAScript3.Lexer: identifierStart :: Stream s Identity Char => Parser s Char
- Language.ECMAScript3.Lexer: integer :: ParsecT String u Identity Integer
+ Language.ECMAScript3.Lexer: integer :: Stream s Identity Char => Parser s Integer
- Language.ECMAScript3.Lexer: lexeme :: ParsecT String u Identity a -> ParsecT String u Identity a
+ Language.ECMAScript3.Lexer: lexeme :: Stream s Identity Char => Parser s a -> Parser s a
- Language.ECMAScript3.Lexer: natural :: ParsecT String u Identity Integer
+ Language.ECMAScript3.Lexer: natural :: Stream s Identity Char => Parser s Integer
- Language.ECMAScript3.Lexer: naturalOrFloat :: ParsecT String u Identity (Either Integer Double)
+ Language.ECMAScript3.Lexer: naturalOrFloat :: Stream s Identity Char => Parser s (Either Integer Double)
- Language.ECMAScript3.Lexer: octal :: ParsecT String u Identity Integer
+ Language.ECMAScript3.Lexer: octal :: Stream s Identity Char => Parser s Integer
- Language.ECMAScript3.Lexer: operator :: ParsecT String u Identity String
+ Language.ECMAScript3.Lexer: operator :: Stream s Identity Char => Parser s String
- Language.ECMAScript3.Lexer: parens :: ParsecT String u Identity a -> ParsecT String u Identity a
+ Language.ECMAScript3.Lexer: parens :: Stream s Identity Char => Parser s a -> Parser s a
- Language.ECMAScript3.Lexer: reserved :: String -> ParsecT String u Identity ()
+ Language.ECMAScript3.Lexer: reserved :: Stream s Identity Char => String -> Parser s ()
- Language.ECMAScript3.Lexer: reservedOp :: String -> ParsecT String u Identity ()
+ Language.ECMAScript3.Lexer: reservedOp :: Stream s Identity Char => String -> Parser s ()
- Language.ECMAScript3.Lexer: semi :: ParsecT String u Identity String
+ Language.ECMAScript3.Lexer: semi :: Stream s Identity Char => Parser s String
- Language.ECMAScript3.Lexer: squares :: ParsecT String u Identity a -> ParsecT String u Identity a
+ Language.ECMAScript3.Lexer: squares :: Stream s Identity Char => Parser s a -> Parser s a
- Language.ECMAScript3.Lexer: stringLiteral :: ParsecT String u Identity String
+ Language.ECMAScript3.Lexer: stringLiteral :: Stream s Identity Char => Parser s String
- Language.ECMAScript3.Lexer: symbol :: String -> ParsecT String u Identity String
+ Language.ECMAScript3.Lexer: symbol :: Stream s Identity Char => String -> Parser s String
- Language.ECMAScript3.Lexer: whiteSpace :: ParsecT String u Identity ()
+ Language.ECMAScript3.Lexer: whiteSpace :: Stream s Identity Char => Parser s ()
- Language.ECMAScript3.Parser: assignExpr :: ExpressionParser
+ Language.ECMAScript3.Parser: assignExpr :: Stream s Identity Char => ExpressionParser s
- Language.ECMAScript3.Parser: parse :: Stream s Identity t => Parsec s [String] a -> SourceName -> s -> Either ParseError a
+ Language.ECMAScript3.Parser: parse :: Stream s Identity Char => Parser s a -> SourceName -> s -> Either ParseError a
- Language.ECMAScript3.Parser: parseBlockStmt :: StatementParser
+ Language.ECMAScript3.Parser: parseBlockStmt :: Stream s Identity Char => StatementParser s
- Language.ECMAScript3.Parser: parseExpression :: ExpressionParser
+ Language.ECMAScript3.Parser: parseExpression :: Stream s Identity Char => ExpressionParser s
- Language.ECMAScript3.Parser: parseScript :: CharParser (JavaScript SourcePos)
+ Language.ECMAScript3.Parser: parseScript :: Stream s Identity Char => Parser s (JavaScript SourcePos)
- Language.ECMAScript3.Parser: parseSimpleExpr' :: ParsecT String ParserState Identity ParsedExpression
+ Language.ECMAScript3.Parser: parseSimpleExpr' :: Stream s Identity Char => ExpressionParser s
- Language.ECMAScript3.Parser: parseStatement :: StatementParser
+ Language.ECMAScript3.Parser: parseStatement :: Stream s Identity Char => StatementParser s
- Language.ECMAScript3.Parser: type ExpressionParser = CharParser ParsedExpression
+ Language.ECMAScript3.Parser: type ExpressionParser s = Parser s ParsedExpression
- Language.ECMAScript3.Parser: type StatementParser = CharParser ParsedStatement
+ Language.ECMAScript3.Parser: type StatementParser s = Parser s ParsedStatement
Files
- CHANGELOG +7/−1
- language-ecmascript.cabal +13/−7
- src/Language/ECMAScript3/Lexer.hs +36/−7
- src/Language/ECMAScript3/Parser.hs +108/−107
- src/Language/ECMAScript3/Parser/State.hs +4/−0
- src/Language/ECMAScript3/Parser/Type.hs +7/−0
- src/Language/ECMAScript3/Syntax/QuasiQuote.hs +45/−0
CHANGELOG view
@@ -1,7 +1,13 @@ Version change log. -=0.10=+=0.11.1=+Fixed binary operator precedence in the parser. See +=0.11=+Added a simple quasi-quoter for ECMAScript (see+Language.ECMAScript3.Syntax.QuasiQuote)++=0.10= The ParenExpr constructor was removed from the Expression AST (WARNING: might break some builds). The pretty printer was rewritten to automatically parenthesize sub-expressions based on operator
language-ecmascript.cabal view
@@ -1,5 +1,5 @@ Name: language-ecmascript-Version: 0.10+Version: 0.11.1 Cabal-Version: >= 1.10 Copyright: (c) 2007-2012 Brown University, (c) 2008-2010 Claudiu Saftoiu, (c) 2012 Stevens Institute of Technology@@ -21,7 +21,7 @@ Includes a parser, pretty-printer, and basic building blocks for more sophisticated tools. - This package used to be called WebBits.+ This package supercedes package WebBits. Source-repository head type: git@@ -30,7 +30,7 @@ Source-repository this type: git location: git://github.com/jswebtools/language-ecmascript.git- tag: 0.9.1+ tag: 0.11.1 Library Hs-Source-Dirs:@@ -44,7 +44,9 @@ syb >= 0.1, uniplate >= 1.6 && <1.7, data-default >= 0.4 && <0.6,- QuickCheck >= 2.4.1.1+ QuickCheck >= 2.5,+ template-haskell,+ charset >= 0.3.2.1 ghc-options: -fwarn-incomplete-patterns Exposed-Modules:@@ -55,8 +57,11 @@ Language.ECMAScript3.Syntax Language.ECMAScript3.Syntax.Annotations Language.ECMAScript3.Syntax.Arbitrary+ Language.ECMAScript3.Syntax.QuasiQuote Language.ECMAScript3.Analysis.Environment Language.ECMAScript3.Analysis.LabelSets+ Language.ECMAScript3.Parser.Type+ Language.ECMAScript3.Parser.State Default-Extensions: DeriveDataTypeable, ScopedTypeVariables, DeriveFunctor, DeriveFoldable, DeriveTraversable, FlexibleContexts Default-Language: Haskell2010@@ -76,7 +81,8 @@ filepath, HUnit, data-default >=0.4 && <0.6,- QuickCheck >= 2.4.1.1+ QuickCheck >= 2.5,+ charset >= 0.3.2.1 Default-Extensions: DeriveDataTypeable, ScopedTypeVariables, DeriveFunctor, DeriveFoldable, DeriveTraversable, FlexibleContexts Default-Language: Haskell2010 ghc-options:@@ -96,8 +102,8 @@ directory, filepath, HUnit,- data-default >=0.4 && <0.5,- QuickCheck >= 2.4.1.1,+ data-default >=0.4 && <0.6,+ QuickCheck >= 2.5, uniplate >= 1.6 && <1.7 Default-Extensions: DeriveDataTypeable, ScopedTypeVariables, DeriveFunctor, DeriveFoldable, DeriveTraversable, FlexibleContexts Default-Language: Haskell2010
src/Language/ECMAScript3/Lexer.hs view
@@ -11,9 +11,14 @@ import Prelude hiding (lex) import Text.Parsec import qualified Text.Parsec.Token as T+import Language.ECMAScript3.Parser.State+import Language.ECMAScript3.Parser.Type+import Control.Monad.Identity +identifierStart :: Stream s Identity Char => Parser s Char identifierStart = letter <|> oneOf "$_" +javascriptDef :: Stream s Identity Char =>T.GenLanguageDef s ParserState Identity javascriptDef = T.LanguageDef "/*" "*/"@@ -35,31 +40,55 @@ "[", "]", "{", "}", "(", ")","</","instanceof"] True -- case-sensitive -lex :: T.TokenParser st+lex :: Stream s Identity Char => T.GenTokenParser s ParserState Identity lex = T.makeTokenParser javascriptDef -- everything but commaSep and semiSep+identifier :: Stream s Identity Char => Parser s String identifier = T.identifier lex+reserved :: Stream s Identity Char => String -> Parser s () reserved = T.reserved lex+operator :: Stream s Identity Char => Parser s String operator = T.operator lex+reservedOp :: Stream s Identity Char => String -> Parser s () reservedOp = T.reservedOp lex +charLiteral :: Stream s Identity Char => Parser s Char charLiteral = T.charLiteral lex -stringLiteral = T.stringLiteral lex +stringLiteral :: Stream s Identity Char => Parser s String+stringLiteral = T.stringLiteral lex+natural :: Stream s Identity Char => Parser s Integer natural = T.natural lex +integer :: Stream s Identity Char => Parser s Integer integer = T.integer lex -float = T.float lex -naturalOrFloat = T.naturalOrFloat lex +float :: Stream s Identity Char => Parser s Double+float = T.float lex+naturalOrFloat :: Stream s Identity Char => Parser s (Either Integer Double)+naturalOrFloat = T.naturalOrFloat lex+decimal :: Stream s Identity Char => Parser s Integer decimal = T.decimal lex +hexadecimal :: Stream s Identity Char => Parser s Integer hexadecimal = T.hexadecimal lex -octal = T.octal lex -symbol = T.symbol lex +octal :: Stream s Identity Char => Parser s Integer+octal = T.octal lex+symbol :: Stream s Identity Char => String -> Parser s String+symbol = T.symbol lex+whiteSpace :: Stream s Identity Char => Parser s () whiteSpace = T.whiteSpace lex +parens :: Stream s Identity Char => Parser s a -> Parser s a parens = T.parens lex+braces :: Stream s Identity Char => Parser s a -> Parser s a braces = T.braces lex+squares :: Stream s Identity Char => Parser s a -> Parser s a squares = T.squares lex +semi :: Stream s Identity Char => Parser s String semi = T.semi lex+comma :: Stream s Identity Char => Parser s String comma = T.comma lex-colon = T.colon lex +colon :: Stream s Identity Char => Parser s String+colon = T.colon lex+dot :: Stream s Identity Char => Parser s String dot = T.dot lex+brackets :: Stream s Identity Char => Parser s a -> Parser s a brackets = T.brackets lex+lexeme :: Stream s Identity Char => Parser s a -> Parser s a lexeme = T.lexeme lex
src/Language/ECMAScript3/Parser.hs view
@@ -18,10 +18,14 @@ -- debugging, remove the next 2 lines , mkDecimal , intLen+ , parseObjectLit + , Parser ) where import Language.ECMAScript3.Lexer hiding (identifier) import qualified Language.ECMAScript3.Lexer as Lexer+import Language.ECMAScript3.Parser.State+import Language.ECMAScript3.Parser.Type import Language.ECMAScript3.Syntax import Language.ECMAScript3.Syntax.Annotations import Data.Default@@ -38,27 +42,24 @@ type ParsedStatement = Statement SourcePos type ParsedExpression = Expression SourcePos -type CharParser a = ParsecT String ParserState Identity a- -- These parsers can store some arbitrary state-type StatementParser = CharParser ParsedStatement-type ExpressionParser = CharParser ParsedExpression--- the statement label stack-type ParserState = [String]+type StatementParser s = Parser s ParsedStatement+type ExpressionParser s = Parser s ParsedExpression + initialParserState :: ParserState initialParserState = [] -- | checks if the label is not yet on the stack, if it is -- throws -- an error; otherwise it pushes it onto the stack-pushLabel :: String -> CharParser ()+pushLabel :: String -> Parser s () pushLabel lab = do labs <- getState pos <- getPosition if lab `elem` labs then fail $ "Duplicate label at " ++ show pos else putState (lab:labs) -popLabel :: CharParser ()+popLabel :: Parser s () popLabel = modifyState safeTail where safeTail [] = [] safeTail (_:xs) = xs@@ -66,14 +67,14 @@ clearLabels :: ParserState -> ParserState clearLabels _ = [] -withFreshLabelStack :: CharParser a -> CharParser a+withFreshLabelStack :: Parser s a -> Parser s a withFreshLabelStack p = do oldState <- getState putState $ clearLabels oldState a <- p putState oldState return a -identifier :: CharParser (Id SourcePos)+identifier :: Stream s Identity Char => Parser s (Id SourcePos) identifier = liftM2 Id getPosition Lexer.identifier @@ -88,7 +89,7 @@ -- reserved-word, we truly have a syntax error. Since input has been consumed, -- <|> will not try its alternate in parseExpression, and we will fail. -parseIfStmt:: StatementParser +parseIfStmt:: Stream s Identity Char => StatementParser s parseIfStmt = do pos <- getPosition reserved "if"@@ -100,7 +101,7 @@ return $ IfStmt pos test consequent alternate) <|> return (IfSingleStmt pos test consequent)) -parseSwitchStmt:: StatementParser+parseSwitchStmt :: Stream s Identity Char => StatementParser s parseSwitchStmt = let parseDefault = do pos <- getPosition@@ -128,7 +129,7 @@ checkClauses clauses return (SwitchStmt pos test clauses) -parseWhileStmt:: StatementParser+parseWhileStmt:: Stream s Identity Char => StatementParser s parseWhileStmt = do pos <- getPosition reserved "while"@@ -136,7 +137,7 @@ body <- parseStatement return (WhileStmt pos test body) -parseDoWhileStmt:: StatementParser+parseDoWhileStmt:: Stream s Identity Char => StatementParser s parseDoWhileStmt = do pos <- getPosition reserved "do"@@ -146,7 +147,7 @@ optional semi return (DoWhileStmt pos body test) -parseContinueStmt:: StatementParser+parseContinueStmt:: Stream s Identity Char => StatementParser s parseContinueStmt = do pos <- getPosition reserved "continue"@@ -158,7 +159,7 @@ optional semi return $ ContinueStmt pos id -parseBreakStmt:: StatementParser+parseBreakStmt:: Stream s Identity Char => StatementParser s parseBreakStmt = do pos <- getPosition reserved "break"@@ -170,19 +171,19 @@ optional semi return $ BreakStmt pos id -parseBlockStmt:: StatementParser+parseBlockStmt:: Stream s Identity Char => StatementParser s parseBlockStmt = do pos <- getPosition statements <- braces (many parseStatement) return (BlockStmt pos statements) -parseEmptyStmt:: StatementParser +parseEmptyStmt:: Stream s Identity Char => StatementParser s parseEmptyStmt = do pos <- getPosition semi return (EmptyStmt pos) -parseLabelledStmt:: StatementParser+parseLabelledStmt:: Stream s Identity Char => StatementParser s parseLabelledStmt = do pos <- getPosition -- Lookahead for the colon. If we don't see it, we are parsing an identifier@@ -195,7 +196,7 @@ popLabel return (LabelledStmt pos label statement) -parseExpressionStmt:: StatementParser+parseExpressionStmt:: Stream s Identity Char => StatementParser s parseExpressionStmt = do pos <- getPosition expr <- parseListExpr -- TODO: spec 12.4?@@ -203,7 +204,7 @@ return $ ExprStmt pos expr -parseForInStmt:: StatementParser+parseForInStmt:: Stream s Identity Char => StatementParser s parseForInStmt = let parseInit = (reserved "var" >> liftM ForInVar identifier) <|> liftM ForInLVal lvalue@@ -217,7 +218,7 @@ body <- parseStatement return $ ForInStmt pos init expr body -parseForStmt:: StatementParser+parseForStmt:: Stream s Identity Char => StatementParser s parseForStmt = let parseInit = (reserved "var" >> liftM VarInit (parseVarDecl `sepBy` comma)) <|> liftM ExprInit parseListExpr@@ -234,7 +235,7 @@ stmt <- parseStatement return $ ForStmt pos init test iter stmt -parseTryStmt:: StatementParser+parseTryStmt:: Stream s Identity Char => StatementParser s parseTryStmt = let parseCatchClause = do pos <- getPosition reserved "catch"@@ -253,7 +254,7 @@ else fail $ "A try statement should have at least a catch\ \ or a finally block, at " ++ show pos -parseThrowStmt:: StatementParser+parseThrowStmt:: Stream s Identity Char => StatementParser s parseThrowStmt = do pos <- getPosition reserved "throw"@@ -261,7 +262,7 @@ optional semi return (ThrowStmt pos expr) -parseReturnStmt:: StatementParser+parseReturnStmt:: Stream s Identity Char => StatementParser s parseReturnStmt = do pos <- getPosition reserved "return"@@ -269,7 +270,7 @@ optional semi return (ReturnStmt pos expr) -parseWithStmt:: StatementParser+parseWithStmt:: Stream s Identity Char => StatementParser s parseWithStmt = do pos <- getPosition reserved "with"@@ -277,13 +278,14 @@ stmt <- parseStatement return (WithStmt pos context stmt) +parseVarDecl :: Stream s Identity Char => Parser s (VarDecl SourcePos) parseVarDecl = do pos <- getPosition id <- identifier init <- (reservedOp "=" >> liftM Just parseExpression) <|> return Nothing return (VarDecl pos id init) -parseVarDeclStmt:: StatementParser+parseVarDeclStmt:: Stream s Identity Char => StatementParser s parseVarDeclStmt = do pos <- getPosition reserved "var"@@ -291,7 +293,7 @@ optional semi return (VarDeclStmt pos decls) -parseFunctionStmt:: StatementParser+parseFunctionStmt:: Stream s Identity Char => StatementParser s parseFunctionStmt = do pos <- getPosition name <- try (reserved "function" >> identifier) -- ambiguity with FuncExpr@@ -301,7 +303,7 @@ "function body in { ... }" return (FunctionStmt pos name args body) -parseStatement:: StatementParser+parseStatement:: Stream s Identity Char => StatementParser s parseStatement = parseIfStmt <|> parseSwitchStmt <|> parseWhileStmt <|> parseDoWhileStmt <|> parseContinueStmt <|> parseBreakStmt <|> parseBlockStmt <|> parseEmptyStmt <|> parseForInStmt <|> parseForStmt@@ -331,32 +333,33 @@ --{{{ Primary expressions -parseThisRef:: ExpressionParser+parseThisRef:: Stream s Identity Char => ExpressionParser s parseThisRef = do pos <- getPosition reserved "this" return (ThisRef pos) -parseNullLit:: ExpressionParser+parseNullLit:: Stream s Identity Char => ExpressionParser s parseNullLit = do pos <- getPosition reserved "null" return (NullLit pos) -parseBoolLit:: ExpressionParser+parseBoolLit:: Stream s Identity Char => ExpressionParser s parseBoolLit = do pos <- getPosition let parseTrueLit = reserved "true" >> return (BoolLit pos True) parseFalseLit = reserved "false" >> return (BoolLit pos False) parseTrueLit <|> parseFalseLit -parseVarRef:: ExpressionParser+parseVarRef:: Stream s Identity Char => ExpressionParser s parseVarRef = liftM2 VarRef getPosition identifier -parseArrayLit:: ExpressionParser+parseArrayLit:: Stream s Identity Char => ExpressionParser s parseArrayLit = liftM2 ArrayLit getPosition (squares (parseExpression `sepEndBy` comma))- ++parseFuncExpr :: Stream s Identity Char => ExpressionParser s parseFuncExpr = do pos <- getPosition reserved "function"@@ -375,17 +378,20 @@ allEscapes:: String allEscapes = map fst escapeChars +parseEscapeChar :: Stream s Identity Char => Parser s Char parseEscapeChar = do c <- oneOf allEscapes let (Just c') = lookup c escapeChars -- will succeed due to line above return c' +parseAsciiHexChar :: Stream s Identity Char => Parser s Char parseAsciiHexChar = do char 'x' d1 <- hexDigit d2 <- hexDigit return ((chr.fst.head.readHex) (d1:d2:"")) +parseUnicodeHexChar :: Stream s Identity Char => Parser s Char parseUnicodeHexChar = do char 'u' liftM (chr.fst.head.readHex) @@ -410,7 +416,7 @@ else return (c:cs)) <|> liftM2 (:) anyChar (parseStringLit' endWith) -parseStringLit:: ExpressionParser+parseStringLit:: Stream s Identity Char => ExpressionParser s parseStringLit = do pos <- getPosition -- parseStringLit' takes as an argument the quote-character that opened the@@ -425,14 +431,14 @@ --}}} -parseRegexpLit:: ExpressionParser+parseRegexpLit:: Stream s Identity Char => ExpressionParser s parseRegexpLit = do let parseFlags = do flags <- many (oneOf "mgi") return $ \f -> f ('g' `elem` flags) ('i' `elem` flags) - let parseEscape :: CharParser Char+ let parseEscape :: Stream s Identity Char => Parser s Char parseEscape = char '\\' >> anyChar- let parseChar :: CharParser Char+ let parseChar :: Stream s Identity Char => Parser s Char parseChar = noneOf "/" let parseRe = (char '/' >> return "") <|> (do char '\\'@@ -448,7 +454,7 @@ spaces -- crucial for Parsec.Token parsers return $ flags (RegexpLit pos pat) -parseObjectLit:: ExpressionParser+parseObjectLit:: Stream s Identity Char => ExpressionParser s parseObjectLit = let parseProp = do -- Parses a string, identifier or integer as the property name. I@@ -465,7 +471,7 @@ return $ ObjectLit pos props --{{{ Parsing numbers. From pg. 17-18 of ECMA-262.-+hexLit :: Stream s Identity Char => Parser s (Bool, Double) hexLit = do try (string "0x") digits <- many1 (oneOf "0123456789abcdefABCDEF")@@ -477,18 +483,16 @@ mkDecimal whole frac fracLen exp = ((fromInteger whole) + ((fromInteger frac) * (10 ^^ (-fracLen)))) * (10 ^^ exp) --- mkDecimal:: Double -> Double -> Int -> Double--- mkDecimal w f e = if f >= 1.0--- then mkDecimal w (f / 10.0) e--- else (w + f) * (10.0 ^^ e)-+exponentPart :: Stream s Identity Char => Parser s Integer exponentPart = do oneOf "eE" (char '+' >> decimal) <|> (char '-' >> negate `fmap` decimal) <|> decimal --wrap a parser's result in a Just:+jparser :: Stream s Identity Char => Parser s a -> Parser s (Maybe a) jparser = liftM Just +decLit :: Stream s Identity Char => Parser s (Bool, Double) decLit = (do whole <- decimal mfrac <- option Nothing (jparser (char '.' >> decimal))@@ -508,7 +512,7 @@ intLen i | i `div` 10 < 1 = 1 intLen i | otherwise = 1 + intLen (i `div` 10) -parseNumLit:: ExpressionParser+parseNumLit:: Stream s Identity Char => ExpressionParser s parseNumLit = do pos <- getPosition (isint, num) <- lexeme $ hexLit <|> decLit@@ -542,20 +546,23 @@ -- Expression Parsers ------------------------------------------------------------------------------- -parseParenExpr:: ExpressionParser+parseParenExpr:: Stream s Identity Char => ExpressionParser s parseParenExpr = parens parseListExpr -- everything above expect functions+parseExprForNew :: Stream s Identity Char => ExpressionParser s parseExprForNew = parseThisRef <|> parseNullLit <|> parseBoolLit <|> parseStringLit <|> parseArrayLit <|> parseParenExpr <|> parseNewExpr <|> parseNumLit <|> parseRegexpLit <|> parseObjectLit <|> parseVarRef -- all the expression parsers defined above+parseSimpleExpr' :: Stream s Identity Char => ExpressionParser s parseSimpleExpr' = parseThisRef <|> parseNullLit <|> parseBoolLit <|> parseStringLit <|> parseArrayLit <|> parseParenExpr <|> parseFuncExpr <|> parseNumLit <|> parseRegexpLit <|> parseObjectLit <|> parseVarRef +parseNewExpr :: Stream s Identity Char => ExpressionParser s parseNewExpr = (do pos <- getPosition reserved "new"@@ -571,6 +578,8 @@ e <- parseNewExpr <?> "expression (3)" parseSimpleExpr (Just e) +parseSimpleExprForNew :: Stream s Identity Char+ =>(Maybe ParsedExpression) -> ExpressionParser s parseSimpleExprForNew (Just e) = ((dotRef e <|> bracketRef e) >>= parseSimpleExprForNew . Just) <|> return e@@ -581,7 +590,8 @@ --}}} makeInfixExpr str constr = Infix parser AssocLeft where- parser:: CharParser (Expression SourcePos -> Expression SourcePos -> Expression SourcePos)+ parser:: Stream s Identity Char+ => Parser s (Expression SourcePos -> Expression SourcePos -> Expression SourcePos) parser = do pos <- getPosition reservedOp str@@ -589,6 +599,7 @@ -- apparently, expression tables can't handle immediately-nested prefixes+parsePrefixedExpr :: Stream s Identity Char => ExpressionParser s parsePrefixedExpr = do pos <- getPosition op <- optionMaybe $ (reservedOp "!" >> return PrefixLNot) <|> @@ -606,24 +617,19 @@ innerExpr <- parsePrefixedExpr return (PrefixExpr pos op innerExpr) -exprTable:: [[Operator String ParserState Identity ParsedExpression]]+exprTable:: Stream s Identity Char => [[Operator s ParserState Identity ParsedExpression]] exprTable = - [ [ makeInfixExpr "==" OpEq- , makeInfixExpr "!=" OpNEq- , makeInfixExpr "===" OpStrictEq- , makeInfixExpr "!==" OpStrictNEq+ [ [ makeInfixExpr "*" OpMul+ , makeInfixExpr "/" OpDiv+ , makeInfixExpr "%" OpMod ]-- , [ makeInfixExpr "||" OpLOr ]-- , [ makeInfixExpr "&&" OpLAnd ]- - , [ makeInfixExpr "|" OpBOr ]-- , [ makeInfixExpr "^" OpBXor ]-- , [ makeInfixExpr "&" OpBAnd ]-+ , [ makeInfixExpr "+" OpAdd+ , makeInfixExpr "-" OpSub+ ]+ , [ makeInfixExpr "<<" OpLShift+ , makeInfixExpr ">>" OpSpRShift+ , makeInfixExpr ">>>" OpZfRShift+ ] , [ makeInfixExpr "<" OpLT , makeInfixExpr "<=" OpLEq , makeInfixExpr ">" OpGT@@ -631,42 +637,39 @@ , makeInfixExpr "instanceof" OpInstanceof , makeInfixExpr "in" OpIn ]-- , [ makeInfixExpr "<<" OpLShift- , makeInfixExpr ">>" OpSpRShift- , makeInfixExpr ">>>" OpZfRShift- ]-- , [ makeInfixExpr "+" OpAdd- , makeInfixExpr "-" OpSub- ]-- , [ makeInfixExpr "*" OpMul- , makeInfixExpr "/" OpDiv- , makeInfixExpr "%" OpMod+ , [ makeInfixExpr "==" OpEq+ , makeInfixExpr "!=" OpNEq+ , makeInfixExpr "===" OpStrictEq+ , makeInfixExpr "!==" OpStrictNEq ]+ , [ makeInfixExpr "&" OpBAnd ]+ , [ makeInfixExpr "^" OpBXor ]+ , [ makeInfixExpr "|" OpBOr ]+ , [ makeInfixExpr "&&" OpLAnd ]+ , [ makeInfixExpr "||" OpLOr ] ] +parseExpression' :: Stream s Identity Char => ExpressionParser s parseExpression' = buildExpressionParser exprTable parsePrefixedExpr <?> "simple expression" -asLValue :: SourcePos+asLValue :: Stream s Identity Char+ => SourcePos -> Expression SourcePos - -> CharParser (LValue SourcePos)+ -> Parser s (LValue SourcePos) asLValue p' e = case e of VarRef p (Id _ x) -> return (LVar p x) DotRef p e (Id _ x) -> return (LDot p e x) BracketRef p e1 e2 -> return (LBracket p e1 e2) otherwise -> fail $ "expected a left-value at " ++ show p' -lvalue :: CharParser (LValue SourcePos)+lvalue :: Stream s Identity Char => Parser s (LValue SourcePos) lvalue = do p <- getPosition e <- parseSimpleExpr Nothing asLValue p e --unaryAssignExpr :: CharParser ParsedExpression+unaryAssignExpr :: Stream s Identity Char => ExpressionParser s unaryAssignExpr = do p <- getPosition let prefixInc = do@@ -686,8 +689,8 @@ postfixInc e <|> postfixDec e <|> return e prefixInc <|> prefixDec <|> other --parseTernaryExpr':: CharParser (ParsedExpression,ParsedExpression)+parseTernaryExpr':: Stream s Identity Char+ => Parser s (ParsedExpression,ParsedExpression) parseTernaryExpr' = do reservedOp "?" l <- assignExpr@@ -695,7 +698,7 @@ r <- assignExpr return (l,r) -parseTernaryExpr:: ExpressionParser+parseTernaryExpr:: Stream s Identity Char => ExpressionParser s parseTernaryExpr = do e <- parseExpression' e' <- optionMaybe parseTernaryExpr'@@ -704,24 +707,21 @@ Just (l,r) -> do p <- getPosition return $ CondExpr p e l r --assignOp :: CharParser AssignOp-assignOp = - (reservedOp "=" >> return OpAssign) <|>- (reservedOp "+=" >> return OpAssignAdd) <|>- (reservedOp "-=" >> return OpAssignSub) <|>- (reservedOp "*=" >> return OpAssignMul) <|>- (reservedOp "/=" >> return OpAssignDiv) <|>- (reservedOp "%=" >> return OpAssignMod) <|>- (reservedOp "<<=" >> return OpAssignLShift) <|>- (reservedOp ">>=" >> return OpAssignSpRShift) <|>- (reservedOp ">>>=" >> return OpAssignZfRShift) <|>- (reservedOp "&=" >> return OpAssignBAnd) <|>- (reservedOp "^=" >> return OpAssignBXor) <|>- (reservedOp "|=" >> return OpAssignBOr)-+assignOp :: Stream s Identity Char => Parser s AssignOp+assignOp = (reservedOp "=" >> return OpAssign)+ <|>(reservedOp "+=" >> return OpAssignAdd)+ <|>(reservedOp "-=" >> return OpAssignSub)+ <|>(reservedOp "*=" >> return OpAssignMul)+ <|>(reservedOp "/=" >> return OpAssignDiv)+ <|>(reservedOp "%=" >> return OpAssignMod)+ <|>(reservedOp "<<=" >> return OpAssignLShift)+ <|>(reservedOp ">>=" >> return OpAssignSpRShift)+ <|>(reservedOp ">>>=" >> return OpAssignZfRShift)+ <|>(reservedOp "&=" >> return OpAssignBAnd)+ <|>(reservedOp "^=" >> return OpAssignBXor)+ <|>(reservedOp "|=" >> return OpAssignBOr) -assignExpr :: ExpressionParser+assignExpr :: Stream s Identity Char => ExpressionParser s assignExpr = do p <- getPosition lhs <- parseTernaryExpr@@ -732,22 +732,23 @@ return (AssignExpr p op lhs rhs) assign <|> return lhs -parseExpression:: ExpressionParser+parseExpression:: Stream s Identity Char => ExpressionParser s parseExpression = assignExpr +parseListExpr :: Stream s Identity Char => ExpressionParser s parseListExpr = assignExpr `sepBy1` comma >>= \exprs -> case exprs of [expr] -> return expr es -> liftM2 ListExpr getPosition (return es) -parseScript:: CharParser (JavaScript SourcePos)+parseScript:: Stream s Identity Char => Parser s (JavaScript SourcePos) parseScript = do whiteSpace liftM2 Script getPosition (parseStatement `sepBy` whiteSpace) -- | Parse from a stream; same as 'Text.Parsec.parse'-parse :: Stream s Identity t - => Parsec s [String] a -- ^ The parser to use+parse :: Stream s Identity Char+ => Parser s a -- ^ The parser to use -> SourceName -- ^ Name of the source file -> s -- ^ the stream to parse, usually a 'String' -> Either ParseError a
+ src/Language/ECMAScript3/Parser/State.hs view
@@ -0,0 +1,4 @@+module Language.ECMAScript3.Parser.State where++-- the statement label stack+type ParserState = [String]
+ src/Language/ECMAScript3/Parser/Type.hs view
@@ -0,0 +1,7 @@+module Language.ECMAScript3.Parser.Type where++import Language.ECMAScript3.Parser.State+import Text.Parsec+import Control.Monad.Identity++type Parser s a = ParsecT s ParserState Identity a
+ src/Language/ECMAScript3/Syntax/QuasiQuote.hs view
@@ -0,0 +1,45 @@+-- | Experimental and very simple quasi-quotation of ECMAScript in+-- Haskell. Doesn't support anti-quotation as of now.++{-# LANGUAGE FlexibleContexts #-}+module Language.ECMAScript3.Syntax.QuasiQuote (js, jsexpr, jsstmt) where++import qualified Language.Haskell.TH as TH+import Language.Haskell.TH.Quote+import Text.Parsec hiding (parse)+import Control.Monad.Identity+import Data.Data (Data)++import Language.ECMAScript3.Syntax+import Language.ECMAScript3.Parser++jsexpr :: QuasiQuoter+jsexpr = QuasiQuoter {quoteExp = quoteJSExpr}++jsstmt :: QuasiQuoter+jsstmt = QuasiQuoter {quoteExp = quoteJSStmt}++js :: QuasiQuoter+js = QuasiQuoter {quoteExp = quoteJS}++quoteJSExpr :: String -> TH.ExpQ+quoteJSExpr = quoteCommon parseExpression++quoteJSStmt :: String -> TH.ExpQ+quoteJSStmt = quoteCommon parseStatement++quoteJS :: String -> TH.ExpQ+quoteJS = quoteCommon parseScript++quoteCommon :: Data a => Parser String a -> String -> TH.ExpQ+quoteCommon p s = do loc <- TH.location+ let fname = TH.loc_filename loc+ let (line, col) = TH.loc_start loc+ let p2 = (getPosition >>= \pos ->+ setPosition $ (flip setSourceName) fname $+ (flip setSourceLine) line $+ (flip setSourceColumn) col $ pos) >> p+ case parse p2 "" s of+ Left err -> do TH.report True $ show err+ return $ TH.UnboxedTupE []+ Right x -> dataToExpQ (const Nothing) x