Skip to content
This repository was archived by the owner on Apr 1, 2025. It is now read-only.

Commit d3726fa

Browse files
committed
Merge branch 'scope-graphs' into re-name
2 parents f141319 + 0515d7c commit d3726fa

File tree

25 files changed

+190
-112
lines changed

25 files changed

+190
-112
lines changed

.ghci

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,9 @@
22
:set -package pretty-show -package hscolour
33

44
-- See docs/💡ProTip!.md
5-
:undef pretty
6-
:def pretty \ _ -> return ":set -interactive-print Semantic.Util.Pretty.prettyShow"
7-
8-
-- See docs/💡ProTip!.md
9-
:undef no-pretty
10-
:def no-pretty \_ -> return ":set -interactive-print System.IO.print"
11-
12-
-- See docs/💡ProTip!.md
13-
:undef r
14-
:def r \_ -> return (unlines [":reload", ":pretty"])
5+
:def! pretty \ _ -> return ":set -interactive-print Semantic.Util.Pretty.prettyShow"
6+
:def! no-pretty \_ -> return ":set -interactive-print System.IO.print"
7+
:def! r \_ -> return (unlines [":reload", ":pretty"])
158

169
-- See docs/💡ProTip!.md for documentation & examples.
1710
:{
@@ -29,8 +22,7 @@ assignmentExample lang = case lang of
2922
_ -> mk "" ""
3023
where mk fileExtension parser = putStrLn ("example: fmap (() <$) . runTask . parse " ++ parser ++ "Parser =<< Semantic.Util.blob \"example." ++ fileExtension ++ "\"") >> return ("import Parsing.Parser\nimport Semantic.Task\nimport Semantic.Util")
3124
:}
32-
:undef assignment
33-
:def assignment assignmentExample
25+
:def! assignment assignmentExample
3426

3527
-- Enable breaking on errors for code written in the repl.
3628
:seti -fbreak-on-error

script/publish

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
set -e
77
cd $(dirname "$0")/..
88

9-
VERSION="0.6.0"
9+
VERSION="0.7.0.0"
1010
BUILD_SHA=$(git rev-parse HEAD 2>/dev/null)
1111
DOCKER_IMAGE=docker.pkg.github.com/github/semantic/semantic
1212

