packages feed

Elm-0.1.0: src/Parse/Lexer.hs

module Lexer (tokenize) where

import Data.Char (isSymbol)
import Text.Parsec.Char
import Text.Parsec.Combinator
import Text.ParserCombinators.Parsec.Prim (parse,(<|>),many,try)
import Tokens

token = do { integer >>= return . NUMBER }
    <|> whitespace
    <|> chrs [ ('(',LPAREN)  , (')',RPAREN)
             , ('{',LBRACE)  , ('}',RBRACE)
             , ('[',LBRACKET), (']',RBRACKET)
             , (',',COMMA)   , (';',SEMI), ('_',UNDERSCORE)
             , ('\\',LAMBDA) , ('\x03BB',LAMBDA) ]
    <|> reserveds [ ("True",TRUE), ("False",FALSE)
                  , ("if",IF), ("then",THEN), ("else",ELSE)
                  , ("case",CASE), ("of",OF), ("data", DATA) 
                  , ("let",LET), ("in",IN) ]
    <|> do { char '`'; v <- variable; char '`'; return $ OP v }
    <|> anyOp
    <|> do { char '"'; s <- many $ backslashed <|> satisfy (/='"'); char '"'
           ; return $ STRING s}
    <|> do { char '\''; c <- backslashed <|> satisfy (/='\''); char '\''
           ; return $ CHAR c}
    <|> do { variable >>= return . ID }
    <|> typeVar
    <|> do { try $ string "\r\n" <|> string "\n"; return NEWLINE }

str s t = do { try $ string s; return t }
chrs = choice . map (uncurry chr)
chr c t = do { char c; return t }
reserveds = choice . map (uncurry reserved)
reserved str token =
    try $ do {string str; notFollowedBy $ alphaNum <|> char '_'; return token }
anyOp = do op <- many1 (satisfy isSymbol <|> oneOf "+-/*=.$<>:&|^?%#@~!")
           case op of { ".." -> return DOT2
                      ; "->" -> return ARROW; "\8594" -> return ARROW
                      ; _ -> return $ OP op }

backslashed = do { char '\\'; c <- satisfy (\x -> True)
                 ; return . read $ ['\'','\\',c,'\''] }

integer = return . read =<< many1 digit
variable = do
  shd <- letter <|> char '_'
  stl <- many $ alphaNum <|> char '_' <|> char '\''
  return $ shd:stl
typeVar = do
  shd <- upper
  stl <- many $ alphaNum <|> char '_' <|> char '\''
  return . TYPE $ shd:stl


----  White Space and comments  ----

whitespace = (lineComment >> return NEWLINE) <|>
             (many1 (multiComment <|> many1 (char ' ')) >> return SPACES)
lineComment = do try $ string "--"
                 manyTill anyChar $ newline <|> (eof >> return '\n')

multiComment = do { try $ string "{-"; closeComment }
closeComment = manyTill anyChar . choice $
               [ try $ string "-}"
               , do { try $ string "{-"; closeComment; closeComment }
               ]

token_parser = many1 token

tokenize s = case parse token_parser "" s of
               Right ts -> Right ts
               Left err -> Left $ "Syntax error: " ++ show err