never executed always true always false
1 {-# LANGUAGE RecordWildCards #-}
2
3 module Conjure.Language.Parser
4 ( runLexerAndParser,
5 lexAndParse,
6 parseIO,
7 parseModel,
8 parseTopLevels,
9 parseExpr,
10 parseDomain,
11 parseDomainWithRepr,
12 prettyPrintWithChecks,
13 Pipeline,
14 PipelineError (..),
15 runPipeline,
16 )
17 where
18
19 import Conjure.Language.AST.ASTParser (ParserError, parseProgram, runASTParser)
20 import Conjure.Language.AST.ASTParser qualified as P
21 import Conjure.Language.AST.Helpers qualified as P
22 import Conjure.Language.AST.Reformer (HighLevelTree (..), flatten)
23 import Conjure.Language.AST.Syntax (DomainNode, ProgramTree)
24 import Conjure.Language.AST.Syntax qualified as S
25 import Conjure.Language.Definition
26 import Conjure.Language.Domain
27 import Conjure.Language.Lexer (ETokenStream, LexerError)
28 import Conjure.Language.Lexer qualified as L
29 import Conjure.Language.Pretty
30 import Conjure.Language.Type (Type (..))
31 import Conjure.Language.Validator ((?=>))
32 import Conjure.Language.Validator qualified as V
33 import Conjure.Prelude
34 import Conjure.UI.ErrorDisplay (showDiagnosticsForConsole)
35 import Data.Text qualified as T
36 import Data.Void (Void)
37 import Prettyprinter qualified as Pr
38 import Text.Megaparsec (Parsec)
39
40 type Pipeline a b = ((Parsec Void ETokenStream) a, a -> V.ValidatorS b, Bool)
41
42 data PipelineError = LexErr LexerError | ParserError ParserError | ValidatorError Doc
43 deriving (Show)
44
45 instance Pretty PipelineError where
46 pretty (ValidatorError d) = d
47 pretty e = pretty $ show e
48
49 lexAndParse :: (HighLevelTree a) => P.Parser a -> Text -> Either PipelineError a
50 lexAndParse parse t = do
51 lr <- either (Left . LexErr) Right $ L.runLexer t Nothing
52 either (Left . ParserError) Right $ runASTParser parse lr
53
54 runPipeline :: (HighLevelTree a) => Pipeline a b -> (Maybe FilePath, Text) -> Either PipelineError b
55 runPipeline (parse, val, tc) (fp, txt) = do
56 lexResult <- either (Left . LexErr) Right $ L.runLexer txt fp
57 parseResult <- either (Left . ParserError) Right $ runASTParser parse lexResult
58 let fileNameText = T.pack <$> fp
59 let x = V.runValidator (val parseResult) (V.initialState parseResult fileNameText) {V.typeChecking = tc}
60 case x of
61 (m, ds, _) | not $ any V.isError ds -> Right m
62 (_, ves, _) -> Left $ ValidatorError $ pretty (showDiagnosticsForConsole ves fp txt)
63
64 parseModel :: Pipeline ProgramTree Model
65 parseModel = (parseProgram, V.validateModel, True)
66
67 parseIO :: (MonadFailDoc m, HighLevelTree i) => Pipeline i a -> String -> m a
68 parseIO p s = do
69 case runPipeline p $ (Just "IO", T.pack s) of
70 Left err -> failDoc $ pretty $ show err
71 Right x -> return x
72
73 -- --------------------------------------------------------------------------------
74 -- -- Actual parsers --------------------------------------------------------------
75 -- --------------------------------------------------------------------------------
76
77 parseTopLevels :: Pipeline [S.StatementNode] [Statement]
78 parseTopLevels = (P.parseTopLevels, V.validateProgramTree, False)
79
80 parseDomain :: Pipeline DomainNode (Domain () Expression)
81 parseDomain = (P.parseDomain, fmap V.untype . V.validateDomain, True)
82
83 parseDomainWithRepr :: Pipeline DomainNode (Domain HasRepresentation Expression)
84 parseDomainWithRepr = (P.parseDomain, fmap V.untype . V.validateDomainWithRepr, True)
85
86 parseExpr :: Pipeline S.ExpressionNode Expression
87 parseExpr = (P.parseExpression, \x -> V.validateExpression x ?=> V.exactly TypeAny, True)
88
89 runLexerAndParser :: (HighLevelTree n) => Pipeline n a -> String -> T.Text -> Either Doc a
90 runLexerAndParser p file inp = case runPipeline p (Just file, inp) of
91 Left pe -> Left $ pretty pe
92 Right a -> Right a
93
94 prettyPrintWithChecks :: (MonadFailDoc m) => Text -> m (Pr.Doc ann)
95 prettyPrintWithChecks src = do
96 v <- case lexAndParse parseProgram src of
97 Left pe -> failDoc $ pretty $ show pe
98 Right pt -> return pt
99 return $ (if V.isSyntacticallyValid V.validateModel v then Pr.pretty else partialPretty) v
100
101 partialPretty :: ProgramTree -> Pr.Doc ann
102 partialPretty (S.ProgramTree lv sns lt) =
103 Pr.vcat
104 [ langVer,
105 Pr.vcat $ map pTopLevel sns,
106 Pr.pretty lt
107 ]
108 where
109 langVer = case lv of
110 Nothing -> "language Essence 1.3"
111 Just _ -> if V.isSyntacticallyValid V.validateLanguageVersion lv then Pr.pretty lv else fallback lv
112 fallback :: (HighLevelTree a) => a -> Pr.Doc ann
113 fallback v = Pr.pretty $ L.reformList $ flatten v
114 pTopLevel st = if V.isSyntacticallyValid V.validateStatement st then Pr.pretty st else fallback st