Skip to content

Commit 7ca79f4

Browse files
committed
Introduced Expr type to correspond to Pat. DERIVER IS BROKEN AFTER CHANGES!
1 parent 322de6c commit 7ca79f4

File tree

11 files changed

+783
-339
lines changed

11 files changed

+783
-339
lines changed

lambda-buffers-compiler/lambda-buffers-compiler.cabal

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,8 +152,10 @@ test-suite tests
152152
hs-source-dirs: test
153153
main-is: Test.hs
154154
build-depends:
155+
, containers
155156
, lambda-buffers-compiler
156157
, lambda-buffers-compiler-pb >=0.1
158+
, prettyprinter
157159
, proto-lens >=0.7
158160
, QuickCheck >=2.14
159161
, tasty >=1.4
@@ -162,6 +164,7 @@ test-suite tests
162164
, text >=1.2
163165

164166
other-modules:
167+
Test.DeriveCheck
165168
Test.KindCheck
166169
Test.TypeClassCheck
167170
Test.Utils.CompilerInput

lambda-buffers-compiler/src/LambdaBuffers/Compiler/TypeClass/Compat.hs

Lines changed: 52 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,14 @@
11
{-# LANGUAGE OverloadedLabels #-}
22

3-
module LambdaBuffers.Compiler.TypeClass.Compat (
4-
modulename,
5-
defToPat,
6-
tyToPat,
7-
) where
3+
module LambdaBuffers.Compiler.TypeClass.Compat where
84

95
import Control.Lens ((^.))
106
import Control.Lens.Combinators (view)
117
import Data.List.NonEmpty (NonEmpty ((:|)))
128
import Data.List.NonEmpty qualified as NE
139
import Data.Text qualified as T
1410
import LambdaBuffers.Compiler.ProtoCompat qualified as P
15-
import LambdaBuffers.Compiler.TypeClass.Pat (
16-
Pat (
17-
AppP,
18-
DecP,
19-
ModuleName,
20-
Name,
21-
Nil,
22-
Opaque,
23-
RefP,
24-
TyVarP,
25-
(:*),
26-
(:=)
27-
),
28-
toProd,
29-
toRec,
30-
toSum,
31-
)
11+
import LambdaBuffers.Compiler.TypeClass.Pat
3212

3313
{-
3414
TyDefs
@@ -47,39 +27,78 @@ making the resulting Pat suitable for substitution into Rules.
4727
4828
(TyVarP is a literal pattern)
4929
-}
30+
defToExp :: P.TyDef -> Exp
31+
defToExp (P.TyDef tName (P.TyAbs tArgs tBody _) _) = DecE (LitE . Name $ tName ^. #name) vars $ case tBody of
32+
P.SumI constrs -> toSumE . NE.toList . fmap goConstr $ (constrs ^. #constructors)
33+
P.OpaqueI _ -> LitE Opaque
34+
where
35+
collectFreeTyVars :: [P.TyArg] -> Exp
36+
collectFreeTyVars = foldr (\x acc -> LitE (TyVar (x ^. (#argName . #name))) *: acc) nil
37+
38+
vars = collectFreeTyVars tArgs
39+
40+
goConstr :: P.Constructor -> Exp
41+
goConstr (P.Constructor n p) = LitE (Name (n ^. #name)) *= goProduct p
42+
43+
goProduct :: P.Product -> Exp
44+
goProduct = \case
45+
P.RecordI (P.Record rMap _) -> toRecE . NE.toList . fmap goField $ rMap
46+
P.TupleI (P.Tuple pList _) -> toProdE $ fmap tyToExp pList
47+
48+
goField :: P.Field -> Exp
49+
goField (P.Field n v) = LitE (Name (n ^. #name)) *= tyToExp v
50+
51+
tyToExp :: P.Ty -> Exp
52+
tyToExp = \case
53+
P.TyVarI t -> LitE . TyVar $ t ^. #varName . #name
54+
P.TyAppI tapp ->
55+
let fun = tyToExp $ tapp ^. #tyFunc
56+
ps = tyToExp <$> tapp ^. #tyArgs
57+
in appToExp fun ps
58+
P.TyRefI ref -> case ref of
59+
P.LocalI (P.LocalRef tn _) -> RefE NilE . LitE . Name $ tn ^. #name
60+
P.ForeignI (P.ForeignRef tn mn _) ->
61+
let mnm = modulename mn
62+
in RefE (LitE $ ModuleName mnm) . LitE . Name $ (tn ^. #name)
63+
64+
appToExp :: Exp -> NonEmpty Exp -> Exp
65+
appToExp fun (p :| ps) = case NE.nonEmpty ps of
66+
Nothing -> AppE fun p
67+
Just rest -> AppE fun p `appToExp` rest
68+
5069
defToPat :: P.TyDef -> Pat
51-
defToPat (P.TyDef tName (P.TyAbs tArgs tBody _) _) = DecP (Name $ tName ^. #name) vars $ case tBody of
52-
P.SumI constrs -> toSum . NE.toList . fmap goConstr $ (constrs ^. #constructors)
53-
P.OpaqueI _ -> Opaque
70+
defToPat (P.TyDef tName (P.TyAbs tArgs tBody _) _) = DecP (LitP . Name $ tName ^. #name) vars $ case tBody of
71+
P.SumI constrs -> toSumP . NE.toList . fmap goConstr $ (constrs ^. #constructors)
72+
P.OpaqueI _ -> LitP Opaque
5473
where
5574
collectFreeTyVars :: [P.TyArg] -> Pat
56-
collectFreeTyVars = foldr (\x acc -> TyVarP (x ^. (#argName . #name)) :* acc) Nil
75+
collectFreeTyVars = foldr (\x acc -> VarP (x ^. (#argName . #name)) *: acc) nil
5776

5877
vars = collectFreeTyVars tArgs
5978

6079
goConstr :: P.Constructor -> Pat
61-
goConstr (P.Constructor n p) = Name (n ^. #name) := goProduct p
80+
goConstr (P.Constructor n p) = LitP (Name (n ^. #name)) *= goProduct p
6281

6382
goProduct :: P.Product -> Pat
6483
goProduct = \case
65-
P.RecordI (P.Record rMap _) -> toRec . NE.toList . fmap goField $ rMap
66-
P.TupleI (P.Tuple pList _) -> toProd $ fmap tyToPat pList
84+
P.RecordI (P.Record rMap _) -> toRecP . NE.toList . fmap goField $ rMap
85+
P.TupleI (P.Tuple pList _) -> toProdP $ fmap tyToPat pList
6786

6887
goField :: P.Field -> Pat
69-
goField (P.Field n v) = Name (n ^. #name) := tyToPat v
88+
goField (P.Field n v) = LitP (Name (n ^. #name)) *= tyToPat v
7089

7190
tyToPat :: P.Ty -> Pat
7291
tyToPat = \case
73-
P.TyVarI t -> TyVarP (t ^. #varName . #name)
92+
P.TyVarI t -> VarP (t ^. #varName . #name)
7493
P.TyAppI tapp ->
7594
let fun = tyToPat $ tapp ^. #tyFunc
7695
ps = tyToPat <$> tapp ^. #tyArgs
7796
in appToPat fun ps
7897
P.TyRefI ref -> case ref of
79-
P.LocalI (P.LocalRef tn _) -> RefP Nil . Name $ tn ^. #name
98+
P.LocalI (P.LocalRef tn _) -> RefP NilP . LitP . Name $ tn ^. #name
8099
P.ForeignI (P.ForeignRef tn mn _) ->
81100
let mnm = modulename mn
82-
in RefP (ModuleName mnm) . Name $ (tn ^. #name)
101+
in RefP (LitP $ ModuleName mnm) . LitP . Name $ (tn ^. #name)
83102

84103
appToPat :: Pat -> NonEmpty Pat -> Pat
85104
appToPat fun (p :| ps) = case NE.nonEmpty ps of
Lines changed: 90 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,8 @@
11
{-# LANGUAGE LambdaCase #-}
22

3-
module LambdaBuffers.Compiler.TypeClass.Pat (
4-
Pat (..),
5-
toProd,
6-
toRec,
7-
toSum,
8-
patList,
9-
matches,
10-
) where
3+
module LambdaBuffers.Compiler.TypeClass.Pat where
114

5+
import Data.Kind (Type)
126
import Data.Text (Text)
137

148
{- A simple ADT to represent patterns.
@@ -18,15 +12,15 @@ This could be ameliorated by using a GADT, which would give us correct-by-constr
1812
cost of significantly more complex type signatures.
1913
-}
2014

21-
data Pat
22-
= {- Name / ModuleName / Opaque / TyVarP are literal patterns (or ground terms)
23-
because hey cannot contain any VarPs and therefore "have no holes".
24-
Every TyDef or subcomponent thereof will be translated into a composite
25-
pattern "without any holes". (Nil is also a literal/ground term, I guess) -}
26-
Name Text
15+
data Literal
16+
= Name Text
2717
| ModuleName [Text]
2818
| Opaque
29-
| TyVarP Text
19+
| TyVar Text
20+
deriving stock (Show, Eq, Ord)
21+
22+
data Pat
23+
= LitP Literal
3024
| {- Lists (constructed from Nil and :*) with bare types are used to
3125
encode products (where a list of length n encodes an n-tuple)
3226
Lists with field labels (l := t) are used to encode records and sum types
@@ -40,10 +34,10 @@ data Pat
4034
using a GADT for Pat, but this would greatly complicate the constraint solving/deriving
4135
algorithms and require copious use of type families (and possibly singletons).
4236
-}
43-
Nil -- Nil and :* are hacks to write rules for ProdP and SumP. A bare Nil == Unit
44-
| Pat :* Pat -- cons
45-
| Pat := Pat {- field labels or constr names. The LHS should be (Name "Foo")
46-
for schema types, but should be a PatVar for deriving rules and instances -}
37+
NilP -- Nil and :* are hacks to write rules for ProdP and SumP. A bare Nil == Unit
38+
| ConsP Pat Pat -- cons
39+
| LabelP Pat Pat {- field labels or constr names. The LHS should be (Name "Foo")
40+
for schema types, but should be a PatVar for deriving rules and instances -}
4741
| RecP Pat {- where the Pat arg is expected to be (l := t :* rest) or Nil, where rest
4842
is also a pat-list of labeled fields or Nil -}
4943
| ProdP Pat {- Pat arg should be a list of "Bare types" -}
@@ -62,26 +56,83 @@ data Pat
6256
DecP Pat Pat Pat
6357
deriving stock (Show, Eq, Ord)
6458

65-
infixr 5 :*
59+
-- infixr 5 :*
6660

6761
{- Utility functions. Turn a list of types into a product/record/sum type.
6862
-}
69-
toProd :: [Pat] -> Pat
70-
toProd = ProdP . foldr (:*) Nil
63+
toProdP :: [Pat] -> Pat
64+
toProdP = ProdP . foldr ConsP NilP
7165

72-
toRec :: [Pat] -> Pat
73-
toRec = RecP . foldr (:*) Nil
66+
toRecP :: [Pat] -> Pat
67+
toRecP = RecP . foldr ConsP NilP
7468

75-
toSum :: [Pat] -> Pat
76-
toSum = SumP . foldr (:*) Nil
69+
toSumP :: [Pat] -> Pat
70+
toSumP = SumP . foldr ConsP NilP
7771

7872
{- Converts a pattern that consists of a well formed pattern list
7973
(i.e. patterns formed from :* and Nil) into a list of patterns.
8074
-}
8175
patList :: Pat -> Maybe [Pat]
8276
patList = \case
83-
Nil -> Just []
84-
p1 :* p2 -> (p1 :) <$> patList p2
77+
NilP -> Just []
78+
p1 `ConsP` p2 -> (p1 :) <$> patList p2
79+
_ -> Nothing
80+
81+
data Exp
82+
= LitE Literal
83+
| NilE
84+
| ConsE Exp Exp
85+
| LabelE Exp Exp
86+
| RecE Exp
87+
| ProdE Exp
88+
| SumE Exp
89+
| -- NO EXPRESSION VARS! EXPRESSIONS DON'T HAVE HOLES!
90+
RefE Exp Exp {- 1st arg should be a ModuleName -}
91+
| AppE Exp Exp {- Pattern for Type applications -}
92+
| DecE Exp Exp Exp
93+
deriving stock (Show, Eq, Ord)
94+
95+
class ExpressionLike (p :: Type) where
96+
(*:) :: p -> p -> p
97+
98+
nil :: p
99+
100+
(*=) :: p -> p -> p
101+
102+
infixr 5 *:
103+
104+
instance ExpressionLike Pat where
105+
p1 *: p2 = p1 `ConsP` p2
106+
107+
nil = NilP
108+
109+
p1 *= p2 = LabelP p1 p2
110+
111+
instance ExpressionLike Exp where
112+
p1 *: p2 = p1 `ConsE` p2
113+
114+
nil = NilE
115+
116+
p1 *= p2 = LabelE p1 p2
117+
118+
{- Utility functions. Turn a list of types into a product/record/sum type.
119+
-}
120+
toProdE :: [Exp] -> Exp
121+
toProdE = ProdE . foldr ConsE NilE
122+
123+
toRecE :: [Exp] -> Exp
124+
toRecE = RecE . foldr ConsE NilE
125+
126+
toSumE :: [Exp] -> Exp
127+
toSumE = SumE . foldr ConsE NilE
128+
129+
{- Converts a pattern that consists of a well formed pattern list
130+
(i.e. patterns formed from :* and Nil) into a list of patterns.
131+
-}
132+
expList :: Exp -> Maybe [Exp]
133+
expList = \case
134+
NilE -> Just []
135+
p1 `ConsE` p2 -> (p1 :) <$> expList p2
85136
_ -> Nothing
86137

87138
{- This is used as a predicate to filter instances or Gens which are structurally compatible
@@ -91,16 +142,17 @@ patList = \case
91142
NOTE: Is not bidirectional! The first Pat has to be more general than the first
92143
(more specifically: The second Pat should be a substitution instance of the first)
93144
-}
94-
matches :: Pat -> Pat -> Bool
95-
matches t1 t2 | t1 == t2 = True -- need the guard
145+
matches :: Pat -> Exp -> Bool
146+
matches (LitP l1) (LitE l2) = l1 == l2
96147
matches (VarP _) _ = True
97-
matches (x :* xs) (x' :* xs') = matches x x' && matches xs xs'
98-
matches (l := t) (l' := t') = matches l l' && matches t t'
99-
matches (ProdP xs) (ProdP xs') = matches xs xs'
100-
matches (RecP xs) (RecP xs') = matches xs xs'
101-
matches (SumP xs) (SumP xs') = matches xs xs'
102-
matches (AppP t1 t2) (AppP t1' t2') = matches t1 t1' && matches t2 t2'
103-
matches (RefP mn t1) (RefP mn' t2) = matches mn mn' && matches t1 t2
104-
matches (DecP t1 t2 t3) (DecP t1' t2' t3') =
148+
matches (x `ConsP` xs) (x' `ConsE` xs') = matches x x' && matches xs xs'
149+
matches (LabelP l t) (LabelE l' t') = matches l l' && matches t t'
150+
matches (ProdP xs) (ProdE xs') = matches xs xs'
151+
matches (RecP xs) (RecE xs') = matches xs xs'
152+
matches (SumP xs) (SumE xs') = matches xs xs'
153+
matches (AppP t1 t2) (AppE t1' t2') = matches t1 t1' && matches t2 t2'
154+
matches (RefP mn t1) (RefE mn' t2) = matches mn mn' && matches t1 t2
155+
matches (DecP t1 t2 t3) (DecE t1' t2' t3') =
105156
matches t1 t1' && matches t2 t2' && matches t3 t3'
157+
matches NilP NilE = True
106158
matches _ _ = False

0 commit comments

Comments
 (0)