Includes better error handling, additional tests, parsing and lexing
fixes to match the desired behavior defined by the new tests, and a very
basic REPL implementation.
This commit is contained in:
2024-12-20 11:38:09 -06:00
committed by James Eversole
parent 2a63942cdb
commit b3583c796e
8 changed files with 234 additions and 136 deletions

View File

@ -4,7 +4,9 @@ import Research
import Text.Megaparsec
import Text.Megaparsec.Char
import Data.Void
import qualified Data.Set as Set
-- Lexer type and tokens
type Lexer = Parsec Void String
data LToken
= LKeywordT
@ -19,6 +21,7 @@ data LToken
| LNewline
deriving (Show, Eq, Ord)
-- Lexical rules
keywordT :: Lexer LToken
keywordT = string "t" *> notFollowedBy alphaNumChar *> pure LKeywordT
@ -38,8 +41,11 @@ stringLiteral :: Lexer LToken
stringLiteral = do
char '"'
content <- many (noneOf ['"'])
char '"' --"
return (LStringLiteral content)
if null content
then fail "Empty string literals are not allowed"
else do
char '"' -- "
return (LStringLiteral content)
assign :: Lexer LToken
assign = char '=' *> pure LAssign
@ -59,13 +65,15 @@ closeBracket = char ']' *> pure LCloseBracket
lnewline :: Lexer LToken
lnewline = char '\n' *> pure LNewline
-- Whitespace consumer
sc :: Lexer ()
sc = skipMany (char ' ' <|> char '\t')
-- Lexer definition
saplingLexer :: Lexer [LToken]
saplingLexer = many (sc *> choice
[ try keywordT
, try identifier
[ try identifier
, try keywordT
, try integerLiteral
, try stringLiteral
, assign
@ -74,8 +82,10 @@ saplingLexer = many (sc *> choice
, openBracket
, closeBracket
, lnewline
]) <* eof
] <* sc) <* eof
-- Lexing function with enhanced error handling
lexSapling :: String -> [LToken]
lexSapling input = case runParser saplingLexer "" input of
Left err -> error "Failed to lex input"
Left err -> error $ "Lexical error:\n" ++ errorBundlePretty err
Right tokens -> tokens