Somewhat working lambdas
Architectural changes to lambda evaluation and parsing to allow for correct expression evaluation. Contains several failing AI-generated tests and we're still failing tests for erroring incomplete definitions
This commit is contained in:
100
src/Parser.hs
100
src/Parser.hs
@ -1,10 +1,8 @@
|
||||
module Parser where
|
||||
|
||||
import Debug.Trace
|
||||
|
||||
import Lexer
|
||||
import Research hiding (toList)
|
||||
|
||||
import Control.Exception (throw)
|
||||
import Data.List.NonEmpty (toList)
|
||||
import qualified Data.Set as Set
|
||||
@ -14,17 +12,18 @@ import Text.Megaparsec.Char
|
||||
import Text.Megaparsec.Error (errorBundlePretty, ParseErrorBundle)
|
||||
|
||||
type Parser = Parsec Void [LToken]
|
||||
|
||||
data SaplingAST
|
||||
= SVar String
|
||||
| SInt Int
|
||||
| SStr String
|
||||
| SList [SaplingAST]
|
||||
| SFunc String [String] SaplingAST
|
||||
| SApp SaplingAST SaplingAST
|
||||
= SVar String
|
||||
| SInt Int
|
||||
| SStr String
|
||||
| SList [SaplingAST]
|
||||
| SFunc String [String] SaplingAST
|
||||
| SApp SaplingAST SaplingAST
|
||||
| TLeaf
|
||||
| TStem SaplingAST
|
||||
| TFork SaplingAST SaplingAST
|
||||
| SLambda [String] SaplingAST
|
||||
| TStem SaplingAST
|
||||
| TFork SaplingAST SaplingAST
|
||||
| SLambda [String] SaplingAST
|
||||
deriving (Show, Eq, Ord)
|
||||
|
||||
parseSapling :: String -> [SaplingAST]
|
||||
@ -35,7 +34,7 @@ parseSapling input =
|
||||
parseSingle :: String -> SaplingAST
|
||||
parseSingle "" = error "Empty input provided to parseSingle"
|
||||
parseSingle input = case runParser parseExpression "" (lexSapling input) of
|
||||
Left err -> error $ handleParseError err
|
||||
Left err -> error $ handleParseError err
|
||||
Right ast -> ast
|
||||
|
||||
scnParser :: Parser ()
|
||||
@ -45,6 +44,7 @@ parseExpression :: Parser SaplingAST
|
||||
parseExpression = choice
|
||||
[ try parseFunction
|
||||
, try parseLambda
|
||||
, try parseLambdaExpression
|
||||
, try parseListLiteral
|
||||
, try parseApplication
|
||||
, try parseTreeTerm
|
||||
@ -59,6 +59,19 @@ parseFunction = do
|
||||
body <- parseExpression
|
||||
return (SFunc name (map getIdentifier args) body)
|
||||
|
||||
parseAtomicBase :: Parser SaplingAST
|
||||
parseAtomicBase = choice
|
||||
[ try parseVarWithoutAssignment
|
||||
, parseTreeLeaf
|
||||
, parseGrouped
|
||||
]
|
||||
parseVarWithoutAssignment :: Parser SaplingAST
|
||||
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)
|
||||
|
||||
parseLambda :: Parser SaplingAST
|
||||
parseLambda = between (satisfy (== LOpenParen)) (satisfy (== LCloseParen)) $ do
|
||||
satisfy (== LBackslash)
|
||||
@ -81,6 +94,7 @@ parseAtomicLambda = choice
|
||||
, parseTreeLeaf
|
||||
, parseLiteral
|
||||
, parseListLiteral
|
||||
, try parseLambda
|
||||
, between (satisfy (== LOpenParen)) (satisfy (== LCloseParen)) parseLambdaExpression
|
||||
]
|
||||
|
||||
@ -92,22 +106,15 @@ parseApplication = do
|
||||
|
||||
parseLambdaApplication :: Parser SaplingAST
|
||||
parseLambdaApplication = do
|
||||
func <- parseAtomicLambda
|
||||
args <- many parseAtomicLambda
|
||||
return $ foldl (\acc arg -> SApp acc arg) func args
|
||||
func <- parseAtomicLambda
|
||||
args <- many parseAtomicLambda
|
||||
return $ foldl (\acc arg -> SApp acc arg) func args
|
||||
|
||||
isTreeTerm :: SaplingAST -> Bool
|
||||
isTreeTerm TLeaf = True
|
||||
isTreeTerm (TStem _) = True
|
||||
isTreeTerm TLeaf = True
|
||||
isTreeTerm (TStem _) = True
|
||||
isTreeTerm (TFork _ _) = True
|
||||
isTreeTerm _ = False
|
||||
|
||||
parseAtomicBase :: Parser SaplingAST
|
||||
parseAtomicBase = choice
|
||||
[ parseVar
|
||||
, parseTreeLeaf
|
||||
, parseGrouped
|
||||
]
|
||||
isTreeTerm _ = False
|
||||
|
||||
parseTreeLeaf :: Parser SaplingAST
|
||||
parseTreeLeaf = satisfy isKeywordT *> notFollowedBy (satisfy (== LAssign)) *> pure TLeaf
|
||||
@ -123,8 +130,8 @@ parseTreeTerm = do
|
||||
pure $ foldl combine base rest
|
||||
where
|
||||
combine acc next = case acc of
|
||||
TLeaf -> TStem next
|
||||
TStem t -> TFork t next
|
||||
TLeaf -> TStem next
|
||||
TStem t -> TFork t next
|
||||
TFork _ _ -> TFork acc next
|
||||
|
||||
parseTreeLeafOrParenthesized :: Parser SaplingAST
|
||||
@ -147,7 +154,6 @@ parseAtomic = choice
|
||||
, parseLiteral
|
||||
]
|
||||
|
||||
|
||||
parseGrouped :: Parser SaplingAST
|
||||
parseGrouped = between (satisfy (== LOpenParen)) (satisfy (== LCloseParen)) parseExpression
|
||||
|
||||
@ -190,8 +196,8 @@ parseSingleItem = do
|
||||
token <- satisfy isListItem
|
||||
case token of
|
||||
LIdentifier name -> return (SVar name)
|
||||
LKeywordT -> return TLeaf
|
||||
_ -> fail "Unexpected token in list item"
|
||||
LKeywordT -> return TLeaf
|
||||
_ -> fail "Unexpected token in list item"
|
||||
|
||||
isListItem :: LToken -> Bool
|
||||
isListItem (LIdentifier _) = True
|
||||
@ -216,24 +222,19 @@ parseStrLiteral = do
|
||||
return (SStr value)
|
||||
|
||||
-- Boolean Helpers
|
||||
isKeywordT (LKeywordT) = True
|
||||
isKeywordT _ = False
|
||||
|
||||
isIdentifier (LIdentifier _) = True
|
||||
isIdentifier _ = False
|
||||
|
||||
isKeywordT (LKeywordT) = True
|
||||
isKeywordT _ = False
|
||||
isIdentifier (LIdentifier _) = True
|
||||
isIdentifier _ = False
|
||||
isIntegerLiteral (LIntegerLiteral _) = True
|
||||
isIntegerLiteral _ = False
|
||||
|
||||
isStringLiteral (LStringLiteral _) = True
|
||||
isStringLiteral _ = False
|
||||
|
||||
isLiteral (LIntegerLiteral _) = True
|
||||
isLiteral (LStringLiteral _) = True
|
||||
isLiteral _ = False
|
||||
|
||||
esNewline (LNewline) = True
|
||||
isNewline _ = False
|
||||
isIntegerLiteral _ = False
|
||||
isStringLiteral (LStringLiteral _) = True
|
||||
isStringLiteral _ = False
|
||||
isLiteral (LIntegerLiteral _) = True
|
||||
isLiteral (LStringLiteral _) = True
|
||||
isLiteral _ = False
|
||||
isNewline (LNewline) = True
|
||||
isNewline _ = False
|
||||
|
||||
-- Error Handling
|
||||
handleParseError :: ParseErrorBundle [LToken] Void -> String
|
||||
@ -246,9 +247,10 @@ handleParseError bundle =
|
||||
showError :: ParseError [LToken] Void -> String
|
||||
showError (TrivialError offset (Just (Tokens tokenStream)) expected) =
|
||||
"Parse error at offset " ++ show offset ++ ": unexpected token "
|
||||
++ show tokenStream ++ ", expected one of " ++ show (Set.toList expected)
|
||||
++ show tokenStream ++ ", expected one of " ++ show (Set.toList expected)
|
||||
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 "
|
||||
++ show (Set.toList expected)
|
||||
++ show (Set.toList expected)
|
||||
|
||||
|
Reference in New Issue
Block a user