{-# OPTIONS -fglasgow-exts #-} {- Lexical analyzer. No words were laid on stream or stone When Durin woke and walked alone. He named the nameless hills and dells; He drank from yet untasted wells... -} module Lexer where import Internals import qualified Text.ParserCombinators.Parsec.Token as P perl6Def = javaStyle { P.commentStart = "\n=begin\n" , P.commentEnd = "\n=cut\n" , P.commentLine = "#" , P.nestedComments = False , P.identStart = letter <|> oneOf "_:$@%&" , P.identLetter = alphaNum <|> oneOf "_:" , P.reservedNames = words $ "if then else do while skip" , P.reservedOpNames= words $ " . .+ .? .* .+ .() .[] .{} .<<>> .= " ++ " ++ -- ** ! + - ~ ? * ** +^ ~^ ?^ \\ " ++ " * / % x xx +& +< +> ~& ~<< ~>> " ++ " + - ~ +| +^ ~| ~^ " ++ " & | ^ " ++ " rand sleep abs " ++ " => but does cmp <=> .. ^.. ..^ ^..^ " ++ " != == < <= > >= ~~ !~ eq ne lt le gt ge =:= " ++ " && || ^^ // ?? :: = := ::= += **= xx= " ++ " , <== print push any all true not " ++ " ==> and or xor err ;" , P.opLetter = oneOf (concat (P.reservedOpNames perl6Def)) , P.caseSensitive = False } perl6Lexer = P.makeTokenParser perl6Def reservedOp = P.reservedOp perl6Lexer integer = P.integer perl6Lexer whiteSpace = P.whiteSpace perl6Lexer parens = P.parens perl6Lexer float = P.float perl6Lexer lexeme = P.lexeme perl6Lexer stringLiteral = choice [ P.stringLiteral perl6Lexer , singleQuoted ] naturalOrFloat = lexeme (natFloat) "number" where natFloat = do{ char '0' ; zeroNumFloat } <|> decimalFloat zeroNumFloat = do{ n <- hexadecimal <|> octal <|> binary ; return (Left n) } <|> decimalFloat <|> fractFloat 0 <|> return (Left 0) decimalFloat = do{ n <- decimal ; option (Left n) (try $ fractFloat n) } fractFloat n = do{ f <- fractExponent n ; return (Right f) } fractExponent n = do{ fract <- fraction ; expo <- option 1.0 exponent' ; return ((fromInteger n + fract)*expo) } <|> do{ expo <- exponent' ; return ((fromInteger n)*expo) } fraction = do{ char '.' ; digits <- many digit "fraction" ; return (foldr op 0.0 digits) } "fraction" where op d f = (f + fromIntegral (digitToInt d))/10.0 exponent' = do{ oneOf "eE" ; f <- sign ; e <- decimal "exponent" ; return (power (f e)) } "exponent" where power e | e < 0 = 1.0/power(-e) | otherwise = fromInteger (10^e) -- integers and naturals int = do{ f <- lexeme sign ; n <- nat ; return (f n) } -- sign :: CharParser st (Integer -> Integer) sign = (char '-' >> return negate) <|> (char '+' >> return id) <|> return id nat = zeroNumber <|> decimal zeroNumber = do{ char '0' ; hexadecimal <|> octal <|> decimal <|> return 0 } "" decimal = number 10 digit hexadecimal = do{ char 'x'; number 16 hexDigit } octal = do{ char 'o'; number 8 octDigit } binary = do{ char 'b'; number 2 (oneOf "01") } -- number :: Integer -> CharParser st Char -> CharParser st Integer number base baseDigit = do{ digits <- many1 baseDigit ; let n = foldl (\x d -> base*x + toInteger (digitToInt d)) 0 digits ; seq n (return n) } singleQuoted = lexeme ( do{ str <- between (char '\'') (char '\'' "end of string") (many singleStrChar) ; return (foldr (id (:)) "" str) } "literal string") singleStrChar = quotedQuote <|> noneOf "'" quotedQuote = do char '\\' anyChar