Skip to content

Instantly share code, notes, and snippets.

@dannypsnl
Forked from osa1/Lexer.hs
Created August 23, 2019 03:35
Show Gist options
  • Save dannypsnl/a12b171bb089d1650aeb7f9a93ac02cc to your computer and use it in GitHub Desktop.
Save dannypsnl/a12b171bb089d1650aeb7f9a93ac02cc to your computer and use it in GitHub Desktop.
separated lexing and parsing stages in parsec
module Lexer
( Token(..)
, TokenPos
, tokenize
) where
import Text.ParserCombinators.Parsec hiding (token, tokens)
import Control.Applicative ((<*), (*>), (<$>), (<*>))
data Token = Ide String
| Number String
| Bool String
| LBrack
| RBrack
| LBrace
| RBrace
| Keyword String
deriving (Show, Eq)
type TokenPos = (Token, SourcePos)
ide :: Parser TokenPos
ide = do
pos <- getPosition
fc <- oneOf firstChar
r <- optionMaybe (many $ oneOf rest)
spaces
return $ flip (,) pos $ case r of
Nothing -> Ide [fc]
Just s -> Ide $ [fc] ++ s
where firstChar = ['A'..'Z'] ++ ['a'..'z'] ++ "_"
rest = firstChar ++ ['0'..'9']
parsePos :: Parser Token -> Parser TokenPos
parsePos p = (,) <$> p <*> getPosition
lbrack, rbrack, lbrace, rbrace :: Parser TokenPos
lbrack = parsePos $ char '[' >> return LBrack
rbrack = parsePos $ char ']' >> return RBrack
lbrace = parsePos $ char '{' >> return LBrace
rbrace = parsePos $ char '}' >> return RBrace
token :: Parser TokenPos
token = choice
[ ide
, lbrack
, rbrack
, lbrace
, rbrace
]
tokens :: Parser [TokenPos]
tokens = spaces *> many (token <* spaces)
tokenize :: SourceName -> String -> Either ParseError [TokenPos]
tokenize = runParser tokens ()
{-# LANGUAGE FlexibleContexts #-}
module Parser where
import Text.Parsec as P
import Control.Monad.Identity
import Lexer
parseTest :: Show a => Parsec [TokenPos] () a -> String -> IO ()
parseTest p s =
case tokenize "test" s of
Left e -> putStrLn $ show e
Right ts' -> P.parseTest p ts'
type Parser a = Parsec [TokenPos] () a
advance :: SourcePos -> t -> [TokenPos] -> SourcePos
advance _ _ ((_, pos) : _) = pos
advance pos _ [] = pos
satisfy :: (TokenPos -> Bool) -> Parser Token
satisfy f = tokenPrim show
advance
(\c -> if f c then Just (fst c) else Nothing)
tok :: Token -> Parser Token
tok t = (Parser.satisfy $ (== t) . fst) <?> show t
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment