-
Notifications
You must be signed in to change notification settings - Fork 53
/
Copy pathPipeline.hs
105 lines (94 loc) · 3.6 KB
/
Pipeline.hs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
{-# LANGUAGE OverloadedStrings #-}
-- |
-- SPDX-License-Identifier: BSD-3-Clause
--
-- Some convenient functions for putting together the whole Swarm
-- language processing pipeline: parsing, type checking, capability
-- checking, and elaboration. If you want to simply turn some raw
-- text representing a Swarm program into something useful, this is
-- probably the module you want.
module Swarm.Language.Pipeline (
-- * Pipeline functions
processTerm,
processParsedTerm,
processTerm',
processParsedTerm',
processTermEither,
-- * Utilities
extractTCtx,
extractReqCtx,
) where
import Control.Lens ((^.))
import Data.Bifunctor (first)
import Data.Text (Text)
import Data.Text qualified as T
import Swarm.Language.Context qualified as Ctx
import Swarm.Language.Elaborate
import Swarm.Language.Parser (readTerm)
import Swarm.Language.Requirements.Type (ReqCtx)
import Swarm.Language.Syntax
import Swarm.Language.Typecheck
import Swarm.Language.Types (TCtx)
import Swarm.Language.Value (Env, envReqs, envTydefs, envTypes)
processTermEither :: Text -> Either Text TSyntax
processTermEither t = case processTerm t of
Left err -> Left $ T.unwords ["Could not parse term:", err]
Right Nothing -> Left "Term was only whitespace"
Right (Just pt) -> Right pt
-- | Given a 'Text' value representing a Swarm program,
--
-- 1. Parse it (see "Swarm.Language.Parse")
-- 2. Typecheck it (see "Swarm.Language.Typecheck")
-- 3. Elaborate it (see "Swarm.Language.Elaborate")
--
-- Return either the end result (or @Nothing@ if the input was only
-- whitespace) or a pretty-printed error message.
processTerm :: Text -> Either Text (Maybe TSyntax)
processTerm = processTerm' mempty
-- | Like 'processTerm', but use a term that has already been parsed.
processParsedTerm :: Syntax -> Either ContextualTypeErr TSyntax
processParsedTerm = processParsedTerm' mempty
-- | Like 'processTerm', but use explicit starting contexts.
processTerm' :: Env -> Text -> Either Text (Maybe TSyntax)
processTerm' e txt = do
mt <- readTerm txt
first (prettyTypeErrText txt) $ traverse (processParsedTerm' e) mt
-- | Like 'processTerm'', but use a term that has already been parsed.
processParsedTerm' :: Env -> Syntax -> Either ContextualTypeErr TSyntax
processParsedTerm' e t = do
tt <- inferTop (e ^. envTypes) (e ^. envReqs) (e ^. envTydefs) t
return $ elaborate tt
------------------------------------------------------------
-- Some utility functions
------------------------------------------------------------
-- | Extract a type context from type annotations on definitions
-- contained in a term. Should probably only be used for testing.
extractTCtx :: Syntax' ty -> TCtx
extractTCtx (Syntax' _ t _ _) = extractTCtxTerm t
where
extractTCtxTerm = \case
SLet _ _ (LV _ x) _ mty _ _ t2 -> maybe id (Ctx.addBinding x) mty (extractTCtx t2)
SBind mx _ mty _ c1 c2 ->
maybe
id
(uncurry Ctx.addBinding)
((,) . lvVar <$> mx <*> mty)
(extractTCtx c1 <> extractTCtx c2)
SAnnotate t1 _ -> extractTCtx t1
_ -> mempty
-- | Extract a requirements context from requirements annotations on
-- definitions contained in a term. Should probably only be used
-- for testing.
extractReqCtx :: Syntax' ty -> ReqCtx
extractReqCtx (Syntax' _ t _ _) = extractReqCtxTerm t
where
extractReqCtxTerm = \case
SLet _ _ (LV _ x) _ _ mreq _ t2 -> maybe id (Ctx.addBinding x) mreq (extractReqCtx t2)
SBind mx _ _ mreq c1 c2 ->
maybe
id
(uncurry Ctx.addBinding)
((,) . lvVar <$> mx <*> mreq)
(extractReqCtx c1 <> extractReqCtx c2)
SAnnotate t1 _ -> extractReqCtx t1
_ -> mempty