module Language.ECMAScript3.Lexer(lexeme,identifier,reserved,operator,reservedOp,charLiteral,
stringLiteral,
symbol,whiteSpace,parens,
braces,brackets,squares,semi,comma,colon,dot,
identifierStart
,hexIntLit,decIntLit, decDigits, decDigitsOpt, exponentPart, decLit) where
import Prelude hiding (lex)
import Data.Char
import Data.Monoid ((<>), mconcat)
import qualified Data.CharSet as Set
import qualified Data.CharSet.Unicode.Category as Set
import Text.Parsec
import qualified Text.Parsec.Token as T
import Language.ECMAScript3.Parser.State
import Language.ECMAScript3.Parser.Type
import Control.Monad.Identity
import Control.Applicative ((<$>), (<*>))
import Data.Maybe (isNothing)
identifierStartCharSet :: Set.CharSet
identifierStartCharSet =
mconcat
[ Set.fromDistinctAscList "$_"
, Set.lowercaseLetter
, Set.uppercaseLetter
, Set.titlecaseLetter
, Set.modifierLetter
, Set.otherLetter
, Set.letterNumber
]
identifierRestCharSet :: Set.CharSet
identifierRestCharSet =
identifierStartCharSet
<> mconcat
[ Set.nonSpacingMark
, Set.spacingCombiningMark
, Set.decimalNumber
, Set.connectorPunctuation
]
identifierStart :: Stream s Identity Char => Parser s Char
identifierStart = satisfy (flip Set.member identifierStartCharSet) <?> "letter, '$', '_'"
identifierRest :: Stream s Identity Char => Parser s Char
identifierRest = satisfy (flip Set.member identifierRestCharSet) <?> "letter, digits, '$', '_' ..."
javascriptDef :: Stream s Identity Char =>T.GenLanguageDef s ParserState Identity
javascriptDef =
T.LanguageDef "/*"
"*/"
"//"
False
identifierStart
identifierRest
(oneOf "{}<>()~.,?:|&^=!+-*/%!")
(oneOf "=<>|&+")
["break", "case", "catch", "const", "continue", "debugger",
"default", "delete", "do", "else", "enum", "false", "finally",
"for", "function", "if", "instanceof", "in", "let", "new",
"null", "return", "switch", "this", "throw", "true", "try",
"typeof", "var", "void", "while", "with"]
["|=", "^=", "&=", "<<=", ">>=", ">>>=", "+=", "-=", "*=", "/=",
"%=", "=", ";", ",", "?", ":", "||", "&&", "|", "^", "&",
"===", "==", "=", "!==", "!=", "<<", "<=", "<", ">>>", ">>",
">=", ">", "++", "--", "+", "-", "*", "/", "%", "!", "~", ".",
"[", "]", "{", "}", "(", ")","</","instanceof"]
True
lex :: Stream s Identity Char => T.GenTokenParser s ParserState Identity
lex = T.makeTokenParser javascriptDef
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 :: Stream s Identity Char => Parser s String
stringLiteral = T.stringLiteral 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 :: 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
decIntLit :: Stream s Identity Char => Parser s String
decIntLit = digit >>= \d -> case d of
'0' -> return [d]
_ -> (d:) <$> decDigitsOpt
decDigitsOpt :: Stream s Identity Char => Parser s String
decDigitsOpt = many digit
decDigits :: Stream s Identity Char => Parser s String
decDigits = many1 digit
hexIntLit :: Stream s Identity Char => Parser s String
hexIntLit = do try (char '0' >> oneOf "xX")
many1 hexDigit
exponentPart :: Stream s Identity Char => Parser s String
exponentPart = do ei <- oneOf "eE"
sgn<- option "" $ oneOf "+-" >>= \x -> return [x]
si <- decDigits
return (ei:(sgn++si))
decLit :: Stream s Identity Char => Parser s (String, Bool)
decLit =
choice [do whole <- decIntLit
mfrac <- optionMaybe ((:) <$> char '.' <*> decDigitsOpt)
mexp <- optionMaybe exponentPart
let isint = isNothing mfrac && isNothing mexp
return (whole ++ marr mfrac ++ marr mexp, isint)
,do frac <- (:) <$> (char '.') <*> decDigits
exp <- option "" exponentPart
return ('0':frac++exp, True)
]
marr (Just ar) = ar
marr Nothing = []