Skip to content

Commit 58398f9

Browse files
authored
Merge pull request github#675 from github/great-exportations
Track exports in exception tracing modules
2 parents 09787a3 + daaf962 commit 58398f9

File tree

8 files changed

+98
-61
lines changed

8 files changed

+98
-61
lines changed

semantic-analysis/.gitignore

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
test.json
2-
test.py
1+
*.json
2+
*.py

semantic-analysis/python.tsg

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,15 @@
9393
attr (@this.node -> @else.node) type = "alternative"
9494
}
9595

96+
(function_definition name: (_) @name body: (_) @body) @this
97+
{
98+
node @this.node
99+
attr (@this.node) type = "function"
100+
attr (@this.node) name = (source-text @name)
101+
edge @this.node -> @body.node
102+
attr (@this.node -> @body.node) type = "body"
103+
}
104+
96105
(module (_) @child) @this
97106
{
98107
edge @this.node -> @child.node

semantic-analysis/src/Analysis/Analysis/Concrete.hs

Lines changed: 17 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -28,17 +28,15 @@ import Control.Algebra
2828
import Control.Carrier.Fresh.Strict
2929
import Control.Carrier.Reader hiding (Local)
3030
import Control.Effect.Labelled
31-
import Control.Monad.Trans.Class (MonadTrans(..))
31+
import Control.Monad.Trans.Class (MonadTrans (..))
3232
import Data.Foldable (foldl')
3333
import Data.Function (fix, on)
34-
import Data.Semigroup (Last(..))
34+
import Data.Semigroup (Last (..))
3535
import Data.Text as Text (Text)
3636
import Prelude hiding (fail)
37-
import Source.Span
38-
import qualified System.Path as Path
3937

4038
data Concrete
41-
= Closure Path.AbsRelFile Span (Named (Concrete -> Concrete))
39+
= Closure Reference [Name] ([Concrete] -> Concrete)
4240
| Unit
4341
| Bool Bool
4442
| Int Int
@@ -62,14 +60,14 @@ instance Show Concrete where
6260
showsPrec p = showsPrec p . quote
6361

6462

65-
newtype Elim a = EApp a
63+
newtype Elim a = EApp [a]
6664
deriving (Eq, Foldable, Functor, Ord, Show, Traversable)
6765

6866
vvar :: Name -> Concrete
6967
vvar n = Neutral n Nil
7068

7169
velim :: Concrete -> Elim Concrete -> Concrete
72-
velim (Closure _ _ f) (EApp a) = namedValue f a
70+
velim (Closure _ _ f) (EApp a) = f a
7371
velim (Neutral h as) a = Neutral h (as :> a)
7472
velim _ _ = error "velim: cannot eliminate" -- FIXME: fail in the monad instead
7573

@@ -84,7 +82,7 @@ vsubst n v = go
8482
| otherwise -> Neutral n' as'
8583
where
8684
as' = fmap go <$> as
87-
Closure p s b -> Closure p s ((go .) <$> b) -- NB: Shadowing can’t happen because n' can’t occur inside b
85+
Closure r n b -> Closure r n (go . b) -- NB: Shadowing can’t happen because n' can’t occur inside b
8886
Unit -> Unit
8987
Bool b -> Bool b
9088
Int i -> Int i
@@ -93,24 +91,24 @@ vsubst n v = go
9391

9492
data FO
9593
= FOVar Name
96-
| FOClosure Path.AbsRelFile Span (Named FO)
94+
| FOClosure Reference [Name] FO
9795
| FOUnit
9896
| FOBool Bool
9997
| FOInt Int
10098
| FOString Text
101-
| FOApp FO FO
99+
| FOApp FO [FO]
102100
deriving (Eq, Ord, Show)
103101

104102

105103
quote :: Concrete -> FO
106104
quote = \case
107105
-- FIXME: should quote take a Level incremented under binders?
108-
Closure path span body -> FOClosure path span ((\ f -> quote (f (vvar (namedName body)))) <$> body)
109-
Unit -> FOUnit
110-
Bool b -> FOBool b
111-
Int i -> FOInt i
112-
String s -> FOString s
113-
Neutral n sp -> foldl' (\ f (EApp a) -> FOApp f (quote a)) (FOVar n) sp
106+
Closure r n body -> FOClosure r n (quote (body (map vvar n)))
107+
Unit -> FOUnit
108+
Bool b -> FOBool b
109+
Int i -> FOInt i
110+
String s -> FOString s
111+
Neutral n sp -> foldl' (\ f (EApp a) -> FOApp f (map quote a)) (FOVar n) sp
114112

115113

116114
type Eval term m value = (term -> m value) -> (term -> m value)
@@ -160,9 +158,10 @@ instance ( Has (A.Env A.PAddr) sig m
160158
alg hdl sig ctx = case sig of
161159
L (DVar n) -> pure (vvar n <$ ctx)
162160
L (DAbs n b) -> do
163-
b' <- hdl (b (vvar n) <$ ctx)
161+
b' <- hdl (b (map vvar n) <$ ctx)
164162
ref <- ask
165-
pure $ Closure (refPath ref) (refSpan ref) . named n . flip (vsubst n) <$> b'
163+
let closure body = Closure ref n (\ args -> let substs = zipWith vsubst n args in foldl' (.) id substs body)
164+
pure $ closure <$> b'
166165
L (DApp f a) -> pure $ velim f (EApp a) <$ ctx
167166
L (DInt i) -> pure (Int i <$ ctx)
168167
L DUnit -> pure (Unit <$ ctx)

semantic-analysis/src/Analysis/Analysis/Exception.hs

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ module Analysis.Analysis.Exception
1414
, fromExceptions
1515
, var
1616
, exc
17+
, subst
1718
-- * Exception tracing analysis
1819
, ExcC(..)
1920
) where
@@ -33,6 +34,7 @@ import Control.Effect.Labelled
3334
import Control.Effect.State
3435
import qualified Data.Foldable as Foldable
3536
import Data.Function (fix)
37+
import qualified Data.Map as Map
3638
import qualified Data.Set as Set
3739
import qualified Data.Text as Text
3840

@@ -61,6 +63,9 @@ var v = ExcSet (Set.singleton v) mempty
6163
exc :: Exception -> ExcSet
6264
exc e = ExcSet mempty (Set.singleton e)
6365

66+
subst :: Name -> ExcSet -> ExcSet -> ExcSet
67+
subst name (ExcSet fvs' es') (ExcSet fvs es) = ExcSet (Set.delete name fvs <> fvs') (es <> es')
68+
6469

6570
exceptionTracing
6671
:: Ord term
@@ -87,9 +92,11 @@ runFile eval = traverse run where
8792
. A.runEnv @ExcSet
8893
. convergeTerm (A.runStore @ExcSet . runExcC . fix (cacheTerm . eval))
8994
result msgs sets = do
95+
exports <- gets @(A.MStore ExcSet) (fmap Foldable.fold . Map.mapKeys A.getMAddr . A.getMStore)
9096
let set = Foldable.fold sets
91-
imports = Set.fromList (map (\ (A.Import components) -> name (Text.intercalate (Text.pack ".") (Foldable.toList components))) msgs)
92-
pure (Module (const set) imports mempty (freeVariables set))
97+
imports = Set.fromList (map extractImport msgs)
98+
pure (Module (Foldable.foldl' (flip (uncurry subst)) set . Map.toList) imports exports (freeVariables set))
99+
extractImport (A.Import components) = name (Text.intercalate (Text.pack ".") (Foldable.toList components))
93100

94101
newtype ExcC m a = ExcC { runExcC :: m a }
95102
deriving (Alternative, Applicative, Functor, Monad)
@@ -99,7 +106,7 @@ instance (Algebra sig m, Alternative m) => Algebra (Dom ExcSet :+: sig) (ExcC m)
99106
L dom -> case dom of
100107
DVar n -> pure $ var n <$ ctx
101108
DAbs _ b -> runExcC (hdl (b mempty <$ ctx))
102-
DApp f a -> pure $ f <> a <$ ctx
109+
DApp f a -> pure $ f <> Foldable.fold a <$ ctx
103110
DInt _ -> pure nil
104111
DUnit -> pure nil
105112
DBool _ -> pure nil

semantic-analysis/src/Analysis/Analysis/Typecheck.hs

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -30,19 +30,19 @@ import Analysis.FlowInsensitive
3030
import Analysis.Functor.Named
3131
import Analysis.Reference
3232
import Control.Algebra
33-
import Control.Applicative (Alternative(..))
33+
import Control.Applicative (Alternative (..))
3434
import Control.Carrier.Fresh.Strict as Fresh
3535
import Control.Carrier.Reader hiding (Local)
3636
import Control.Carrier.State.Strict
3737
import Control.Effect.Labelled
3838
import Control.Monad (ap, guard, unless)
3939
import Control.Monad.Trans.Class
40-
import Data.Foldable (for_)
40+
import Data.Foldable (for_, sequenceA_)
4141
import Data.Function (fix)
4242
import qualified Data.IntMap as IM
4343
import qualified Data.IntSet as IS
4444
import Data.Maybe (fromJust, fromMaybe)
45-
import Data.Semigroup (Last(..))
45+
import Data.Semigroup (Last (..))
4646
import qualified Data.Set as Set
4747
import Data.Void
4848
import GHC.Generics (Generic1)
@@ -54,7 +54,7 @@ data Monotype a
5454
| Bool
5555
| Int
5656
| String
57-
| Monotype a :-> Monotype a
57+
| [Monotype a] :-> Monotype a
5858
-- | (Locally) undefined names whose types are unknown. May not be eliminated by unification.
5959
| TypeOf Name
6060
deriving (Eq, Foldable, Functor, Generic1, Ord, Show, Traversable)
@@ -78,7 +78,7 @@ instance Monad Monotype where
7878
Int -> Int
7979
String -> String
8080
TypeOf n -> TypeOf n
81-
a :-> b -> (a >>= f) :-> (b >>= f)
81+
a :-> b -> (map (>>= f) a) :-> (b >>= f)
8282

8383

8484
type Type = Monotype Meta
@@ -180,7 +180,7 @@ type Substitution = IM.IntMap Type
180180
solve :: (Has (State Substitution) sig m, MonadFail m) => Set.Set (Type, Type) -> m ()
181181
solve cs = for_ cs (uncurry solve)
182182
where solve = curry $ \case
183-
(a1 :-> b1, a2 :-> b2) -> solve a1 a2 *> solve b1 b2
183+
(a1 :-> b1, a2 :-> b2) -> sequenceA_ (zipWith solve a1 a2) *> solve b1 b2
184184
(Var m1 , Var m2) | m1 == m2 -> pure ()
185185
(Var m1 , t2) -> do
186186
sol <- solution m1
@@ -230,16 +230,16 @@ instance ( Alternative m
230230
L (DString _) -> pure (String <$ ctx)
231231

232232
L (DAbs n b) -> do
233-
addr <- A.alloc n
234-
arg <- meta
235-
addr A..= arg
236-
ty <- hdl (b arg <$ ctx)
237-
pure ((arg :->) <$> ty)
233+
addrs <- traverse A.alloc n
234+
args <- traverse (const meta) n
235+
sequenceA_ (zipWith (A..=) addrs args)
236+
ty <- hdl (b args <$ ctx)
237+
pure ((args :->) <$> ty)
238238
L (DApp f a) -> do
239-
arg <- meta
239+
args <- traverse (const meta) a
240240
ret <- meta
241-
unify f (arg :-> ret)
242-
unify a arg
241+
unify f (args :-> ret)
242+
sequenceA_ (zipWith unify a args)
243243
pure (ret <$ ctx)
244244

245245
L (DDie msg) -> fail (show msg)

semantic-analysis/src/Analysis/Carrier/Store/Monovariant.hs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ import Control.Monad.Fail as Fail
3636
import Data.Map as Map
3737
import Data.Set as Set
3838

39-
newtype MAddr = MAddr Name
39+
newtype MAddr = MAddr { getMAddr :: Name }
4040
deriving (Eq, Ord, Show)
4141

4242
newtype MStore value = MStore { getMStore :: Map.Map MAddr (Set.Set value) }

semantic-analysis/src/Analysis/Effect/Domain.hs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -39,10 +39,10 @@ dvar = send . DVar
3939

4040
-- Functions
4141

42-
dabs :: Has (Dom val) sig m => Name -> (val -> m val) -> m val
42+
dabs :: Has (Dom val) sig m => [Name] -> ([val] -> m val) -> m val
4343
dabs n = send . DAbs n
4444

45-
dapp :: Has (Dom val) sig m => val -> val -> m val
45+
dapp :: Has (Dom val) sig m => val -> [val] -> m val
4646
dapp f a = send $ DApp f a
4747

4848

@@ -89,8 +89,8 @@ ddie = send . DDie
8989

9090
data Dom val m k where
9191
DVar :: Name -> Dom val m val
92-
DAbs :: Name -> (val -> m val) -> Dom val m val
93-
DApp :: val -> val -> Dom val m val
92+
DAbs :: [Name] -> ([val] -> m val) -> Dom val m val
93+
DApp :: val -> [val] -> Dom val m val
9494
DInt :: Int -> Dom val m val
9595
DUnit :: Dom val m val
9696
DBool :: Bool -> Dom val m val

semantic-analysis/src/Analysis/Syntax.hs

Lines changed: 41 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ module Analysis.Syntax
1212
, eval
1313
-- * Macro-expressible syntax
1414
, let'
15+
, letrec
1516
-- * Parsing
1617
, parseFile
1718
, parseGraph
@@ -35,6 +36,7 @@ import qualified Data.Aeson.Internal as A
3536
import qualified Data.Aeson.Parser as A
3637
import qualified Data.Aeson.Types as A
3738
import qualified Data.ByteString.Lazy as B
39+
import Data.Foldable (fold)
3840
import Data.Function (fix)
3941
import qualified Data.IntMap as IntMap
4042
import Data.List (sortOn)
@@ -54,6 +56,7 @@ data Term
5456
| Throw Term
5557
| Let Name Term Term
5658
| Import (NonEmpty Text)
59+
| Function Name [Name] Term
5760
deriving (Eq, Ord, Show)
5861

5962

@@ -79,6 +82,8 @@ eval eval = \case
7982
v' <- eval v
8083
let' n v' (eval b)
8184
Import ns -> S.simport ns >> dunit
85+
Function n ps b -> letrec n (dabs ps (\ as ->
86+
foldr (\ (p, a) m -> let' p a m) (eval b) (zip ps as)))
8287

8388

8489
-- Macro-expressible syntax
@@ -89,6 +94,13 @@ let' n v m = do
8994
addr .= v
9095
bind n addr m
9196

97+
letrec :: (Has (Env addr) sig m, HasLabelled Store (Store addr val) sig m) => Name -> m val -> m val
98+
letrec n m = do
99+
addr <- alloc n
100+
v <- bind n addr m
101+
addr .= v
102+
pure v
103+
92104

93105
-- Parsing
94106

@@ -102,26 +114,32 @@ parseFile path = do
102114
-- FIXME: this should use the span of the source file, not an empty span.
103115
Right (_, Just root) -> pure (File (Ref.fromPath (Path.absRel path)) root)
104116

105-
parseGraph :: A.Value -> A.Parser (IntMap.IntMap Term, Maybe Term)
117+
newtype Graph = Graph { terms :: IntMap.IntMap Term }
118+
119+
-- | Parse a @Value@ into an entire graph of terms, as well as a root node, if any exists.
120+
parseGraph :: A.Value -> A.Parser (Graph, Maybe Term)
106121
parseGraph = A.withArray "nodes" $ \ nodes -> do
107-
(untied, First root) <- foldMap (\ (k, v, r) -> ([(k, v)], First r)) <$> traverse (A.withObject "node" parseNode) (V.toList nodes)
108-
-- @untied@ is a list of key/value pairs, where the keys are graph node IDs and the values are functions from the final graph to the representations of said graph nodes. Likewise, @root@ is a function of the same variety, wrapped in a @Maybe@.
122+
(untied, First root) <- fold <$> traverse parseNode (V.toList nodes)
123+
-- @untied@ is an intmap, where the keys are graph node IDs and the values are functions from the final graph to the representations of said graph nodes. Likewise, @root@ is a function of the same variety, wrapped in a @Maybe@.
109124
--
110-
-- We define @tied@ as the fixpoint of the former to yield the former as a graph of type @IntMap.IntMap Term@, and apply the latter to said graph to yield the entry point, if any, from which to evaluate.
111-
let tied = fix (\ tied -> ($ tied) <$> IntMap.fromList untied)
112-
pure (tied, ($ tied) <$> root)
113-
114-
parseNode :: A.Object -> A.Parser (IntMap.Key, IntMap.IntMap Term -> Term, Maybe (IntMap.IntMap Term -> Term))
115-
parseNode o = do
125+
-- We define @tied@ as the fixpoint of the former to yield the former as a graph of type @Graph@, and apply the latter to said graph to yield the entry point, if any, from which to evaluate.
126+
let tied = fix (\ tied -> ($ Graph tied) <$> untied)
127+
pure (Graph tied, ($ Graph tied) <$> root)
128+
129+
-- | Parse a node from a JSON @Value@ into a pair of a partial graph of unfixed terms and optionally an unfixed term representing the root node.
130+
--
131+
-- The partial graph is represented as an adjacency map relating node IDs to unfixed terms—terms which may make reference to a completed graph to find edges, and which therefore can't be inspected until the full graph is known.
132+
parseNode :: A.Value -> A.Parser (IntMap.IntMap (Graph -> Term), First (Graph -> Term))
133+
parseNode = A.withObject "node" $ \ o -> do
116134
edges <- o A..: fromString "edges"
117135
index <- o A..: fromString "id"
118136
o A..: fromString "attrs" >>= A.withObject "attrs" (\ attrs -> do
119137
ty <- attrs A..: fromString "type"
120-
node <- parseType attrs edges ty
121-
pure (index, node, node <$ guard (ty == "module")))
138+
node <- parseTerm attrs edges ty
139+
pure (IntMap.singleton index node, node <$ First (guard (ty == "module"))))
122140

123-
parseType :: A.Object -> [A.Value] -> String -> A.Parser (IntMap.IntMap Term -> Term)
124-
parseType attrs edges = \case
141+
parseTerm :: A.Object -> [A.Value] -> String -> A.Parser (Graph -> Term)
142+
parseTerm attrs edges = \case
125143
"string" -> const . String <$> attrs A..: fromString "text"
126144
"true" -> pure (const (Bool True))
127145
"false" -> pure (const (Bool False))
@@ -131,13 +149,14 @@ parseType attrs edges = \case
131149
"module" -> children edges
132150
"identifier" -> const . Var . name <$> attrs A..: fromString "text"
133151
"import" -> const . Import . fromList . map snd . sortOn fst <$> traverse (resolveWith (const moduleNameComponent)) edges
152+
"function" -> liftA3 Function . pure . name <$> attrs A..: fromString "name" <*> pure (pure []) <*> findEdgeNamed edges "body"
134153
t -> A.parseFail ("unrecognized type: " <> t <> " attrs: " <> show attrs <> " edges: " <> show edges)
135154

136-
findEdgeNamed :: (Foldable t, A.FromJSON a, Eq a) => t A.Value -> a -> A.Parser (IntMap.IntMap rep -> rep)
155+
findEdgeNamed :: (Foldable t, A.FromJSON a, Eq a) => t A.Value -> a -> A.Parser (Graph -> Term)
137156
findEdgeNamed edges name = foldMap (resolveWith (\ rep attrs -> attrs A..: fromString "type" >>= (rep <$) . guard . (== name))) edges
138157

139158
-- | Map a list of edges to a list of child nodes.
140-
children :: [A.Value] -> A.Parser (IntMap.IntMap Term -> Term)
159+
children :: [A.Value] -> A.Parser (Graph -> Term)
141160
children edges = fmap (foldr chain Noop . zip [0..]) . sequenceA <$> traverse resolve edges
142161

143162
moduleNameComponent :: A.Object -> A.Parser (Int, Text)
@@ -147,11 +166,14 @@ moduleNameComponent attrs = (,) <$> attrs A..: fromString "index" <*> attrs A..:
147166
chain :: (Int, Term) -> Term -> Term
148167
chain = uncurry (Let . nameI)
149168

150-
resolve :: A.Value -> A.Parser (IntMap.IntMap rep -> rep)
169+
resolve :: A.Value -> A.Parser (Graph -> Term)
151170
resolve = resolveWith (const . pure)
152171

153-
resolveWith :: ((IntMap.IntMap rep -> rep) -> A.Object -> A.Parser a) -> A.Value -> A.Parser a
154-
resolveWith f = A.withObject "edge" (\ edge -> do
172+
resolveWith :: ((Graph -> Term) -> A.Object -> A.Parser a) -> A.Value -> A.Parser a
173+
resolveWith f = resolveWith' (f . flip ((IntMap.!) . terms))
174+
175+
resolveWith' :: (IntMap.Key -> A.Object -> A.Parser a) -> A.Value -> A.Parser a
176+
resolveWith' f = A.withObject "edge" (\ edge -> do
155177
sink <- edge A..: fromString "sink"
156178
attrs <- edge A..: fromString "attrs"
157-
f (IntMap.! sink) attrs)
179+
f sink attrs)

0 commit comments

Comments
 (0)