module Parser.Lexer (
Parser,
sc,
lexeme,
symbol,
pKeyword,
pIdentifier,
parens,
braces,
semicolon,
comma,
colon,
withPos
) where
import Text.Megaparsec
import Text.Megaparsec.Char
import qualified Text.Megaparsec.Char.Lexer as L
import Data.Void
import qualified Data.Text as DT
import AST.Ast (Ast(..))
type Parser = Parsec Void DT.Text
sc :: Parser ()
sc :: Parser ()
sc = Parser () -> Parser () -> Parser () -> Parser ()
forall e s (m :: * -> *).
MonadParsec e s m =>
m () -> m () -> m () -> m ()
L.space
Parser ()
forall e s (m :: * -> *).
(MonadParsec e s m, Token s ~ Char) =>
m ()
space1
(Tokens Text -> Parser ()
forall e s (m :: * -> *).
(MonadParsec e s m, Token s ~ Char) =>
Tokens s -> m ()
L.skipLineComment (String -> Text
DT.pack String
"//"))
(Tokens Text -> Tokens Text -> Parser ()
forall e s (m :: * -> *).
MonadParsec e s m =>
Tokens s -> Tokens s -> m ()
L.skipBlockComment (String -> Text
DT.pack String
"/*") (String -> Text
DT.pack String
"*/"))
lexeme :: Parser a -> Parser a
lexeme :: forall a. Parser a -> Parser a
lexeme = Parser ()
-> ParsecT Void Text Identity a -> ParsecT Void Text Identity a
forall e s (m :: * -> *) a. MonadParsec e s m => m () -> m a -> m a
L.lexeme Parser ()
sc
symbol :: DT.Text -> Parser DT.Text
symbol :: Text -> Parser Text
symbol = Parser ()
-> Tokens Text -> ParsecT Void Text Identity (Tokens Text)
forall e s (m :: * -> *).
MonadParsec e s m =>
m () -> Tokens s -> m (Tokens s)
L.symbol Parser ()
sc
parens :: Parser a -> Parser a
parens :: forall a. Parser a -> Parser a
parens = Parser Text
-> Parser Text
-> ParsecT Void Text Identity a
-> ParsecT Void Text Identity a
forall (m :: * -> *) open close a.
Applicative m =>
m open -> m close -> m a -> m a
between (Text -> Parser Text
symbol (String -> Text
DT.pack String
"(")) (Text -> Parser Text
symbol (String -> Text
DT.pack String
")"))
braces :: Parser a -> Parser a
braces :: forall a. Parser a -> Parser a
braces = Parser Text
-> Parser Text
-> ParsecT Void Text Identity a
-> ParsecT Void Text Identity a
forall (m :: * -> *) open close a.
Applicative m =>
m open -> m close -> m a -> m a
between (Text -> Parser Text
symbol (String -> Text
DT.pack String
"{")) (Text -> Parser Text
symbol (String -> Text
DT.pack String
"}"))
semicolon :: Parser DT.Text
semicolon :: Parser Text
semicolon = Text -> Parser Text
symbol (String -> Text
DT.pack String
";")
comma :: Parser DT.Text
comma :: Parser Text
comma = Text -> Parser Text
symbol (String -> Text
DT.pack String
",")
colon :: Parser DT.Text
colon :: Parser Text
colon = Text -> Parser Text
symbol (String -> Text
DT.pack String
":")
withPos :: Parser Ast -> Parser Ast
withPos :: Parser Ast -> Parser Ast
withPos Parser Ast
p = do
pos <- ParsecT Void Text Identity SourcePos
forall s e (m :: * -> *).
(TraversableStream s, MonadParsec e s m) =>
m SourcePos
getSourcePos
node <- p
return (APos (unPos (sourceLine pos)) (unPos (sourceColumn pos)) node)
reservedWords :: [DT.Text]
reservedWords :: [Text]
reservedWords = (String -> Text) -> [String] -> [Text]
forall a b. (a -> b) -> [a] -> [b]
map String -> Text
DT.pack [String
"func", String
"ret", String
"if", String
"else", String
"int",
String
"bool", String
"void", String
"while", String
"lambda", String
"break"]
pKeyword :: DT.Text -> Parser DT.Text
pKeyword :: Text -> Parser Text
pKeyword Text
w = Parser Text -> Parser Text
forall a. Parser a -> Parser a
lexeme (Tokens Text -> ParsecT Void Text Identity (Tokens Text)
forall e s (m :: * -> *).
MonadParsec e s m =>
Tokens s -> m (Tokens s)
string Text
Tokens Text
w Parser Text -> Parser () -> Parser Text
forall a b.
ParsecT Void Text Identity a
-> ParsecT Void Text Identity b -> ParsecT Void Text Identity a
forall (f :: * -> *) a b. Applicative f => f a -> f b -> f a
<* ParsecT Void Text Identity Char -> Parser ()
forall a. ParsecT Void Text Identity a -> Parser ()
forall e s (m :: * -> *) a. MonadParsec e s m => m a -> m ()
notFollowedBy ParsecT Void Text Identity Char
ParsecT Void Text Identity (Token Text)
forall e s (m :: * -> *).
(MonadParsec e s m, Token s ~ Char) =>
m (Token s)
alphaNumChar)
pIdentifier :: Parser DT.Text
pIdentifier :: Parser Text
pIdentifier = (Parser Text -> Parser Text
forall a. Parser a -> Parser a
lexeme (Parser Text -> Parser Text) -> Parser Text -> Parser Text
forall a b. (a -> b) -> a -> b
$ do
first <- ParsecT Void Text Identity Char
ParsecT Void Text Identity (Token Text)
forall e s (m :: * -> *).
(MonadParsec e s m, Token s ~ Char) =>
m (Token s)
letterChar ParsecT Void Text Identity Char
-> ParsecT Void Text Identity Char
-> ParsecT Void Text Identity Char
forall a.
ParsecT Void Text Identity a
-> ParsecT Void Text Identity a -> ParsecT Void Text Identity a
forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> Token Text -> ParsecT Void Text Identity (Token Text)
forall e s (m :: * -> *).
(MonadParsec e s m, Token s ~ Char) =>
Token s -> m (Token s)
char Char
Token Text
'_'
rest <- many (alphaNumChar <|> char '_')
let name = String -> Text
DT.pack (Char
first Char -> String -> String
forall a. a -> [a] -> [a]
: String
rest)
if name `elem` reservedWords
then fail $
"Keyword '" ++ DT.unpack name ++ "' cannot be an identifier"
else return name) Parser Text -> String -> Parser Text
forall e s (m :: * -> *) a.
MonadParsec e s m =>
m a -> String -> m a
<?> String
"identifier"