2024-12-18 18:55:51 -06:00
|
|
|
module Parser where
|
|
|
|
|
|
|
|
import Lexer
|
2024-12-20 11:38:09 -06:00
|
|
|
import Research hiding (toList)
|
2024-12-29 20:29:41 -06:00
|
|
|
|
2024-12-20 11:38:09 -06:00
|
|
|
import Data.List.NonEmpty (toList)
|
2024-12-29 20:29:41 -06:00
|
|
|
import Data.Void (Void)
|
2024-12-18 18:55:51 -06:00
|
|
|
import Text.Megaparsec
|
|
|
|
import Text.Megaparsec.Char
|
2024-12-20 11:38:09 -06:00
|
|
|
import Text.Megaparsec.Error (errorBundlePretty, ParseErrorBundle)
|
2024-12-18 18:55:51 -06:00
|
|
|
|
2024-12-29 20:29:41 -06:00
|
|
|
import qualified Data.Set as Set
|
|
|
|
|
2024-12-30 08:30:40 -06:00
|
|
|
type Parser = Parsec Void [LToken]
|
|
|
|
type AltParser = Parsec Void String
|
2024-12-27 12:27:00 -06:00
|
|
|
|
2024-12-29 08:29:25 -06:00
|
|
|
data TricuAST
|
2024-12-27 12:27:00 -06:00
|
|
|
= SVar String
|
|
|
|
| SInt Int
|
|
|
|
| SStr String
|
2024-12-29 08:29:25 -06:00
|
|
|
| SList [TricuAST]
|
|
|
|
| SFunc String [String] TricuAST
|
|
|
|
| SApp TricuAST TricuAST
|
2024-12-18 18:55:51 -06:00
|
|
|
| TLeaf
|
2024-12-29 08:29:25 -06:00
|
|
|
| TStem TricuAST
|
|
|
|
| TFork TricuAST TricuAST
|
|
|
|
| SLambda [String] TricuAST
|
2024-12-29 20:29:41 -06:00
|
|
|
| SEmpty
|
2024-12-18 18:55:51 -06:00
|
|
|
deriving (Show, Eq, Ord)
|
|
|
|
|
2024-12-29 08:29:25 -06:00
|
|
|
parseTricu :: String -> [TricuAST]
|
2024-12-29 20:29:41 -06:00
|
|
|
parseTricu input
|
|
|
|
| null tokens = []
|
|
|
|
| otherwise = map parseSingle tokens
|
|
|
|
where
|
|
|
|
tokens = case lexTricu input of
|
|
|
|
[] -> []
|
|
|
|
tokens -> lines input
|
2024-12-20 11:38:09 -06:00
|
|
|
|
2024-12-29 08:29:25 -06:00
|
|
|
parseSingle :: String -> TricuAST
|
2024-12-29 20:29:41 -06:00
|
|
|
parseSingle input = case lexTricu input of
|
|
|
|
[] -> SEmpty
|
|
|
|
tokens -> case runParser parseExpression "" tokens of
|
|
|
|
Left err -> error $ handleParseError err
|
|
|
|
Right ast -> ast
|
2024-12-18 18:55:51 -06:00
|
|
|
|
2024-12-29 08:29:25 -06:00
|
|
|
parseExpression :: Parser TricuAST
|
2024-12-18 18:55:51 -06:00
|
|
|
parseExpression = choice
|
|
|
|
[ try parseFunction
|
2024-12-27 08:17:06 -06:00
|
|
|
, try parseLambda
|
2024-12-27 12:27:00 -06:00
|
|
|
, try parseLambdaExpression
|
2024-12-27 08:17:06 -06:00
|
|
|
, try parseListLiteral
|
2024-12-18 18:55:51 -06:00
|
|
|
, try parseApplication
|
2024-12-27 08:17:06 -06:00
|
|
|
, try parseTreeTerm
|
2024-12-18 18:55:51 -06:00
|
|
|
, parseLiteral
|
|
|
|
]
|
|
|
|
|
2024-12-29 12:22:24 -06:00
|
|
|
scnParser :: Parser ()
|
|
|
|
scnParser = skipMany (satisfy isNewline)
|
|
|
|
|
2024-12-29 08:29:25 -06:00
|
|
|
parseFunction :: Parser TricuAST
|
2024-12-18 18:55:51 -06:00
|
|
|
parseFunction = do
|
|
|
|
LIdentifier name <- satisfy isIdentifier
|
|
|
|
args <- many (satisfy isIdentifier)
|
|
|
|
satisfy (== LAssign)
|
|
|
|
body <- parseExpression
|
|
|
|
return (SFunc name (map getIdentifier args) body)
|
|
|
|
|
2024-12-29 08:29:25 -06:00
|
|
|
parseAtomicBase :: Parser TricuAST
|
2024-12-27 12:27:00 -06:00
|
|
|
parseAtomicBase = choice
|
|
|
|
[ try parseVarWithoutAssignment
|
|
|
|
, parseTreeLeaf
|
|
|
|
, parseGrouped
|
|
|
|
]
|
2024-12-29 08:29:25 -06:00
|
|
|
parseVarWithoutAssignment :: Parser TricuAST
|
2024-12-27 12:27:00 -06:00
|
|
|
parseVarWithoutAssignment = do
|
|
|
|
LIdentifier name <- satisfy isIdentifier
|
|
|
|
if (name == "t" || name == "__result")
|
|
|
|
then fail $ "Reserved keyword: " ++ name ++ " cannot be assigned."
|
|
|
|
else notFollowedBy (satisfy (== LAssign)) *> return (SVar name)
|
|
|
|
|
2024-12-29 08:29:25 -06:00
|
|
|
parseLambda :: Parser TricuAST
|
2024-12-27 08:17:06 -06:00
|
|
|
parseLambda = between (satisfy (== LOpenParen)) (satisfy (== LCloseParen)) $ do
|
|
|
|
satisfy (== LBackslash)
|
2024-12-28 07:24:19 -06:00
|
|
|
param <- satisfy isIdentifier
|
|
|
|
rest <- many (satisfy isIdentifier)
|
2024-12-27 08:17:06 -06:00
|
|
|
satisfy (== LColon)
|
2024-12-28 07:24:19 -06:00
|
|
|
body <- parseLambdaExpression
|
2024-12-27 08:17:06 -06:00
|
|
|
let nestedLambda = foldr (\v acc -> SLambda [v] acc) body (map getIdentifier rest)
|
|
|
|
return (SLambda [getIdentifier param] nestedLambda)
|
|
|
|
|
2024-12-29 08:29:25 -06:00
|
|
|
parseLambdaExpression :: Parser TricuAST
|
2024-12-27 08:17:06 -06:00
|
|
|
parseLambdaExpression = choice
|
|
|
|
[ try parseLambdaApplication
|
|
|
|
, parseAtomicLambda
|
|
|
|
]
|
|
|
|
|
2024-12-29 08:29:25 -06:00
|
|
|
parseAtomicLambda :: Parser TricuAST
|
2024-12-27 08:17:06 -06:00
|
|
|
parseAtomicLambda = choice
|
|
|
|
[ parseVar
|
|
|
|
, parseTreeLeaf
|
|
|
|
, parseLiteral
|
|
|
|
, parseListLiteral
|
2024-12-27 12:27:00 -06:00
|
|
|
, try parseLambda
|
2024-12-27 08:17:06 -06:00
|
|
|
, between (satisfy (== LOpenParen)) (satisfy (== LCloseParen)) parseLambdaExpression
|
|
|
|
]
|
|
|
|
|
2024-12-29 08:29:25 -06:00
|
|
|
parseApplication :: Parser TricuAST
|
2024-12-18 18:55:51 -06:00
|
|
|
parseApplication = do
|
2024-12-19 18:57:57 -06:00
|
|
|
func <- parseAtomicBase
|
2024-12-27 08:17:06 -06:00
|
|
|
args <- many parseAtomic
|
|
|
|
return $ foldl (\acc arg -> SApp acc arg) func args
|
|
|
|
|
2024-12-29 08:29:25 -06:00
|
|
|
parseLambdaApplication :: Parser TricuAST
|
2024-12-27 08:17:06 -06:00
|
|
|
parseLambdaApplication = do
|
2024-12-27 12:27:00 -06:00
|
|
|
func <- parseAtomicLambda
|
|
|
|
args <- many parseAtomicLambda
|
|
|
|
return $ foldl (\acc arg -> SApp acc arg) func args
|
2024-12-19 18:57:57 -06:00
|
|
|
|
2024-12-29 08:29:25 -06:00
|
|
|
isTreeTerm :: TricuAST -> Bool
|
2024-12-27 12:27:00 -06:00
|
|
|
isTreeTerm TLeaf = True
|
|
|
|
isTreeTerm (TStem _) = True
|
2024-12-19 18:57:57 -06:00
|
|
|
isTreeTerm (TFork _ _) = True
|
2024-12-27 12:27:00 -06:00
|
|
|
isTreeTerm _ = False
|
2024-12-19 18:57:57 -06:00
|
|
|
|
2024-12-29 08:29:25 -06:00
|
|
|
parseTreeLeaf :: Parser TricuAST
|
2024-12-20 11:38:09 -06:00
|
|
|
parseTreeLeaf = satisfy isKeywordT *> notFollowedBy (satisfy (== LAssign)) *> pure TLeaf
|
2024-12-18 18:55:51 -06:00
|
|
|
|
|
|
|
getIdentifier :: LToken -> String
|
|
|
|
getIdentifier (LIdentifier name) = name
|
|
|
|
getIdentifier _ = error "Expected identifier"
|
|
|
|
|
2024-12-29 08:29:25 -06:00
|
|
|
parseTreeTerm :: Parser TricuAST
|
2024-12-18 18:55:51 -06:00
|
|
|
parseTreeTerm = do
|
|
|
|
base <- parseTreeLeafOrParenthesized
|
|
|
|
rest <- many parseTreeLeafOrParenthesized
|
|
|
|
pure $ foldl combine base rest
|
|
|
|
where
|
|
|
|
combine acc next = case acc of
|
2024-12-27 12:27:00 -06:00
|
|
|
TLeaf -> TStem next
|
|
|
|
TStem t -> TFork t next
|
2024-12-18 18:55:51 -06:00
|
|
|
TFork _ _ -> TFork acc next
|
|
|
|
|
2024-12-29 08:29:25 -06:00
|
|
|
parseTreeLeafOrParenthesized :: Parser TricuAST
|
2024-12-18 18:55:51 -06:00
|
|
|
parseTreeLeafOrParenthesized = choice
|
|
|
|
[ between (satisfy (== LOpenParen)) (satisfy (== LCloseParen)) parseTreeTerm
|
2024-12-20 11:38:09 -06:00
|
|
|
, parseTreeLeaf
|
2024-12-18 18:55:51 -06:00
|
|
|
]
|
|
|
|
|
2024-12-29 08:29:25 -06:00
|
|
|
foldTree :: [TricuAST] -> TricuAST
|
2024-12-18 18:55:51 -06:00
|
|
|
foldTree [] = TLeaf
|
|
|
|
foldTree [x] = x
|
|
|
|
foldTree (x:y:rest) = TFork x (foldTree (y:rest))
|
|
|
|
|
2024-12-29 08:29:25 -06:00
|
|
|
parseAtomic :: Parser TricuAST
|
2024-12-18 18:55:51 -06:00
|
|
|
parseAtomic = choice
|
|
|
|
[ parseVar
|
2024-12-27 08:17:06 -06:00
|
|
|
, parseTreeLeaf
|
2024-12-18 18:55:51 -06:00
|
|
|
, parseListLiteral
|
2024-12-27 08:17:06 -06:00
|
|
|
, parseGrouped
|
|
|
|
, parseLiteral
|
2024-12-18 18:55:51 -06:00
|
|
|
]
|
|
|
|
|
2024-12-29 08:29:25 -06:00
|
|
|
parseGrouped :: Parser TricuAST
|
2024-12-27 08:17:06 -06:00
|
|
|
parseGrouped = between (satisfy (== LOpenParen)) (satisfy (== LCloseParen)) parseExpression
|
2024-12-20 11:38:09 -06:00
|
|
|
|
2024-12-29 08:29:25 -06:00
|
|
|
parseLiteral :: Parser TricuAST
|
2024-12-18 18:55:51 -06:00
|
|
|
parseLiteral = choice
|
|
|
|
[ parseIntLiteral
|
|
|
|
, parseStrLiteral
|
|
|
|
]
|
|
|
|
|
2024-12-29 08:29:25 -06:00
|
|
|
parens :: Parser TricuAST -> Parser TricuAST
|
2024-12-19 18:57:57 -06:00
|
|
|
parens p = do
|
|
|
|
satisfy (== LOpenParen)
|
|
|
|
result <- p
|
|
|
|
satisfy (== LCloseParen)
|
|
|
|
return result
|
|
|
|
|
2024-12-29 08:29:25 -06:00
|
|
|
parseListLiteral :: Parser TricuAST
|
2024-12-18 18:55:51 -06:00
|
|
|
parseListLiteral = do
|
2024-12-19 18:57:57 -06:00
|
|
|
satisfy (== LOpenBracket)
|
|
|
|
elements <- many parseListItem
|
2024-12-18 18:55:51 -06:00
|
|
|
satisfy (== LCloseBracket)
|
|
|
|
return (SList elements)
|
|
|
|
|
2024-12-29 08:29:25 -06:00
|
|
|
parseListItem :: Parser TricuAST
|
2024-12-19 19:53:32 -06:00
|
|
|
parseListItem = choice
|
2024-12-20 11:38:09 -06:00
|
|
|
[ parseGroupedItem
|
|
|
|
, parseListLiteral
|
|
|
|
, parseSingleItem
|
2024-12-19 19:53:32 -06:00
|
|
|
]
|
2024-12-19 18:57:57 -06:00
|
|
|
|
2024-12-29 08:29:25 -06:00
|
|
|
parseGroupedItem :: Parser TricuAST
|
2024-12-19 18:57:57 -06:00
|
|
|
parseGroupedItem = do
|
2024-12-20 11:38:09 -06:00
|
|
|
satisfy (== LOpenParen)
|
2024-12-19 18:57:57 -06:00
|
|
|
inner <- parseExpression
|
|
|
|
satisfy (== LCloseParen)
|
|
|
|
return inner
|
|
|
|
|
2024-12-29 08:29:25 -06:00
|
|
|
parseSingleItem :: Parser TricuAST
|
2024-12-19 18:57:57 -06:00
|
|
|
parseSingleItem = do
|
2024-12-20 11:38:09 -06:00
|
|
|
token <- satisfy isListItem
|
2024-12-19 18:57:57 -06:00
|
|
|
case token of
|
|
|
|
LIdentifier name -> return (SVar name)
|
2024-12-27 12:27:00 -06:00
|
|
|
LKeywordT -> return TLeaf
|
|
|
|
_ -> fail "Unexpected token in list item"
|
2024-12-19 18:57:57 -06:00
|
|
|
|
|
|
|
isListItem :: LToken -> Bool
|
|
|
|
isListItem (LIdentifier _) = True
|
|
|
|
isListItem LKeywordT = True
|
|
|
|
isListItem _ = False
|
|
|
|
|
2024-12-29 08:29:25 -06:00
|
|
|
parseVar :: Parser TricuAST
|
2024-12-20 11:38:09 -06:00
|
|
|
parseVar = do
|
2024-12-18 18:55:51 -06:00
|
|
|
LIdentifier name <- satisfy isIdentifier
|
2024-12-20 11:38:09 -06:00
|
|
|
if (name == "t" || name == "__result")
|
|
|
|
then fail $ "Reserved keyword: " ++ name ++ " cannot be assigned."
|
|
|
|
else return (SVar name)
|
2024-12-18 18:55:51 -06:00
|
|
|
|
2024-12-29 08:29:25 -06:00
|
|
|
parseIntLiteral :: Parser TricuAST
|
2024-12-18 18:55:51 -06:00
|
|
|
parseIntLiteral = do
|
|
|
|
LIntegerLiteral value <- satisfy isIntegerLiteral
|
|
|
|
return (SInt value)
|
|
|
|
|
2024-12-29 08:29:25 -06:00
|
|
|
parseStrLiteral :: Parser TricuAST
|
2024-12-18 18:55:51 -06:00
|
|
|
parseStrLiteral = do
|
|
|
|
LStringLiteral value <- satisfy isStringLiteral
|
|
|
|
return (SStr value)
|
|
|
|
|
2024-12-19 18:57:57 -06:00
|
|
|
-- Boolean Helpers
|
2024-12-27 12:27:00 -06:00
|
|
|
isKeywordT (LKeywordT) = True
|
|
|
|
isKeywordT _ = False
|
|
|
|
isIdentifier (LIdentifier _) = True
|
|
|
|
isIdentifier _ = False
|
2024-12-18 18:55:51 -06:00
|
|
|
isIntegerLiteral (LIntegerLiteral _) = True
|
2024-12-27 12:27:00 -06:00
|
|
|
isIntegerLiteral _ = False
|
|
|
|
isStringLiteral (LStringLiteral _) = True
|
|
|
|
isStringLiteral _ = False
|
|
|
|
isLiteral (LIntegerLiteral _) = True
|
|
|
|
isLiteral (LStringLiteral _) = True
|
|
|
|
isLiteral _ = False
|
|
|
|
isNewline (LNewline) = True
|
|
|
|
isNewline _ = False
|
2024-12-20 11:38:09 -06:00
|
|
|
|
2024-12-30 08:30:40 -06:00
|
|
|
-- Alternative parsers
|
|
|
|
altSC :: AltParser ()
|
|
|
|
altSC = skipMany (char ' ' <|> char '\t' <|> char '\n')
|
|
|
|
|
|
|
|
parseTernaryTerm :: AltParser TricuAST
|
|
|
|
parseTernaryTerm = do
|
|
|
|
altSC
|
|
|
|
term <- choice parseTernaryTerm'
|
|
|
|
altSC
|
|
|
|
pure term
|
|
|
|
where
|
|
|
|
parseTernaryTerm' =
|
|
|
|
[ try (between (char '(') (char ')') parseTernaryTerm)
|
|
|
|
, try parseTernaryLeaf
|
|
|
|
, try parseTernaryStem
|
|
|
|
, try parseTernaryFork
|
|
|
|
]
|
|
|
|
|
|
|
|
parseTernaryLeaf :: AltParser TricuAST
|
|
|
|
parseTernaryLeaf = char '0' *> pure TLeaf
|
|
|
|
|
|
|
|
parseTernaryStem :: AltParser TricuAST
|
|
|
|
parseTernaryStem = char '1' *> (TStem <$> parseTernaryTerm)
|
|
|
|
|
|
|
|
parseTernaryFork :: AltParser TricuAST
|
|
|
|
parseTernaryFork = do
|
|
|
|
char '2'
|
|
|
|
term1 <- parseTernaryTerm
|
|
|
|
term2 <- parseTernaryTerm
|
|
|
|
pure $ TFork term1 term2
|
|
|
|
|
|
|
|
parseTernary :: String -> Either String TricuAST
|
|
|
|
parseTernary input = case runParser (parseTernaryTerm <* eof) "" input of
|
|
|
|
Left err -> Left (errorBundlePretty err)
|
|
|
|
Right ast -> Right ast
|
|
|
|
|
2024-12-20 11:38:09 -06:00
|
|
|
-- Error Handling
|
|
|
|
handleParseError :: ParseErrorBundle [LToken] Void -> String
|
|
|
|
handleParseError bundle =
|
|
|
|
let errors = bundleErrors bundle
|
|
|
|
errorList = toList errors
|
|
|
|
formattedErrors = map showError errorList
|
|
|
|
in unlines ("Parse error(s) encountered:" : formattedErrors)
|
|
|
|
|
|
|
|
showError :: ParseError [LToken] Void -> String
|
|
|
|
showError (TrivialError offset (Just (Tokens tokenStream)) expected) =
|
|
|
|
"Parse error at offset " ++ show offset ++ ": unexpected token "
|
2024-12-27 12:27:00 -06:00
|
|
|
++ show tokenStream ++ ", expected one of " ++ show (Set.toList expected)
|
2024-12-20 11:38:09 -06:00
|
|
|
showError (FancyError offset fancy) =
|
|
|
|
"Parse error at offset " ++ show offset ++ ":\n " ++ unlines (map show (Set.toList fancy))
|
|
|
|
showError (TrivialError offset Nothing expected) =
|
|
|
|
"Parse error at offset " ++ show offset ++ ": expected one of "
|
2024-12-27 12:27:00 -06:00
|
|
|
++ show (Set.toList expected)
|