Skip to content

Commit e2c784a

Browse files
committed
basic record support
1 parent badb8c2 commit e2c784a

File tree

6 files changed

+100
-15
lines changed

6 files changed

+100
-15
lines changed

agda2lambox.cabal

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ executable agda2lambox
2323
Agda2Lambox.Convert.Class,
2424
Agda2Lambox.Convert.Data,
2525
Agda2Lambox.Convert.Function,
26+
Agda2Lambox.Convert.Record,
2627
Agda2Lambox.Convert.Term,
2728
Agda2Lambox,
2829
Utils,

src/Agda2Lambox/Convert/Function.hs

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,12 @@ module Agda2Lambox.Convert.Function
77
import Control.Monad.Reader ( ask, liftIO )
88
import Control.Monad ( forM )
99
import Data.List ( elemIndex )
10+
import Data.Maybe ( isNothing, isJust )
1011

1112
import Utils
1213

1314
import Agda ( liftTCM )
14-
import Agda.Lib ()
15+
import Agda.Lib ( (^.), funInline )
1516
import Agda.Utils
1617
import Agda.Syntax.Abstract.Name ( qnameModule )
1718
import Agda.TypeChecking.Monad.Base
@@ -20,6 +21,7 @@ import Agda.Compiler.ToTreeless ( toTreeless )
2021
import Agda.Compiler.Backend ( getConstInfo )
2122
import Agda.Syntax.Treeless ( EvaluationStrategy(EagerEvaluation) )
2223
import Agda.Syntax.Common.Pretty ( prettyShow )
24+
import Agda.Syntax.Common ( hasQuantityω )
2325

2426
import LambdaBox
2527

@@ -40,14 +42,29 @@ convertFunctionBody Defn{defName} =
4042
Just t <- liftTCM $ toTreeless EagerEvaluation defName
4143
convert t
4244

45+
-- | Whether a function is a (true) record projection.
46+
isProjection :: Either ProjectionLikenessMissing Projection -> Bool
47+
isProjection (Left _) = False
48+
isProjection (Right Projection{projProper}) = isJust projProper
49+
50+
-- | Whether to compile a function definition to λ□.
51+
shouldCompileFunction :: Definition -> Bool
52+
shouldCompileFunction def@Defn{theDef} | Function{..} <- theDef
53+
= not (theDef ^. funInline) -- not inlined (from module application)
54+
&& isNothing funExtLam -- not a pattern-lambda-generated function NOTE(flupe): ?
55+
&& isNothing funWith -- not a with-generated function NOTE(flupe): ?
56+
&& not (isProjection funProjection) -- not a record projection
57+
&& hasQuantityω def -- non-erased
58+
4359
-- | Convert a function definition to a λ□ declaration.
44-
convertFunction :: Definition :~> GlobalDecl
60+
convertFunction :: Definition :~> Maybe GlobalDecl
61+
convertFunction defn | not (shouldCompileFunction defn) = return Nothing
4562
convertFunction defn@Defn{defName, theDef} =
4663
withCurrentModule (qnameModule defName) do
4764
let Function{funMutual = Just ms} = theDef
4865

4966
if null ms then
50-
ConstantDecl . Just <$> convertFunctionBody defn
67+
Just. ConstantDecl . Just <$> convertFunctionBody defn
5168
else do
5269
mdefs :: [Definition] <- mapM getConstInfo ms
5370

@@ -59,7 +76,7 @@ convertFunction defn@Defn{defName, theDef} =
5976
-- it's unclear in which order mutual fixpoints are added to the local context
6077
let Just k = elemIndex defName ms
6178

62-
ConstantDecl . Just . flip LFix k <$>
79+
Just . ConstantDecl . Just . flip LFix k <$>
6380
forM mdefs \def@Defn{defName} -> do
6481
body <- convertFunctionBody def
6582
return Def