semantic-core/src/Analysis/Concrete.hs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
{-# LANGUAGE DerivingVia, FlexibleContexts, FlexibleInstances, LambdaCase, MultiParamTypeClasses, NamedFieldPuns, OverloadedStrings, RankNTypes, RecordWildCards, TypeOperators, UndecidableInstances #-}
1+
{-# LANGUAGE DerivingVia, FlexibleContexts, FlexibleInstances, LambdaCase, MultiParamTypeClasses, NamedFieldPuns, OverloadedStrings, RankNTypes, RecordWildCards, TypeApplications, TypeOperators, UndecidableInstances #-}
22
module Analysis.Concrete
33
( Concrete(..)
44
, concrete
@@ -46,6 +46,7 @@ data Concrete term
4646
| String Text
4747
| Record Env
4848
deriving (Eq, Ord, Show)
49+
-- NB: We derive the 'Semigroup' instance for 'Concrete' to take the second argument. This is equivalent to stating that the return value of an imperative sequence of statements is the value of its final statement.
4950
deriving Semigroup via Last (Concrete term)
5051

5152
recordFrame :: Concrete term -> Maybe Env
@@ -102,7 +103,7 @@ runFile
102103
runFile eval file = traverse run file
103104
where run = runReader (fileLoc file)
104105
. runFailWithLoc
105-
. runReader (mempty :: Env)
106+
. runReader @Env mempty
106107
. fix (eval concreteAnalysis)
107108

108109
concreteAnalysis :: ( Carrier sig m
@@ -184,7 +185,7 @@ heapGraph vertex edge h = foldr (uncurry graph) G.empty (IntMap.toList h)
184185
Bool _ -> G.empty
185186
String _ -> G.empty
186187
Closure _ _ _ env -> foldr (G.overlay . edge (Left Lexical)) G.empty env
187-
Record frame -> foldr (G.overlay . uncurry (edge . Right)) G.empty (Map.toList frame)
188+
Record frame -> Map.foldrWithKey (\ k -> G.overlay . edge (Right k)) G.empty frame
188189

189190
heapValueGraph :: Heap term -> G.Graph (Concrete term)
190191
heapValueGraph h = heapGraph (const id) (const fromAddr) h

semantic-core/src/Analysis/Eval.hs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,9 @@ eval Analysis{..} eval = \case
4343
addr <- alloc n
4444
v <- bind n addr (eval (instantiate1 (pure n) b))
4545
v <$ assign addr v
46+
-- NB: Combining the results of the evaluations allows us to model effects in abstract domains. This in turn means that we can define an abstract domain modelling the types-and-effects of computations by means of a 'Semigroup' instance which takes the type of its second operand and the union of both operands’ effects.
47+
--
48+
-- It’s also worth noting that we use a semigroup instead of a semilattice because the lattice structure of our abstract domains is instead modelled by nondeterminism effects used by some of them.
4649
a :>> b -> (<>) <$> eval a <*> eval b
4750
Named (Ignored n) a :>>= b -> do
4851
a' <- eval a

semantic-core/src/Analysis/ScopeGraph.hs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,8 @@ scopeGraphAnalysis = Analysis{..}
102102
ref <- asks Ref
103103
bindLoc <- asks (Map.lookup addr)
104104
cell <- gets (Map.lookup addr >=> nonEmpty . Set.toList)
105-
maybe (pure Nothing) (foldMapA (pure . Just . mappend (extendBinding addr ref bindLoc))) cell
105+
let extending = mappend (extendBinding addr ref bindLoc)
106+
maybe (pure Nothing) (foldMapA (pure . Just . extending)) cell
106107
assign addr v = do
107108
ref <- asks Ref
108109
bindLoc <- asks (Map.lookup addr)

semantic-core/src/Analysis/Typecheck.hs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,8 @@ data Monotype f a
4949
type Type = Term Monotype Meta
5050

5151
-- FIXME: Union the effects/annotations on the operands.
52+
53+
-- | We derive the 'Semigroup' instance for types to take the second argument. This is equivalent to stating that the type of an imperative sequence of statements is the type of its final statement.
5254
deriving via (Last (Term Monotype a)) instance Semigroup (Term Monotype a)
5355

5456
deriving instance (Eq a, forall a . Eq a => Eq (f a), Monad f) => Eq (Monotype f a)

semantic-core/src/Control/Monad/Module.hs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,25 @@ module Control.Monad.Module
88

99
import Control.Effect.Carrier
1010

11+
-- | Modules over monads allow lifting of a monad’s product (i.e. 'Control.Monad.join') into another structure composed with the monad. A right-module @f m@ over a monad @m@ therefore allows one to extend @m@’s '>>=' operation to values of @f m@ using the '>>=*' operator.
12+
--
13+
-- In practical terms, this means that we can describe syntax which cannot itself bind or be substituted for variables, but which can be substituted inside when containing a substitutable expression monad. For example, we might not want to allow variables in a declaration context, but might still want to be able to substitute for e.g. globally-bound variables inside declarations; a 'RightModule' instance expresses this relationship nicely.
14+
--
15+
-- Note that we are calling this a right-module following Maciej Piróg, Nicolas Wu, & Jeremy Gibbons in _Modules Over Monads and their Algebras_; confusingly, other sources refer to this as a left-module.
16+
--
17+
-- Laws:
18+
--
19+
-- Right-identity:
20+
--
21+
-- @
22+
-- m >>=* return = m
23+
-- @
24+
--
25+
-- Associativity:
26+
--
27+
-- @
28+
-- m >>=* (k >=> h) = (m >>=* k) >>=* h
29+
-- @
1130
class (forall g . Functor g => Functor (f g), HFunctor f) => RightModule f where
1231
(>>=*) :: Monad m => f m a -> (a -> m b) -> f m b
1332
infixl 1 >>=*

semantic-core/src/Data/Core.hs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,7 @@ do' bindings = fromMaybe unit (foldr bind Nothing bindings)
142142
where bind (n :<- a) v = maybe (a >>>) ((>>>=) . (:<- a)) n <$> v <|> Just a
143143

144144
unstatements :: (Member Core sig, RightModule sig) => Term sig a -> (Stack (Maybe (Named (Either Int a)) :<- Term sig (Either Int a)), Term sig (Either Int a))
145-
unstatements = un (unstatement . Left) . fmap Right
145+
unstatements = unprefix (unstatement . Left) . fmap Right
146146

147147
data a :<- b = a :<- b
148148
deriving (Eq, Foldable, Functor, Ord, Show, Traversable)

semantic-core/src/Data/Core/Parser.hs

Lines changed: 7 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ module Data.Core.Parser
1212
import Control.Applicative
1313
import Control.Effect.Carrier
1414
import qualified Data.Char as Char
15-
import Data.Core (Core)
15+
import Data.Core ((:<-) (..), Core)
1616
import qualified Data.Core as Core
1717
import Data.Foldable (foldl')
1818
import Data.Name
@@ -53,7 +53,8 @@ expr :: (TokenParsing m, Carrier sig t, Member Core sig, Monad m) => m (t Name)
5353
expr = ifthenelse <|> lambda <|> rec <|> load <|> assign
5454

5555
assign :: (TokenParsing m, Carrier sig t, Member Core sig, Monad m) => m (t Name)
56-
assign = application <**> (flip (Core..=) <$ symbolic '=' <*> application <|> pure id) <?> "assignment"
56+
assign = application <**> (symbolic '=' *> rhs <|> pure id) <?> "assignment"
57+
where rhs = flip (Core..=) <$> application
5758

5859
application :: (TokenParsing m, Carrier sig t, Member Core sig, Monad m) => m (t Name)
5960
application = projection `chainl1` (pure (Core.$$))
@@ -72,10 +73,10 @@ atom = choice
7273
comp :: (TokenParsing m, Carrier sig t, Member Core sig, Monad m) => m (t Name)
7374
comp = braces (Core.do' <$> sepEndByNonEmpty statement semi) <?> "compound statement"
7475

75-
statement :: (TokenParsing m, Carrier sig t, Member Core sig, Monad m) => m (Maybe (Named Name) Core.:<- t Name)
76+
statement :: (TokenParsing m, Carrier sig t, Member Core sig, Monad m) => m (Maybe (Named Name) :<- t Name)
7677
statement
77-
= try ((Core.:<-) . Just <$> name <* symbol "<-" <*> expr)
78-
<|> (Nothing Core.:<-) <$> expr
78+
= try ((:<-) . Just <$> name <* symbol "<-" <*> expr)
79+
<|> (Nothing :<-) <$> expr
7980
<?> "statement"
8081

8182
ifthenelse :: (TokenParsing m, Carrier sig t, Member Core sig, Monad m) => m (t Name)
@@ -109,14 +110,8 @@ lit = let x `given` n = x <$ reserved n in choice
109110
, Core.bool False `given` "#false"
110111
, Core.unit `given` "#unit"
111112
, record
112-
, token (between (string "\"") (string "\"") (Core.string . fromString <$> many (escape <|> (noneOf "\"" <?> "non-escaped character"))))
113+
, Core.string <$> stringLiteral
113114
] <?> "literal"
114-
where escape = char '\\' *> choice
115-
[ '"' <$ string "\""
116-
, '\n' <$ string "n"
117-
, '\r' <$ string "r"
118-
, '\t' <$ string "t"
119-
] <?> "escape sequence"
120115

121116
record :: (TokenParsing m, Carrier sig t, Member Core sig, Monad m) => m (t Name)
122117
record = Core.record <$ reserved "#record" <*> braces (sepEndBy ((,) <$> identifier <* symbolic ':' <*> expr) comma)

semantic-core/src/Data/Scope.hs

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@ module Data.Scope
1212
, instantiate1
1313
, instantiate
1414
, instantiateEither
15-
, un
16-
, unEither
15+
, unprefix
16+
, unprefixEither
1717
) where
1818

1919
import Control.Applicative (liftA2)
@@ -110,11 +110,23 @@ instantiateEither :: Monad f => (Either a b -> f c) -> Scope a f b -> f c
110110
instantiateEither f = unScope >=> incr (f . Left) (>>= f . Right)
111111

112112

113-
un :: (Int -> t -> Maybe (a, t)) -> t -> (Stack a, t)
114-
un from = unEither (matchMaybe . from)
115-
116-
unEither :: (Int -> t -> Either (a, t) b) -> t -> (Stack a, b)
117-
unEither from = go (0 :: Int) Nil
113+
-- | Unwrap a (possibly-empty) prefix of @a@s wrapping a @t@ using a helper function.
114+
--
115+
-- This allows us to peel a prefix of syntax, typically binders, off of a term, returning a stack of prefixing values (e.g. variables) and the outermost subterm rejected by the function.
116+
unprefix
117+
:: (Int -> t -> Maybe (a, t)) -- ^ A function taking the 0-based index into the prefix & the current term, and optionally returning a pair of the prefixing value and the inner subterm.
118+
-> t -- ^ The initial term.
119+
-> (Stack a, t) -- ^ A stack of prefixing values & the final subterm.
120+
unprefix from = unprefixEither (matchMaybe . from)
121+
122+
-- | Unwrap a (possibly-empty) prefix of @a@s wrapping a @b@ within a @t@ using a helper function.
123+
--
124+
-- Compared to 'unprefix', this allows the helper function to extract inner terms of a different type, for example when @t@ is a right @b@-module.
125+
unprefixEither
126+
:: (Int -> t -> Either (a, t) b) -- ^ A function taking the 0-based index into the prefix & the current term, and returning either a pair of the prefixing value and the next inner subterm of type @t@, or the final inner subterm of type @b@.
127+
-> t -- ^ The initial term.
128+
-> (Stack a, b) -- ^ A stack of prefixing values & the final subterm.
129+
unprefixEither from = go (0 :: Int) Nil
118130
where go i bs t = case from i t of
119131
Left (b, t) -> go (succ i) (bs :> b) t
120132
Right b -> (bs, b)

0 commit comments

Comments
 (0)