module Lexer where import Research import Text.Megaparsec import Text.Megaparsec.Char import Data.Void type Lexer = Parsec Void String data LToken = LKeywordT | LIdentifier String | LIntegerLiteral Int | LStringLiteral String | LAssign | LOpenParen | LCloseParen | LOpenBracket | LCloseBracket | LNewline deriving (Show, Eq, Ord) keywordT :: Lexer LToken keywordT = string "t" *> notFollowedBy alphaNumChar *> pure LKeywordT identifier :: Lexer LToken identifier = do name <- some (letterChar <|> char '_' <|> char '-') if name == "t" then fail "Keyword 't' cannot be used as an identifier" else return (LIdentifier name) integerLiteral :: Lexer LToken integerLiteral = do num <- some digitChar return (LIntegerLiteral (read num)) stringLiteral :: Lexer LToken stringLiteral = do char '"' content <- many (noneOf ['"']) char '"' --" return (LStringLiteral content) assign :: Lexer LToken assign = char '=' *> pure LAssign openParen :: Lexer LToken openParen = char '(' *> pure LOpenParen closeParen :: Lexer LToken closeParen = char ')' *> pure LCloseParen openBracket :: Lexer LToken openBracket = char '[' *> pure LOpenBracket closeBracket :: Lexer LToken closeBracket = char ']' *> pure LCloseBracket lnewline :: Lexer LToken lnewline = char '\n' *> pure LNewline sc :: Lexer () sc = skipMany (char ' ' <|> char '\t') saplingLexer :: Lexer [LToken] saplingLexer = many (sc *> choice [ try keywordT , try identifier , try integerLiteral , try stringLiteral , assign , openParen , closeParen , openBracket , closeBracket , lnewline ]) <* eof lexSapling input = case runParser saplingLexer "" input of Left err -> error "Failed to lex input" Right tokens -> tokens