src/Agda2Lambox/Convert/Record.hs

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
{-# LANGUAGE NamedFieldPuns #-}
2+
-- | Convert Agda records to λ□ inductive declarations
3+
module Agda2Lambox.Convert.Record
4+
( convertRecord
5+
) where
6+
7+
import Control.Monad.Reader ( ask, liftIO )
8+
import Control.Monad ( forM )
9+
import Data.List ( elemIndex )
10+
import Data.Maybe ( maybe )
11+
12+
import Utils
13+
14+
import Agda ( liftTCM )
15+
import Agda.Lib ()
16+
import Agda.Utils
17+
import Agda.Syntax.Abstract.Name ( qnameModule, qnameName )
18+
import Agda.TypeChecking.Monad.Base
19+
import Agda.TypeChecking.Monad.Env ( withCurrentModule )
20+
import Agda.TypeChecking.Datatypes ( ConstructorInfo(..), getConstructorInfo )
21+
import Agda.Compiler.ToTreeless ( toTreeless )
22+
import Agda.Compiler.Backend ( getConstInfo )
23+
import Agda.Syntax.Treeless ( EvaluationStrategy(EagerEvaluation) )
24+
import Agda.Syntax.Internal ( ConHead(..), unDom )
25+
import Agda.Syntax.Common.Pretty ( prettyShow )
26+
import Agda.Syntax.Common as A ( Induction(..) )
27+
28+
import LambdaBox
29+
30+
import Agda2Lambox.Monad
31+
import Agda2Lambox.Convert.Class
32+
import Agda.Utils.Monad (guardWithError)
33+
34+
inductionToRecKind :: Induction -> RecursivityKind
35+
inductionToRecKind = \case
36+
A.Inductive -> Finite
37+
A.CoInductive -> CoFinite
38+
39+
-- | Convert a datatype definition to a Lambdabox declaration.
40+
convertRecord :: Definition :~> GlobalDecl
41+
convertRecord defn@Defn{defName, theDef} =
42+
withCurrentModule (qnameModule defName) $
43+
let
44+
45+
Record{..} = theDef
46+
ConHead{conName, conFields} = recConHead
47+
48+
fields :: [ProjectionBody]
49+
= Proj . prettyShow . qnameName . unDom <$> recFields
50+
51+
record = OneInductive
52+
{ indName = prettyShow $ qnameName defName
53+
, indPropositional = False -- TODO(flupe): take care of this
54+
, indKElim = IntoAny -- TODO(flupe): also take care of this
55+
, indCtors = [ Ctor (prettyShow $ qnameName conName)
56+
(length conFields) ]
57+
, indProjs = fields
58+
}
59+
60+
in return $ InductiveDecl MutualInductive
61+
{ indFinite = maybe BiFinite inductionToRecKind recInduction
62+
, indPars = 0
63+
-- TODO(flupe):
64+
-- ^ double-check, but it doesn't look like
65+
-- this could be anything other than 0.
66+
, indBodies = [record]
67+
}

src/LambdaBox.hs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,9 @@ data Inductive = Inductive
2323
-- ^ Which of those is the inductive we care about.
2424
} deriving (Eq, Show)
2525

26-
2726
data Name = Anon | Named Ident
2827
deriving (Eq, Show)
2928

30-
3129
type DirPath = [Ident]
3230

3331
-- | The module part of the kernel name

src/Main.hs

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,12 @@ import Paths_agda2lambox ( version )
1717

1818
import Agda.Lib hiding ( (<?>), pretty )
1919
import Agda.Syntax.Common.Pretty ( (<?>), pretty )
20-
import Agda.Syntax.Common ( hasQuantityω )
2120
import Agda.Utils ( pp, unqual, hasPragma )
2221

2322
import Agda2Lambox.Convert ( convert )
2423
import Agda2Lambox.Convert.Function ( convertFunction )
2524
import Agda2Lambox.Convert.Data ( convertDatatype )
25+
import Agda2Lambox.Convert.Record ( convertRecord )
2626
import Agda2Lambox.Monad ( runC0, inMutuals )
2727
import CoqGen ( ToCoq(ToCoq), CoqModule(..) )
2828
import LambdaBox ( KerName, GlobalDecl, qnameToKerName )
@@ -82,22 +82,18 @@ compile opts menv _ def@Defn{..} =
8282
fmap (qnameToKerName defName,) <$> -- prepend kername
8383
case theDef of
8484

85-
-- TODO(flupe): offload the check to Convert.Function
86-
Function{..}
87-
| not (theDef ^. funInline) -- not inlined (from module application)
88-
, isNothing funExtLam -- not a pattern-lambda-generated function NOTE(flupe): ?
89-
, isNothing funWith -- not a with-generated function NOTE(flupe): ?
90-
, hasQuantityω def -- non-erased
91-
-> do
85+
Function{} -> do
9286
-- if the function is annotated with a COMPILE pragma
9387
-- then it is added to the list of programs to run
9488
whenM (hasPragma defName) $
9589
liftIO $ modifyIORef' (modProgs menv) (qnameToKerName defName:)
9690

97-
Just <$> runC0 (convertFunction def)
91+
runC0 (convertFunction def)
9892

9993
Datatype{} -> Just <$> runC0 (convertDatatype def)
10094

95+
Record{} -> Just <$> runC0 (convertRecord def)
96+
10197
_ -> Nothing <$ (liftIO $ putStrLn $ "Skipping " <> prettyShow defName)
10298

10399

test/OddEven.agda

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,3 +26,9 @@ even (succ n) = odd n
2626
test : Bool
2727
test = odd (succ (succ zero))
2828
{-# COMPILE AGDA2LAMBOX test #-}
29+
30+
record Pair (A : Set) (B : Set) : Set where
31+
constructor _,_
32+
field
33+
fst : A
34+
snd : B

0 commit comments

Comments
 (0)