Skip to content

Commit 54c5cb7

Browse files
authored
Merge pull request #636 from hackworthltd/georgefst/primitive-sum
refactor: Use a sum type for primitive definitions
2 parents 1104dcd + c117f4f commit 54c5cb7

File tree

14 files changed

+334
-441
lines changed

14 files changed

+334
-441
lines changed

primer/gen/Primer/Gen/App.hs

+2-1
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,11 @@ module Primer.Gen.App (
1010
) where
1111

1212
import Primer.App (Prog (Prog, progImports, progLog, progModules, progSelection, progSmartHoles), defaultLog)
13-
import Primer.Core (ASTDef (ASTDef), Def (DefAST), GlobalName (baseName), Kind (KType), ModuleName (ModuleName), defType, qualifyName)
13+
import Primer.Core (ASTDef (ASTDef), Def (DefAST), GlobalName (baseName), Kind (KType), ModuleName (ModuleName), qualifyName)
1414
import Primer.Core.Utils (forgetTypeMetadata, generateIDs, generateTypeIDs)
1515
import Primer.Module (Module (Module, moduleDefs, moduleName, moduleTypes), moduleDefsQualified, moduleTypesQualified)
1616
import Primer.Name (Name, unsafeMkName)
17+
import Primer.Primitives (defType)
1718
import Primer.Typecheck (Cxt, SmartHoles, extendGlobalCxt, extendTypeDefCxt)
1819

1920
import Primer.Gen.Core.Typed (WT, freshNameForCxt, genChk, genTypeDefGroup, genWTType)

primer/src/Primer/API.hs

+29-11
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
{-# LANGUAGE BlockArguments #-}
12
{-# LANGUAGE GADTs #-}
23

34
-- | The Primer API.
@@ -63,7 +64,7 @@ import Control.Monad.Zip (MonadZip)
6364
import Data.Map qualified as Map
6465
import Data.Text qualified as T
6566
import ListT qualified (toList)
66-
import Optics (ifoldr, (^.))
67+
import Optics (ifoldr, over, traverseOf, view, (^.))
6768
import Primer.App (
6869
App,
6970
EditAppM,
@@ -107,10 +108,12 @@ import Primer.Core (
107108
Type,
108109
Type' (..),
109110
defAST,
110-
defType,
111111
moduleNamePretty,
112112
unLocalName,
113+
_typeMeta,
114+
_typeMetaLens,
113115
)
116+
import Primer.Core qualified as Core
114117
import Primer.Database (
115118
OffsetLimit,
116119
Page,
@@ -146,6 +149,7 @@ import Primer.JSON (
146149
)
147150
import Primer.Module (moduleDefsQualified, moduleName, moduleTypesQualified)
148151
import Primer.Name (Name, unName)
152+
import Primer.Primitives (primDefType)
149153
import StmContainers.Map qualified as StmMap
150154

151155
-- | The API environment.
@@ -480,11 +484,20 @@ viewProg p =
480484
, editable = e
481485
, types = fst <$> Map.assocs (moduleTypesQualified m)
482486
, defs =
483-
( \(n, d) ->
487+
( \(name, d) ->
484488
Def
485-
{ name = n
486-
, type_ = viewTreeType $ defType d
489+
{ name
487490
, term = viewTreeExpr . astDefExpr <$> defAST d
491+
, type_ =
492+
case d of
493+
Core.DefAST d' -> viewTreeType $ astDefType d'
494+
Core.DefPrim d' -> viewTreeType' $ labelNodes $ primDefType d'
495+
where
496+
labelNodes =
497+
flip evalState (0 :: Int) . traverseOf _typeMeta \() -> do
498+
n <- get
499+
put $ n + 1
500+
pure $ "primtype_" <> show d' <> "_" <> show n
488501
}
489502
)
490503
<$> Map.assocs (moduleDefsQualified m)
@@ -668,7 +681,12 @@ viewTreeExpr e0 = case e0 of
668681

669682
-- | Similar to 'viewTreeExpr', but for 'Type's
670683
viewTreeType :: Type -> Tree
671-
viewTreeType t0 = case t0 of
684+
viewTreeType = viewTreeType' . over _typeMeta (show . view _id)
685+
686+
-- | Like 'viewTreeType', but with the flexibility to accept arbitrary textual node identifiers,
687+
-- rather than using the type's numeric IDs.
688+
viewTreeType' :: Type' Text -> Tree
689+
viewTreeType' t0 = case t0 of
672690
TEmptyHole _ ->
673691
Tree
674692
{ nodeId
@@ -682,7 +700,7 @@ viewTreeType t0 = case t0 of
682700
{ nodeId
683701
, flavor = FlavorTHole
684702
, body = NoBody
685-
, childTrees = [viewTreeType t]
703+
, childTrees = [viewTreeType' t]
686704
, rightChild = Nothing
687705
}
688706
TCon _ n ->
@@ -698,7 +716,7 @@ viewTreeType t0 = case t0 of
698716
{ nodeId
699717
, flavor = FlavorTFun
700718
, body = NoBody
701-
, childTrees = [viewTreeType t1, viewTreeType t2]
719+
, childTrees = [viewTreeType' t1, viewTreeType' t2]
702720
, rightChild = Nothing
703721
}
704722
TVar _ n ->
@@ -714,15 +732,15 @@ viewTreeType t0 = case t0 of
714732
{ nodeId
715733
, flavor = FlavorTApp
716734
, body = NoBody
717-
, childTrees = [viewTreeType t1, viewTreeType t2]
735+
, childTrees = [viewTreeType' t1, viewTreeType' t2]
718736
, rightChild = Nothing
719737
}
720738
TForall _ n k t ->
721739
Tree
722740
{ nodeId
723741
, flavor = FlavorTForall
724742
, body = TextBody $ withKindAnn $ unName $ unLocalName n
725-
, childTrees = [viewTreeType t]
743+
, childTrees = [viewTreeType' t]
726744
, rightChild = Nothing
727745
}
728746
where
@@ -733,7 +751,7 @@ viewTreeType t0 = case t0 of
733751
KType -> identity
734752
_ -> (<> (" :: " <> show k))
735753
where
736-
nodeId = show $ t0 ^. _id
754+
nodeId = t0 ^. _typeMetaLens
737755

738756
showGlobal :: GlobalName k -> Text
739757
showGlobal n = moduleNamePretty (qualifiedModule n) <> "." <> unName (baseName n)

primer/src/Primer/Core.hs

+24-36
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,6 @@ module Primer.Core (
1212
CaseBranch' (..),
1313
Def (..),
1414
DefMap,
15-
_defType,
16-
defType,
1715
ASTDef (..),
1816
defAST,
1917
PrimDef (..),
@@ -55,8 +53,6 @@ module Primer.Core (
5553
PrimTypeDef (..),
5654
PrimCon (..),
5755
primConName,
58-
PrimFun (..),
59-
primFunType,
6056
PrimFunError (..),
6157
ValCon (..),
6258
valConType,
@@ -78,7 +74,6 @@ module Primer.Core (
7874

7975
import Foreword
8076

81-
import Control.Monad.Fresh (MonadFresh (fresh))
8277
import Data.Aeson (Value)
8378
import Data.Data (Data)
8479
import Data.Generics.Product
@@ -93,7 +88,6 @@ import Optics (
9388
afailing,
9489
atraversalVL,
9590
lens,
96-
lensVL,
9791
set,
9892
view,
9993
(%),
@@ -492,13 +486,29 @@ data Def
492486
type DefMap = Map GVarName Def
493487

494488
-- | A primitive, built-in definition.
495-
-- Names and definitions of primitives are hard-coded in Primer.Primitives.
496-
-- A @PrimDef@ simply exposes one of those, and thus the type must match
497-
-- the one stored in the corresponding 'PrimFun'.
498-
newtype PrimDef = PrimDef
499-
{ primDefType :: Type
500-
}
501-
deriving (Eq, Show, Data, Generic)
489+
-- For each of these, we should have a test that the evaluator produces expected results.
490+
data PrimDef
491+
= ToUpper
492+
| IsSpace
493+
| HexToNat
494+
| NatToHex
495+
| EqChar
496+
| IntAdd
497+
| IntMinus
498+
| IntMul
499+
| IntQuotient
500+
| IntRemainder
501+
| IntQuot
502+
| IntRem
503+
| IntLT
504+
| IntLTE
505+
| IntGT
506+
| IntGTE
507+
| IntEq
508+
| IntNeq
509+
| IntToNat
510+
| IntFromNat
511+
deriving (Eq, Show, Enum, Bounded, Data, Generic)
502512
deriving (FromJSON, ToJSON) via PrimerJSON PrimDef
503513

504514
-- | A top-level definition, built from an 'Expr'
@@ -509,12 +519,6 @@ data ASTDef = ASTDef
509519
deriving (Eq, Show, Data, Generic)
510520
deriving (FromJSON, ToJSON) via PrimerJSON ASTDef
511521

512-
_defType :: Lens' Def Type
513-
_defType = lensVL $ \f -> \case
514-
DefPrim (PrimDef t) -> DefPrim . PrimDef <$> f t
515-
DefAST (ASTDef e t) -> DefAST . ASTDef e <$> f t
516-
defType :: Def -> Type
517-
defType = view _defType
518522
defAST :: Def -> Maybe ASTDef
519523
defAST = \case
520524
DefPrim _ -> Nothing
@@ -537,26 +541,10 @@ primConName = \case
537541
PrimChar _ -> qualifyName (mkSimpleModuleName "Primitives") "Char"
538542
PrimInt _ -> qualifyName (mkSimpleModuleName "Primitives") "Int"
539543

540-
data PrimFun = PrimFun
541-
{ primFunTypes :: forall m. MonadFresh ID m => m ([Type], Type)
542-
-- ^ the function's arguments and return type
543-
, primFunDef :: [Expr' () ()] -> Either PrimFunError (forall m. MonadFresh ID m => m Expr)
544-
}
545-
546-
primFunType :: forall m. MonadFresh ID m => PrimFun -> m Type
547-
primFunType pf = do
548-
(args, res) <- primFunTypes pf
549-
foldrM f res args
550-
where
551-
f x y = do
552-
id <- fresh
553-
pure $ TFun (Meta id Nothing Nothing) x y
554-
555544
data PrimFunError
556545
= -- | We have attempted to apply a primitive function to invalid args.
557546
PrimFunError
558-
GVarName
559-
-- ^ Function name
547+
PrimDef
560548
[Expr' () ()]
561549
-- ^ Arguments
562550
deriving (Eq, Show, Data, Generic)

primer/src/Primer/Core/Utils.hs

+1-2
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,6 @@ import Primer.Core (
6060
Kind (KHole),
6161
LVarName,
6262
LocalName (LocalName, unLocalName),
63-
PrimDef (..),
6463
TmVarRef (GlobalVarRef, LocalVarRef),
6564
TyVarName,
6665
Type,
@@ -271,5 +270,5 @@ nextID (DefAST (ASTDef e t)) =
271270
let eid = foldlOf' exprIDs max minBound e
272271
tid = foldlOf' typeIDs max minBound t
273272
in succ $ max eid tid
274-
nextID (DefPrim (PrimDef t)) = succ $ foldlOf' typeIDs max minBound t
273+
nextID (DefPrim _) = 0
275274
{-# INLINE nextID #-}

primer/src/Primer/Eval.hs

+3-6
Original file line numberDiff line numberDiff line change
@@ -63,8 +63,6 @@ import Primer.Core (
6363
LocalName (LocalName, unLocalName),
6464
LocalNameKind (..),
6565
Meta,
66-
PrimDef (..),
67-
PrimFun (..),
6866
PrimFunError (..),
6967
TmVarRef (..),
7068
TyVarName,
@@ -95,7 +93,7 @@ import Primer.Core.Utils (
9593
import Primer.JSON
9694
import Primer.Name (Name, unName, unsafeMkName)
9795
import Primer.Name.Fresh (isFresh, isFreshTy)
98-
import Primer.Primitives (allPrimDefs)
96+
import Primer.Primitives (PrimDef, primFunDef)
9997
import Primer.Zipper (
10098
ExprZ,
10199
FoldAbove,
@@ -989,9 +987,8 @@ tryPrimFun :: Map GVarName PrimDef -> Expr -> Maybe (GVarName, [Expr], forall m.
989987
tryPrimFun primDefs expr
990988
| -- Since no primitive functions are polymorphic, there is no need to unfoldAPP
991989
(Var _ (GlobalVarRef name), args) <- bimap stripAnns (map stripAnns) $ unfoldApp expr
992-
, Map.member name primDefs
993-
, Just PrimFun{primFunDef} <- Map.lookup name allPrimDefs
994-
, Right e <- primFunDef $ forgetMetadata <$> args =
990+
, Just x <- Map.lookup name primDefs
991+
, Right e <- primFunDef x $ forgetMetadata <$> args =
995992
Just (name, args, e)
996993
| otherwise = Nothing
997994
where

0 commit comments

Comments
 (0)