on master help sign in
Merge pull request #2232 from david-christiansen/agda-style-records

New record syntax

commit5e239ba649fce3d29e921eacb7daa12d7589de93 authorDavid Christiansen <david@davidchristiansen.dk> dateFri 8 May 2015, 10:32 (11 years ago) parent501372fea5624e
37 files changed+811−371
CHANGELOG+4 docs/reference/documenting.rst+5−5 docs/reference/ffi.rst+6−5 docs/tutorial/typesfuns.rst+46−17 idris.cabal+7 libs/base/Control/Monad/Identity.idr+3−2 libs/base/Control/Monad/RWS.idr+4−4 libs/base/Control/Monad/Reader.idr+3−3 libs/base/Control/Monad/State.idr+5−5 libs/base/Control/Monad/Writer.idr+3−3 libs/contrib/Network/Cgi.idr+8−7 libs/contrib/Network/Socket.idr+17−19 libs/prelude/IO.idr+5−4 libs/prelude/Prelude/Nat.idr+7−5 src/Idris/AbsSyntax.hs+2−7 src/Idris/AbsSyntaxTree.hs+15−7 src/Idris/DeepSeq.hs+2−2 src/Idris/Elab/Record.hs+414−211 src/Idris/ElabDecls.hs+6−4 src/Idris/IBC.hs+6−2 src/Idris/ParseData.hs+83−16 src/Idris/ParseHelpers.hs+3−4 test/basic001/reg005.dSYM/Contents/Info.plist+20 test/basic001/reg005.dSYM/Contents/Resources/DWARF/reg005 test/corecords001/corecords001.idr+24 test/corecords001/expected+5 test/corecords001/run+4 test/corecords002/corecords002.idr+24 test/corecords002/expected+3 test/corecords002/run+4 test/docs004/docs004.idr+11 test/docs004/expected+15 test/docs004/input+3 test/docs004/run+3 test/records001/test011.idr+10−8 test/records002/record002.idr+7−6 test/records003/records003.idr+24−25
CHANGELOG+4
@@ -36,6 +36,10 @@ New in 0.9.18:
3636 "n". If "n" is lexically bound, then the resulting quotation will be for it,
3737 whereas if it is not, then it will succeed with a quotation of the unique
3838 global name that matches.
39+* New syntax for records that closely matches our other record-like structures:
40+ type classes. See the updated tutorial for details.
41+* Records can be coinductive. Define coinductive records with the "corecord"
42+ keyword.
3943* if ... then ... else ... is now built-in syntax instead of being defined in
4044 a library. It is shown in REPL output and error messages, rather than its
4145 desugaring.
docs/reference/documenting.rst+5−5
@@ -127,9 +127,9 @@ italics correctly). A comprehensive set of examples is given below.
127127 ||| @ rest the remaining work
128128 Later : (rest : Partial a) -> Partial a
129129
130− ||| We can document records just like normal data
131− record Yummy : Type where
132−
130+ ||| We can document records, including their fields and constructors
131+ record Yummy where
133132 ||| Make a yummy
134− ||| @ food what to eat
135− MkYummy : (food : String) -> Yummy
133+ constructor MkYummy
134+ ||| What to eat
135+ food : String
docs/reference/ffi.rst+6−5
@@ -70,21 +70,22 @@ call:
7070
7171.. code-block:: idris
7272
73− record FFI : Type where
74− MkFFI : (ffi_types : Type -> Type) ->
75− (ffi_fn : Type) -> FFI
73+ record FFI where
74+ constructor MkFFI
75+ ffi_types : Type -> Type
76+ ffi_fn : Type
7677
7778For C, this is:
7879
7980.. code-block:: idris
8081
81− -- Supported C integer types
82+ ||| Supported C integer types
8283 data C_IntTypes : Type -> Type where
8384 C_IntChar : C_IntTypes Char
8485 C_IntNative : C_IntTypes Int
8586 ... -- more integer types
8687
87− -- Supported C foreign types
88+ ||| Supported C foreign types
8889 data C_Types : Type -> Type where
8990 C_Str : C_Types String
9091 C_Float : C_Types Float
docs/tutorial/typesfuns.rst+46−17
@@ -979,18 +979,19 @@ example, we can represent a person's name and age in a record:
979979
980980.. code-block:: idris
981981
982− record Person : Type where
983− MkPerson : (name : String) ->
984− (age : Int) -> Person
982+ record Person where
983+ constructor MkPerson
984+ name : String
985+ age : Int
985986
986987 fred : Person
987988 fred = MkPerson "Fred" 30
988989
989−Record declarations are like ``data`` declarations, except that they
990−are introduced by the ``record`` keyword, and can only have one
991−constructor. The names of the binders in the constructor type
992−(``name`` and ``age``) here are the field names, which we can use to
993−access the field values:
990+Records can have *parameters*, which are listed between the record
991+name and the ``where`` keyword, and *fields*, which are in an indented
992+block following the `where` keyword (here, ``name`` and ``age``). The
993+constructor name is provided after the ``constructor`` keyword. The
994+field names can be used to access the field values:
994995
995996::
996997
@@ -1002,7 +1003,8 @@ access the field values:
10021003 name : Person -> String
10031004
10041005We can also use the field names to update a record (or, more
1005−precisely, produce a new record with the given fields updated).
1006+precisely, produce a copy of the record with the given fields
1007+updated):
10061008
10071009.. code-block:: bash
10081010
@@ -1016,15 +1018,14 @@ updates the given fields in a record.
10161018
10171019Records, and fields within records, can have dependent types. Updates
10181020are allowed to change the type of a field, provided that the result is
1019−well-typed, and the result does not affect the type of the record as a
1020−whole. For example:
1021+well-typed.
10211022
10221023.. code-block:: idris
10231024
1024− record Class : Type where
1025− ClassInfo : (students : Vect n Person) ->
1026− (className : String) ->
1027− Class
1025+ record Class where
1026+ constructor ClassInfo
1027+ students : Vect n Person
1028+ className : String
10281029
10291030It is safe to update the ``students`` field to a vector of a different
10301031length because it will not affect the type of the record:
@@ -1037,8 +1038,7 @@ length because it will not affect the type of the record:
10371038::
10381039
10391040 *record> addStudent fred (ClassInfo [] "CS")
1040− ClassInfo (prelude.vect.:: (MkPerson "Fred" 30) (prelude.vect.Nil)) "CS"
1041− : Class
1041+ ClassInfo [MkPerson "Fred" 30] "CS" : Class
10421042
10431043Nested record update
10441044--------------------
@@ -1060,3 +1060,32 @@ can also be accessed with the following syntax:
10601060.. code-block:: idris
10611061
10621062 record { a->b->c } x
1063+
1064+Parameters and Fields
1065+---------------------
1066+
1067+Records can have *parameters*, which are not subject to field
1068+updates. The parameters appear as arguments to the resulting type, and
1069+are written following the record type name. For example, a pair type
1070+could be defined as follows:
1071+
1072+.. code-block:: idris
1073+
1074+ record Prod a b where
1075+ constructor Times
1076+ fst : a
1077+ snd : b
1078+
1079+The parameters to a record type need not be types. For example, we can
1080+restrict the size of classes using a ``Nat`` parameter to the
1081+``Class`` record:
1082+
1083+.. code-block:: idris
1084+
1085+ record SizedClass (size : Nat) where
1086+ constructor SizedClassInfo
1087+ students : Vect size Person
1088+ className : String
1089+
1090+Note that it is no longer possible to write ``addStudent`` for this
1091+type, as that would change the size of the class.
idris.cabal+7
@@ -357,6 +357,13 @@ Extra-source-files:
357357 test/bignum002/*.idr
358358 test/bignum002/expected
359359
360+ test/corecords001/*.idr
361+ test/corecords001/run
362+ test/corecords001/expected
363+ test/corecords002/*.idr
364+ test/corecords002/run
365+ test/corecords002/expected
366+
360367 test/delab001/*.idr
361368 test/delab001/run
362369 test/delab001/expected
libs/base/Control/Monad/Identity.idr+3−2
@@ -1,7 +1,8 @@
11module Control.Monad.Identity
22
3−public record Identity : Type -> Type where
4− Id : (runIdentity : a) -> Identity a
3+public record Identity (a : Type) where
4+ constructor Id
5+ runIdentity : a
56
67instance Functor Identity where
78 map fn (Id a) = Id (fn a)
libs/base/Control/Monad/RWS.idr+4−4
@@ -11,10 +11,10 @@ import Control.Monad.Reader
1111class (Monoid w, MonadReader r m, MonadWriter w m, MonadState s m) => MonadRWS r w s (m : Type -> Type) where {}
1212
1313||| The transformer on which the RWS monad is based
14−record RWST : Type -> Type -> Type -> (Type -> Type) -> Type -> Type where
15− MkRWST : {m : Type -> Type} ->
16− (runRWST : r -> s -> m (a, s, w)) -> RWST r w s m a
17−
14+record RWST (r : Type) (w : Type) (s : Type) (m : Type -> Type) (a : Type) where
15+ constructor MkRWST
16+ runRWST : r -> s -> m (a, s, w)
17+
1818instance Monad m => Functor (RWST r w s m) where
1919 map f (MkRWST m) = MkRWST $ \r,s => do (a, s', w) <- m r s
2020 return (f a, s', w)
libs/base/Control/Monad/Reader.idr+3−3
@@ -14,9 +14,9 @@ class Monad m => MonadReader r (m : Type -> Type) where
1414 local : (r -> r) -> m a -> m a
1515
1616||| The transformer on which the Reader monad is based
17−record ReaderT : Type -> (Type -> Type) -> Type -> Type where
18− RD : {m : Type -> Type} ->
19− (runReaderT : r -> m a) -> ReaderT r m a
17+record ReaderT (r : Type) (m : Type -> Type) (a : Type) where
18+ constructor RD
19+ runReaderT : r -> m a
2020
2121||| Create a ReaderT with an empty context
2222liftReaderT : {m : Type -> Type} -> m a -> ReaderT r m a
libs/base/Control/Monad/State.idr+5−5
@@ -13,9 +13,9 @@ class Monad m => MonadState s (m : Type -> Type) | m where
1313 put : s -> m ()
1414
1515||| The transformer on which the State monad is based
16−record StateT : Type -> (Type -> Type) -> Type -> Type where
17− ST : {m : Type -> Type} ->
18− (runStateT : s -> m (a, s)) -> StateT s m a
16+record StateT (s : Type) (m : Type -> Type) (a : Type) where
17+ constructor ST
18+ runStateT : s -> m (a, s)
1919
2020instance Functor f => Functor (StateT s f) where
2121 map f (ST g) = ST (\st => map (mapFst f) (g st)) where
@@ -57,8 +57,8 @@ State : Type -> Type -> Type
5757State s a = StateT s Identity a
5858
5959||| Unwrap a State monad computation.
60−runState : State s a -> s -> (a,s)
61−runState m = runIdentity . runStateT m
60+runState : StateT s Identity a -> s -> (a, s)
61+runState act = runIdentity . runStateT act
6262
6363||| Unwrap a State monad computation, but discard the final state.
6464evalState : State s a -> s -> a
libs/base/Control/Monad/Writer.idr+3−3
@@ -16,9 +16,9 @@ class (Monoid w, Monad m) => MonadWriter w (m : Type -> Type) where
1616 pass : m (a, w -> w) -> m a
1717
1818||| The transformer base of the Writer monad
19−record WriterT : Type -> (Type -> Type) -> Type -> Type where
20− WR : {m : Type -> Type} ->
21− (runWriterT : m (a, w)) -> WriterT w m a
19+record WriterT (w : Type) (m : Type -> Type) (a : Type) where
20+ constructor WR
21+ runWriterT : m (a, w)
2222
2323instance Functor f => Functor (WriterT w f) where
2424 map f (WR g) = WR $ map (\w => (f . fst $ w, snd w)) g
libs/contrib/Network/Cgi.idr+8−7
@@ -8,13 +8,14 @@ public
88Vars : Type
99Vars = List (String, String)
1010
11−record CGIInfo : Type where
12− CGISt : (GET : Vars) ->
13− (POST : Vars) ->
14− (Cookies : Vars) ->
15− (UserAgent : String) ->
16− (Headers : String) ->
17− (Output : String) -> CGIInfo
11+record CGIInfo where
12+ constructor CGISt
13+ GET : Vars
14+ POST : Vars
15+ Cookies : Vars
16+ UserAgent : String
17+ Headers : String
18+ Output : String
1819
1920add_Headers : String -> CGIInfo -> CGIInfo
2021add_Headers str st = record { Headers = Headers st ++ str } st
libs/contrib/Network/Socket.idr+17−19
@@ -107,19 +107,17 @@ EAGAIN : Int
107107EAGAIN = 11
108108
109109-- TODO: Expand to non-string payloads
110−record UDPRecvData : Type where
111− MkUDPRecvData :
112− (remote_addr : SocketAddress) ->
113− (remote_port : Port) ->
114− (recv_data : String) ->
115− (data_len : Int) ->
116− UDPRecvData
117−
118−record UDPAddrInfo : Type where
119− MkUDPAddrInfo :
120− (remote_addr : SocketAddress) ->
121− (remote_port : Port) ->
122− UDPAddrInfo
110+record UDPRecvData where
111+ constructor MkUDPRecvData
112+ remote_addr : SocketAddress
113+ remote_port : Port
114+ recv_data : String
115+ data_len : Int
116+
117+record UDPAddrInfo where
118+ constructor MkUDPAddrInfo
119+ remote_addr : SocketAddress
120+ remote_port : Port
123121
124122||| Frees a given pointer
125123public
@@ -138,12 +136,12 @@ sock_alloc : ByteLength -> IO BufPtr
138136sock_alloc bl = map BPtr $ foreign FFI_C "idrnet_malloc" (Int -> IO Ptr) bl
139137
140138||| The metadata about a socket
141−record Socket : Type where
142− MkSocket : (descriptor : SocketDescriptor) ->
143− (family : SocketFamily) ->
144− (socketType : SocketType) ->
145− (protocolNumber : ProtocolNumber) ->
146− Socket
139+record Socket where
140+ constructor MkSocket
141+ descriptor : SocketDescriptor
142+ family : SocketFamily
143+ socketType : SocketType
144+ protocalNumber : ProtocolNumber
147145
148146||| Get the C error number
149147getErrno : IO Int
libs/prelude/IO.idr+5−4
@@ -20,10 +20,11 @@ world (TheWorld w) = w
2020abstract WorldRes : Type -> Type
2121WorldRes x = x
2222
23−record FFI : Type where
24− MkFFI : (ffi_types : Type -> Type) ->
25− (ffi_fn : Type) ->
26− (ffi_data : Type) -> FFI
23+record FFI where
24+ constructor MkFFI
25+ ffi_types : Type -> Type
26+ ffi_fn : Type
27+ ffi_data : Type
2728
2829abstract
2930data IO' : (lang : FFI) -> Type -> Type where
libs/prelude/Prelude/Nat.idr+7−5
@@ -214,13 +214,15 @@ instance Cast Integer Nat where
214214 cast = fromInteger
215215
216216||| A wrapper for Nat that specifies the semigroup and monad instances that use (+)
217−record Multiplicative : Type where
218− getMultiplicative : Nat -> Multiplicative
217+record Multiplicative where
218+ constructor getMultiplicative
219+ _ : Nat
219220
220221||| A wrapper for Nat that specifies the semigroup and monad instances that use (*)
221−record Additive : Type where
222− getAdditive : Nat -> Additive
223−
222+record Additive where
223+ constructor getAdditive
224+ _ : Nat
225+
224226instance Semigroup Multiplicative where
225227 (<+>) left right = getMultiplicative $ left' * right'
226228 where
src/Idris/AbsSyntax.hs+2−7
@@ -1093,13 +1093,8 @@ expandParamsD rhs ist dec ps ns (PData doc argDocs syn fc co pd)
10931093 else PDatadecl n (expandParams dec ps ns [] ty) (map econ cons)
10941094 econ (doc, argDocs, n, t, fc, fs)
10951095 = (doc, argDocs, dec n, piBindp expl ps (expandParams dec ps ns [] t), fc, fs)
1096−expandParamsD rhs ist dec ps ns (PRecord doc syn fc tn tty opts cdoc cn cty)
1097− = if tn `elem` ns
1098− then PRecord doc syn fc (dec tn) (piBind ps (expandParams dec ps ns [] tty))
1099− opts cdoc (dec cn) conty
1100− else PRecord doc syn fc (dec tn) (expandParams dec ps ns [] tty)
1101− opts cdoc (dec cn) conty
1102− where conty = piBindp expl ps (expandParams dec ps ns [] cty)
1096+expandParamsD rhs ist dec ps ns d@(PRecord doc rsyn fc opts name prs pdocs fls cn cdoc csyn)
1097+ = d
11031098expandParamsD rhs ist dec ps ns (PParams f params pds)
11041099 = PParams f (ps ++ map (mapsnd (expandParams dec ps ns [])) params)
11051100 (map (expandParamsD True ist dec ps ns) pds)
src/Idris/AbsSyntaxTree.hs+15−7
@@ -36,7 +36,7 @@ import qualified Data.Text as T
3636import Data.Either
3737import qualified Data.Set as S
3838import Data.Word (Word)
39−import Data.Maybe (fromMaybe, mapMaybe)
39+import Data.Maybe (fromMaybe, mapMaybe, maybeToList)
4040import Data.Traversable (Traversable)
4141import Data.Typeable
4242import Data.Foldable (Foldable)
@@ -582,7 +582,6 @@ dictionary :: FnOpts -> Bool
582582dictionary = elem Dictionary
583583
584584
585−
586585-- | Type provider - what to provide
587586data ProvideWhat' t = ProvTerm t t -- ^ the first is the goal type, the second is the term
588587 | ProvPostulate t -- ^ goal type must be Type, so only term
@@ -602,7 +601,15 @@ data PDecl' t
602601 | PData (Docstring (Either Err PTerm)) [(Name, Docstring (Either Err PTerm))] SyntaxInfo FC DataOpts (PData' t) -- ^ Data declaration.
603602 | PParams FC [(Name, t)] [PDecl' t] -- ^ Params block
604603 | PNamespace String [PDecl' t] -- ^ New namespace
605− | PRecord (Docstring (Either Err PTerm)) SyntaxInfo FC Name t DataOpts (Docstring (Either Err PTerm)) Name t -- ^ Record declaration
604+ | PRecord (Docstring (Either Err PTerm)) SyntaxInfo FC DataOpts
605+ Name -- Record name
606+ [(Name, Plicity, t)] -- Parameters
607+ [(Name, Docstring (Either Err PTerm))] -- Param Docs
608+ [((Maybe Name), Plicity, t, Maybe (Docstring (Either Err PTerm)))] -- Fields
609+ (Maybe Name) -- Optional constructor name
610+ (Docstring (Either Err PTerm)) -- Constructor doc
611+ SyntaxInfo -- Constructor SyntaxInfo
612+ -- ^ Record declaration
606613 | PClass (Docstring (Either Err PTerm)) SyntaxInfo FC
607614 [(Name, t)] -- constraints
608615 Name
@@ -725,13 +732,14 @@ declared (PData _ _ _ _ _ (PDatadecl n _ ts)) = n : map fstt ts
725732declared (PData _ _ _ _ _ (PLaterdecl n _)) = [n]
726733declared (PParams _ _ ds) = concatMap declared ds
727734declared (PNamespace _ ds) = concatMap declared ds
728−declared (PRecord _ _ _ n _ _ _ c _) = [n, c]
735+declared (PRecord _ _ _ _ n _ _ _ cn _ _) = n : maybeToList cn
729736declared (PClass _ _ _ _ n _ _ _ ms) = n : concatMap declared ms
730737declared (PInstance _ _ _ _ _ _ _ _ _ _) = []
731738declared (PDSL n _) = [n]
732739declared (PSyntax _ _) = []
733740declared (PMutual _ ds) = concatMap declared ds
734741declared (PDirective _) = []
742+declared _ = []
735743
736744-- get the names declared, not counting nested parameter blocks
737745tldeclared :: PDecl -> [Name]
@@ -739,7 +747,7 @@ tldeclared (PFix _ _ _) = []
739747tldeclared (PTy _ _ _ _ _ n t) = [n]
740748tldeclared (PPostulate _ _ _ _ _ n t) = [n]
741749tldeclared (PClauses _ _ n _) = [] -- not a declaration
742−tldeclared (PRecord _ _ _ n _ _ _ c _) = [n, c]
750+tldeclared (PRecord _ _ _ _ n _ _ _ cn _ _) = n : maybeToList cn
743751tldeclared (PData _ _ _ _ _ (PDatadecl n _ ts)) = n : map fstt ts
744752 where fstt (_, _, a, _, _, _) = a
745753tldeclared (PParams _ _ ds) = []
@@ -760,14 +768,14 @@ defined (PData _ _ _ _ _ (PDatadecl n _ ts)) = n : map fstt ts
760768defined (PData _ _ _ _ _ (PLaterdecl n _)) = []
761769defined (PParams _ _ ds) = concatMap defined ds
762770defined (PNamespace _ ds) = concatMap defined ds
763−defined (PRecord _ _ _ n _ _ _ c _) = [n, c]
771+defined (PRecord _ _ _ _ n _ _ _ cn _ _) = n : maybeToList cn
764772defined (PClass _ _ _ _ n _ _ _ ms) = n : concatMap defined ms
765773defined (PInstance _ _ _ _ _ _ _ _ _ _) = []
766774defined (PDSL n _) = [n]
767775defined (PSyntax _ _) = []
768776defined (PMutual _ ds) = concatMap defined ds
769777defined (PDirective _) = []
770−--defined _ = []
778+defined _ = []
771779
772780updateN :: [(Name, Name)] -> Name -> Name
773781updateN ns n | Just n' <- lookup n ns = n'
src/Idris/DeepSeq.hs+2−2
@@ -145,11 +145,11 @@ instance (NFData t) => NFData (PDecl' t) where
145145 rnf x3 `seq` rnf x4 `seq` rnf x5 `seq` rnf x6 `seq` ()
146146 rnf (PParams x1 x2 x3) = rnf x1 `seq` rnf x2 `seq` rnf x3 `seq` ()
147147 rnf (PNamespace x1 x2) = rnf x1 `seq` rnf x2 `seq` ()
148− rnf (PRecord x1 x2 x3 x4 x5 x6 x7 x8 x9)
148+ rnf (PRecord x1 x2 x3 x4 x5 x6 x7 x8 x9 x10 x11)
149149 = rnf x1 `seq`
150150 rnf x2 `seq`
151151 rnf x3 `seq`
152− rnf x4 `seq` rnf x5 `seq` rnf x6 `seq` rnf x7 `seq` rnf x8 `seq` rnf x9 `seq` ()
152+ rnf x4 `seq` rnf x5 `seq` rnf x6 `seq` rnf x7 `seq` rnf x8 `seq` rnf x9 `seq` rnf x10 `seq` rnf x11 `seq` ()
153153 rnf (PClass x1 x2 x3 x4 x5 x6 x8 x7 x9)
154154 = rnf x1 `seq`
155155 rnf x2 `seq`
src/Idris/Elab/Record.hs+414−211
@@ -1,9 +1,8 @@
1−{-# LANGUAGE PatternGuards #-}
1+{-# LANGUAGE PatternGuards, ViewPatterns #-}
22module Idris.Elab.Record(elabRecord) where
33
44import Idris.AbsSyntax
5−import Idris.ASTUtils
6−import Idris.DSL
5+import Idris.Docstrings
76import Idris.Error
87import Idris.Delaborate
98import Idris.Imports
@@ -18,225 +17,429 @@ import Idris.DeepSeq
1817import Idris.Output (iputStrLn, pshow, iWarn)
1918import IRTS.Lang
2019
20+import Idris.ParseExpr (tryFullExpr)
21+
2122import Idris.Elab.Type
2223import Idris.Elab.Data
2324import Idris.Elab.Utils
2425
2526import Idris.Core.TT
26−import Idris.Core.Elaborate hiding (Tactic(..))
2727import Idris.Core.Evaluate
28−import Idris.Core.Execute
29−import Idris.Core.Typecheck
30−import Idris.Core.CaseTree
31−
32−import Idris.Docstrings
3328
34−import Prelude hiding (id, (.))
35−import Control.Category
29+import Idris.Elab.Data
3630
37−import Control.Applicative hiding (Const)
38−import Control.DeepSeq
39−import Control.Monad
40−import Control.Monad.State.Strict as State
41−import Data.List
4231import Data.Maybe
43−import Debug.Trace
44−
45−import qualified Data.Map as Map
46−import qualified Data.Set as S
47−import qualified Data.Text as T
48−import Data.Char(isLetter, toLower)
49−import Data.List.Split (splitOn)
50−
51−import Util.Pretty(pretty, text)
52−
53−elabRecord :: ElabInfo -> SyntaxInfo -> Docstring (Either Err PTerm) -> FC -> Name ->
54− PTerm -> DataOpts -> Docstring (Either Err PTerm) -> Name -> PTerm -> Idris ()
55−elabRecord info syn doc fc tyn ty opts cdoc cn cty_in
56− = do elabData info syn doc [] fc opts (PDatadecl tyn ty [(cdoc, [], cn, cty_in, fc, [])])
57− -- TODO think: something more in info?
58− cty' <- implicit info syn cn cty_in
59− i <- getIState
60−
61− -- get bound implicits and propagate to setters (in case they
62− -- provide useful information for inference)
63− let extraImpls = getBoundImpls cty'
64−
65− cty <- case lookupTy cn (tt_ctxt i) of
66− [t] -> return (delab i t)
67− _ -> ifail "Something went inexplicably wrong"
68− cimp <- case lookupCtxt cn (idris_implicits i) of
69− [imps] -> return imps
70− ppos <- case lookupCtxt tyn (idris_datatypes i) of
71− [ti] -> return $ param_pos ti
72− let cty_imp = renameBs cimp cty
73− let ptys = getProjs [] cty_imp
74− let ptys_u = getProjs [] cty
75− let recty = getRecTy cty_imp
76− let recty_u = getRecTy cty
77−
78− let paramNames = getPNames recty ppos
79−
80− -- rename indices when we generate the getter/setter types, so
81− -- that they don't clash with the names of the projections
82− -- we're generating
83− let index_names_in = getRecNameMap "_in" ppos recty
84− let recty_in = substMatches index_names_in recty
85−
86− logLvl 3 $ show (recty, recty_u, ppos, paramNames, ptys)
87− -- Substitute indices with projection functions, and parameters with
88− -- the updated parameter name
89− let substs = map (\ (n, _) ->
90− if n `elem` paramNames
91− then (n, PRef fc (mkp n))
92− else (n, PApp fc (PRef fc n)
93− [pexp (PRef fc rec)]))
94− ptys
95−
96− -- Generate projection functions
97− proj_decls <- mapM (mkProj recty_in substs cimp) (zip ptys [0..])
98− logLvl 3 $ show proj_decls
99− let nonImp = mapMaybe isNonImp (zip cimp ptys_u)
100− let implBinds = getImplB id cty'
101−
102− -- Generate update functions
103− update_decls <- mapM (mkUpdate recty_u index_names_in extraImpls
104− (getFieldNames cty')
105− implBinds (length nonImp)) (zip nonImp [0..])
106− mapM_ (rec_elabDecl info EAll info) (concat proj_decls)
107− logLvl 3 $ show update_decls
108− mapM_ (tryElabDecl info) (update_decls)
109− where
110−-- syn = syn_in { syn_namespace = show (nsroot tyn) : syn_namespace syn_in }
32+import Data.List
33+import Control.Monad
11134
112− isNonImp (PExp _ _ _ _, a) = Just a
113− isNonImp _ = Nothing
35+-- | Elaborate a record declaration
36+elabRecord :: ElabInfo
37+ -> (Docstring (Either Err PTerm)) -- ^ The documentation for the whole declaration
38+ -> SyntaxInfo -> FC -> DataOpts
39+ -> Name -- ^ The name of the type being defined
40+ -> [(Name, Plicity, PTerm)] -- ^ Parameters
41+ -> [(Name, Docstring (Either Err PTerm))] -- ^ Parameter Docs
42+ -> [((Maybe Name), Plicity, PTerm, Maybe (Docstring (Either Err PTerm)))] -- ^ Fields
43+ -> Maybe Name -- ^ Constructor Name
44+ -> (Docstring (Either Err PTerm)) -- ^ Constructor Doc
45+ -> SyntaxInfo -- ^ Constructor SyntaxInfo
46+ -> Idris ()
47+elabRecord info doc rsyn fc opts tyn params paramDocs fields cname cdoc csyn
48+ = do logLvl 1 $ "Building data declaration for " ++ show tyn
49+ -- Type constructor
50+ let tycon = generateTyConType params
51+ logLvl 1 $ "Type constructor " ++ showTmImpls tycon
52+
53+ -- Data constructor
54+ dconName <- generateDConName cname
55+ let dconTy = generateDConType params fieldsWithNameAndDoc
56+ logLvl 1 $ "Data constructor: " ++ showTmImpls dconTy
57+
58+ -- Build data declaration for elaboration
59+ iLOG $ foldr (++) "" $ intersperse "\n" (map show dconsArgDocs)
60+ let datadecl = PDatadecl tyn tycon [(cdoc, dconsArgDocs, dconName, dconTy, fc, [])]
61+ elabData info rsyn doc paramDocs fc opts datadecl
62+
63+ iLOG $ "fieldsWithName " ++ show fieldsWithName
64+ iLOG $ "fieldsWIthNameAndDoc " ++ show fieldsWithNameAndDoc
65+ elabRecordFunctions info rsyn fc tyn paramsAndDoc fieldsWithNameAndDoc dconName target
66+ where
67+ -- | Generates a type constructor.
68+ generateTyConType :: [(Name, Plicity, PTerm)] -> PTerm
69+ generateTyConType ((n, p, t) : rest) = PPi p (nsroot n) t (generateTyConType rest)
70+ generateTyConType [] = PType
71+
72+ -- | Generates a name for the data constructor if none was specified.
73+ generateDConName :: Maybe Name -> Idris Name
74+ generateDConName (Just n) = return $ expandNS csyn n
75+ generateDConName Nothing = uniqueName (expandNS csyn $ sMN 0 ("Mk" ++ (show (nsroot tyn))))
76+ where
77+ uniqueName :: Name -> Idris Name
78+ uniqueName n = do i <- getIState
79+ case lookupTyNameExact n (tt_ctxt i) of
80+ Just _ -> uniqueName (nextName n)
81+ Nothing -> return n
82+
83+ -- | Generates the data constructor type.
84+ generateDConType :: [(Name, Plicity, PTerm)] -> [(Name, Plicity, PTerm, a)] -> PTerm
85+ generateDConType ((n, _, t) : ps) as = PPi impl (nsroot n) t (generateDConType ps as)
86+ generateDConType [] ((n, p, t, _) : as) = PPi p (nsroot n) t (generateDConType [] as)
87+ generateDConType [] [] = target
88+
89+ -- | The target for the constructor and projection functions. Also the source of the update functions.
90+ target :: PTerm
91+ target = PApp fc (PRef fc tyn) $ map (uncurry asPRefArg) [(p, n) | (n, p, _) <- params]
92+
93+ paramsAndDoc :: [(Name, Plicity, PTerm, Docstring (Either Err PTerm))]
94+ paramsAndDoc = pad params paramDocs
95+ where
96+ pad :: [(Name, Plicity, PTerm)] -> [(Name, Docstring (Either Err PTerm))] -> [(Name, Plicity, PTerm, Docstring (Either Err PTerm))]
97+ pad ((n, p, t) : rest) docs
98+ = let d = case lookup n docs of
99+ Just d' -> d
100+ Nothing -> emptyDocstring
101+ in (n, p, t, d) : (pad rest docs)
102+ pad _ _ = []
103+
104+ dconsArgDocs :: [(Name, Docstring (Either Err PTerm))]
105+ dconsArgDocs = paramDocs ++ (dcad fieldsWithName)
106+ where
107+ dcad :: [(Name, Plicity, PTerm, Maybe (Docstring (Either Err PTerm)))] -> [(Name, Docstring (Either Err PTerm))]
108+ dcad ((n, _, _, (Just d)) : rest) = ((nsroot n), d) : (dcad rest)
109+ dcad (_ : rest) = dcad rest
110+ dcad [] = []
114111
115− getPNames (PApp _ _ as) ppos = getpn as ppos
112+ fieldsWithName :: [(Name, Plicity, PTerm, Maybe (Docstring (Either Err PTerm)))]
113+ fieldsWithName = fwn [] fields
114+ where
115+ fwn :: [Name] -> [(Maybe Name, Plicity, PTerm, Maybe (Docstring (Either Err PTerm)))] -> [(Name, Plicity, PTerm, Maybe (Docstring (Either Err PTerm)))]
116+ fwn ns ((n, p, t, d) : rest)
117+ = let nn = case n of
118+ Just n' -> n'
119+ Nothing -> newName ns baseName
120+ in (expandNS rsyn $ nn, p, t, d) : (fwn (nn : ns) rest)
121+ fwn _ _ = []
122+
123+ baseName = sUN "__pi_arg"
124+
125+ newName :: [Name] -> Name -> Name
126+ newName ns n
127+ | n `elem` ns = newName ns (nextName n)
128+ | otherwise = n
129+
130+ fieldsWithNameAndDoc :: [(Name, Plicity, PTerm, Docstring (Either Err PTerm))]
131+ fieldsWithNameAndDoc = fwnad fieldsWithName
132+ where
133+ fwnad :: [(Name, Plicity, PTerm, Maybe (Docstring (Either Err PTerm)))] -> [(Name, Plicity, PTerm, Docstring (Either Err PTerm))]
134+ fwnad ((n, p, t, d) : rest)
135+ = let doc = fromMaybe emptyDocstring d
136+ in (n, p, t, doc) : (fwnad rest)
137+ fwnad [] = []
138+
139+elabRecordFunctions :: ElabInfo -> SyntaxInfo -> FC
140+ -> Name -- ^ Record type name
141+ -> [(Name, Plicity, PTerm, Docstring (Either Err PTerm))] -- ^ Parameters
142+ -> [(Name, Plicity, PTerm, Docstring (Either Err PTerm))] -- ^ Fields
143+ -> Name -- ^ Constructor Name
144+ -> PTerm -- ^ Target type
145+ -> Idris ()
146+elabRecordFunctions info rsyn fc tyn params fields dconName target
147+ = do logLvl 1 $ "Elaborating helper functions for record " ++ show tyn
148+
149+ iLOG $ "Fields: " ++ show fieldNames
150+ iLOG $ "Params: " ++ show paramNames
151+ -- The elaborated constructor type for the data declaration
152+ i <- getIState
153+ ttConsTy <-
154+ case lookupTyExact dconName (tt_ctxt i) of
155+ Just as -> return as
156+ Nothing -> tclift $ tfail $ At fc (Elaborating "record " tyn (InternalMsg "It seems like the constructor for this record has disappeared. :( \n This is a bug. Please report."))
157+
158+ -- The arguments to the constructor
159+ let constructorArgs = getArgTys ttConsTy
160+ iLOG $ "Cons args: " ++ show constructorArgs
161+ iLOG $ "Free fields: " ++ show (filter (not . isFieldOrParam') constructorArgs)
162+ -- If elaborating the constructor has resulted in some new implicit fields we make projection functions for them.
163+ let freeFieldsForElab = map (freeField i) (filter (not . isFieldOrParam') constructorArgs)
164+
165+ -- The parameters for elaboration with their documentation
166+ -- Parameter functions are all prefixed with "param_".
167+ let paramsForElab = [((nsroot n), (paramName n), impl, t, d) | (n, _, t, d) <- params] -- zipParams i params paramDocs]
168+
169+ -- The fields (written by the user) with their documentation.
170+ let userFieldsForElab = [((nsroot n), n, p, t, d) | (n, p, t, d) <- fields]
171+
172+ -- All things we need to elaborate projection functions for, together with a number denoting their position in the constructor.
173+ let projectors = [(n, n', p, t, d, i) | ((n, n', p, t, d), i) <- zip (freeFieldsForElab ++ paramsForElab ++ userFieldsForElab) [0..]]
174+ -- Build and elaborate projection functions
175+ elabProj dconName projectors
176+
177+ logLvl 1 $ "Dependencies: " ++ show fieldDependencies
178+
179+ logLvl 1 $ "Depended on: " ++ show dependedOn
180+
181+ -- All things we need to elaborate update functions for, together with a number denoting their position in the constructor.
182+ let updaters = [(n, n', p, t, d, i) | ((n, n', p, t, d), i) <- zip (paramsForElab ++ userFieldsForElab) [0..]]
183+ -- Build and elaborate update functions
184+ elabUp dconName updaters
185+ where
186+ -- | Creates a PArg from a plicity and a name where the term is a Placeholder.
187+ placeholderArg :: Plicity -> Name -> PArg
188+ placeholderArg p n = asArg p (nsroot n) Placeholder
189+
190+ -- | Root names of all fields in the current record declarations
191+ fieldNames :: [Name]
192+ fieldNames = [nsroot n | (n, _, _, _) <- fields]
193+
194+ paramNames :: [Name]
195+ paramNames = [nsroot n | (n, _, _, _) <- params]
196+
197+ isFieldOrParam :: Name -> Bool
198+ isFieldOrParam n = n `elem` (fieldNames ++ paramNames)
199+
200+ isFieldOrParam' :: (Name, a) -> Bool
201+ isFieldOrParam' = isFieldOrParam . fst
202+
203+ isField :: Name -> Bool
204+ isField = flip elem fieldNames
205+
206+ isField' :: (Name, a, b, c, d, f) -> Bool
207+ isField' (n, _, _, _, _, _) = isField n
208+
209+ fieldTerms :: [PTerm]
210+ fieldTerms = [t | (_, _, t, _) <- fields]
211+
212+ -- Delabs the TT to PTerm
213+ -- This is not good.
214+ -- However, for machine generated implicits, there seems to be no PTerm available.
215+ -- Is there a better way to do this without building the setters and getters as TT?
216+ freeField :: IState -> (Name, TT Name) -> (Name, Name, Plicity, PTerm, Docstring (Either Err PTerm))
217+ freeField i arg = let nameInCons = fst arg -- The name as it appears in the constructor
218+ nameFree = expandNS rsyn (freeName $ fst arg) -- The name prefixed with "free_"
219+ plicity = impl -- All free fields are implicit as they are machine generated
220+ fieldType = delab i (snd arg) -- The type of the field
221+ doc = emptyDocstring -- No docmentation for machine generated fields
222+ in (nameInCons, nameFree, plicity, fieldType, doc)
223+
224+ freeName :: Name -> Name
225+ freeName (UN n) = sUN ("free_" ++ str n)
226+ freeName (MN i n) = sMN i ("free_" ++ str n)
227+ freeName (NS n s) = NS (freeName n) s
228+ freeName n = n
229+
230+ -- | Zips together parameters with their documentation. If no documentation for a given field exists, an empty docstring is used.
231+ zipParams :: IState -> [(Name, Plicity, PTerm)] -> [(Name, Docstring (Either Err PTerm))] -> [(Name, PTerm, Docstring (Either Err PTerm))]
232+ zipParams i ((n, _, t) : rest) ((_, d) : rest') = (n, t, d) : (zipParams i rest rest')
233+ zipParams i ((n, _, t) : rest) [] = (n, t, emptyDoc) : (zipParams i rest [])
234+ where emptyDoc = annotCode (tryFullExpr rsyn i) emptyDocstring
235+ zipParams _ [] [] = []
236+
237+ paramName :: Name -> Name
238+ paramName (UN n) = sUN ("param_" ++ str n)
239+ paramName (MN i n) = sMN i ("param_" ++ str n)
240+ paramName (NS n s) = NS (paramName n) s
241+ paramName n = n
242+
243+ -- | Elaborate the projection functions.
244+ elabProj :: Name -> [(Name, Name, Plicity, PTerm, Docstring (Either Err PTerm), Int)] -> Idris ()
245+ elabProj cn fs = let phArgs = map (uncurry placeholderArg) [(p, n) | (n, _, p, _, _, _) <- fs]
246+ elab = \(n, n', p, t, doc, i) ->
247+ -- Use projections in types
248+ do let t' = projectInType [(m, m') | (m, m', _, _, _, _) <- fs
249+ -- Parameters are already in scope, so just use them
250+ , not (m `elem` paramNames)] t
251+ elabProjection info n n' p t' doc rsyn fc target cn phArgs fieldNames i
252+ in mapM_ elab fs
253+
254+ -- | Elaborate the update functions.
255+ elabUp :: Name -> [(Name, Name, Plicity, PTerm, Docstring (Either Err PTerm), Int)] -> Idris ()
256+ elabUp cn fs = let args = map (uncurry asPRefArg) [(p, n) | (n, _, p, _, _, _) <- fs]
257+ elab = \(n, n', p, t, doc, i) -> elabUpdate info n n' p t doc rsyn fc target cn args fieldNames i (optionalSetter n)
258+ in mapM_ elab fs
259+
260+ -- | Decides whether a setter should be generated for a field or not.
261+ optionalSetter :: Name -> Bool
262+ optionalSetter n = n `elem` dependedOn
263+
264+ -- | A map from a field name to the other fields it depends on.
265+ fieldDependencies :: [(Name, [Name])]
266+ fieldDependencies = map (uncurry fieldDep) [(n, t) | (n, _, t, _) <- fields ++ params]
267+ where
268+ fieldDep :: Name -> PTerm -> (Name, [Name])
269+ fieldDep n t = ((nsroot n), paramNames ++ fieldNames `intersect` allNamesIn t)
270+
271+ -- | A list of fields depending on another field.
272+ dependentFields :: [Name]
273+ dependentFields = filter depends fieldNames
274+ where
275+ depends :: Name -> Bool
276+ depends n = case lookup n fieldDependencies of
277+ Just xs -> not $ null xs
278+ Nothing -> False
279+
280+ -- | A list of fields depended on by other fields.
281+ dependedOn :: [Name]
282+ dependedOn = concat ((catMaybes (map (\x -> lookup x fieldDependencies) fieldNames)))
283+
284+-- | Creates and elaborates a projection function.
285+elabProjection :: ElabInfo
286+ -> Name -- ^ Name of the argument in the constructor
287+ -> Name -- ^ Projection Name
288+ -> Plicity -- ^ Projection Plicity
289+ -> PTerm -- ^ Projection Type
290+ -> (Docstring (Either Err PTerm)) -- ^ Projection Documentation
291+ -> SyntaxInfo -- ^ Projection SyntaxInfo
292+ -> FC -> PTerm -- ^ Projection target type
293+ -> Name -- ^ Data constructor tame
294+ -> [PArg] -- ^ Placeholder Arguments to constructor
295+ -> [Name] -- ^ All Field Names
296+ -> Int -- ^ Argument Index
297+ -> Idris ()
298+elabProjection info cname pname plicity projTy pdoc psyn fc targetTy cn phArgs fnames index
299+ = do logLvl 1 $ "Generating Projection for " ++ show pname
300+
301+ let ty = generateTy
302+ logLvl 1 $ "Type of " ++ show pname ++ ": " ++ show ty
303+
304+ let lhs = generateLhs
305+ logLvl 1 $ "LHS of " ++ show pname ++ ": " ++ showTmImpls lhs
306+ let rhs = generateRhs
307+ logLvl 1 $ "RHS of " ++ show pname ++ ": " ++ showTmImpls rhs
308+
309+ rec_elabDecl info EAll info ty
310+
311+ let clause = PClause fc pname lhs [] rhs []
312+ rec_elabDecl info EAll info $ PClauses fc [] pname [clause]
313+ where
314+ -- | The type of the projection function.
315+ generateTy :: PDecl
316+ generateTy = PTy pdoc [] psyn fc [] pname $ PPi expl recName targetTy projTy
317+
318+ -- | The left hand side of the projection function.
319+ generateLhs :: PTerm
320+ generateLhs = let args = lhsArgs index phArgs
321+ in PApp fc (PRef fc pname) [pexp (PApp fc (PRef fc cn) args)]
116322 where
117− getpn as [] = []
118− getpn as (i:is) | length as > i,
119− PRef _ n <- getTm (as!!i) = n : getpn as is
120− | otherwise = getpn as is
121− getPNames _ _ = []
122−
123− tryElabDecl info (fn, ty, val)
124− = do i <- getIState
125− idrisCatch (do rec_elabDecl info EAll info ty
126− rec_elabDecl info EAll info val)
127− (\v -> do iputStrLn $ show fc ++
128− ":Warning - can't generate setter for " ++
129− show fn ++ " (" ++ show ty ++ ")"
130−-- ++ "\n" ++ pshow i v
131− putIState i)
132−
133− getBoundImpls (PPi (Imp _ _ _ _) n ty sc) = (n, ty) : getBoundImpls sc
134− getBoundImpls _ = []
135−
136− getImplB k (PPi (Imp l s _ _) n Placeholder sc)
137− = getImplB k sc
138− getImplB k (PPi (Imp l s p fa) n ty sc)
139− = getImplB (\x -> k (PPi (Imp l s p fa) n ty x)) sc
140− getImplB k (PPi _ n ty sc)
141− = getImplB k sc
142− getImplB k _ = k
143−
144− renameBs (PImp _ _ _ _ _ : ps) (PPi p n ty s)
145− = PPi p (mkImp n) ty (renameBs ps (substMatch n (PRef fc (mkImp n)) s))
146− renameBs (_:ps) (PPi p n ty s) = PPi p n ty (renameBs ps s)
147− renameBs _ t = t
148−
149− getProjs acc (PPi _ n ty s) = getProjs ((n, ty) : acc) s
150− getProjs acc r = reverse acc
151−
152− getFieldNames (PPi (Exp _ _ _) n _ s) = n : getFieldNames s
153− getFieldNames (PPi _ _ _ s) = getFieldNames s
154− getFieldNames _ = []
155−
156− getRecTy (PPi _ n ty s) = getRecTy s
157− getRecTy t = t
158−
159− -- make sure we pick a consistent name for parameters; any name will do
160− -- otherwise
161− getRecNameMap x ppos (PApp fc t args)
162− = mapMaybe toMN (zip [0..] (map getTm args))
323+ lhsArgs :: Int -> [PArg] -> [PArg]
324+ lhsArgs 0 (_ : rest) = (asArg plicity (nsroot cname) (PRef fc pname_in)) : rest
325+ lhsArgs i (x : rest) = x : (lhsArgs (i-1) rest)
326+ lhsArgs _ [] = []
327+
328+ -- | The "_in" name. Used for the lhs.
329+ pname_in :: Name
330+ pname_in = rootname -- in_name rootname
331+
332+ rootname :: Name
333+ rootname = nsroot cname
334+
335+ -- | The right hand side of the projection function.
336+ generateRhs :: PTerm
337+ generateRhs = PRef fc pname_in
338+
339+-- | Creates and elaborates an update function.
340+-- If 'optional' is true, we will not fail if we can't elaborate the update function.
341+elabUpdate :: ElabInfo
342+ -> Name -- ^ Name of the argument in the constructor
343+ -> Name -- ^ Field Name
344+ -> Plicity -- ^ Field Plicity
345+ -> PTerm -- ^ Field Type
346+ -> (Docstring (Either Err PTerm)) -- ^ Field Documentation
347+ -> SyntaxInfo -- ^ Field SyntaxInfo
348+ -> FC -> PTerm -- ^ Projection Source Type
349+ -> Name -- ^ Data Constructor Name
350+ -> [PArg] -- ^ Arguments to constructor
351+ -> [Name] -- ^ All fields
352+ -> Int -- ^ Argument Index
353+ -> Bool -- ^ Optional
354+ -> Idris ()
355+elabUpdate info cname pname plicity pty pdoc psyn fc sty cn args fnames i optional
356+ = do logLvl 1 $ "Generating Update for " ++ show pname
357+
358+ let ty = generateTy
359+ logLvl 1 $ "Type of " ++ show set_pname ++ ": " ++ show ty
360+
361+ let lhs = generateLhs
362+ logLvl 1 $ "LHS of " ++ show set_pname ++ ": " ++ showTmImpls lhs
363+
364+ let rhs = generateRhs
365+ logLvl 1 $ "RHS of " ++ show set_pname ++ ": " ++ showTmImpls rhs
366+
367+ let clause = PClause fc set_pname lhs [] rhs []
368+
369+ idrisCatch (do rec_elabDecl info EAll info ty
370+ rec_elabDecl info EAll info $ PClauses fc [] set_pname [clause])
371+ (\err -> logLvl 1 $ "Could not generate update function for " ++ show pname)
372+ {-if optional
373+ then logLvl 1 $ "Could not generate update function for " ++ show pname
374+ else tclift $ tfail $ At fc (Elaborating "record update function " pname err)) -}
375+ where
376+ -- | The type of the udpate function.
377+ generateTy :: PDecl
378+ generateTy = PTy pdoc [] psyn fc [] set_pname $ PPi expl (nsroot pname) pty (PPi expl recName sty (substInput sty))
379+ where substInput = substMatches [(cname, PRef fc (nsroot pname))]
380+
381+ -- | The "_set" name.
382+ set_pname :: Name
383+ set_pname = set_name pname
384+
385+ set_name :: Name -> Name
386+ set_name (UN n) = sUN ("set_" ++ str n)
387+ set_name (MN i n) = sMN i ("set_" ++ str n)
388+ set_name (NS n s) = NS (set_name n) s
389+ set_name n = n
390+
391+ -- | The left-hand side of the update function.
392+ generateLhs :: PTerm
393+ generateLhs = PApp fc (PRef fc set_pname) [pexp $ PRef fc pname_in, pexp constructorPattern]
394+ where
395+ constructorPattern :: PTerm
396+ constructorPattern = PApp fc (PRef fc cn) args
397+
398+ -- | The "_in" name.
399+ pname_in :: Name
400+ pname_in = in_name rootname
401+
402+ rootname :: Name
403+ rootname = nsroot pname
404+
405+ -- | The right-hand side of the update function.
406+ generateRhs :: PTerm
407+ generateRhs = PApp fc (PRef fc cn) (newArgs i args)
163408 where
164− toMN (i, PRef fc n)
165− | i `elem` ppos = Just (n, PRef fc (mkp n))
166− | otherwise = Just (n, PRef fc (sMN 0 (show n ++ x)))
167− toMN _ = Nothing
168− getRecNameMap x _ _ = []
169−
170− rec = sMN 0 "rec"
171−
172− -- only UNs propagate properly as parameters (bit of a hack then...)
173− mkp (UN n) = sUN ("_p_" ++ str n)
174− mkp (MN i n) = sMN i ("p_" ++ str n)
175− mkp (NS n s) = NS (mkp n) s
176−
177− mkImp (UN n) = sUN ("implicit_" ++ str n)
178− mkImp (MN i n) = sMN i ("implicit_" ++ str n)
179− mkImp (NS n s) = NS (mkImp n) s
180−
181− mkType (UN n) = sUN ("set_" ++ str n)
182− mkType (MN i n) = sMN i ("set_" ++ str n)
183− mkType (NS n s) = NS (mkType n) s
184−
185− mkProj recty substs cimp ((pn_in, pty), pos)
186− = do let pn = expandNS syn pn_in -- projection name
187− -- use pn_in in the indices, consistently, to avoid clash
188− let pfnTy = PTy emptyDocstring [] defaultSyntax fc [] pn
189− (PPi expl rec recty
190− (substMatches substs pty))
191− let pls = repeat Placeholder
192− let before = pos
193− let after = length substs - (pos + 1)
194− let args = take before pls ++ PRef fc (mkp pn_in) : take after pls
195− let iargs = map implicitise (zip cimp args)
196− let lhs = PApp fc (PRef fc pn)
197− [pexp (PApp fc (PRef fc cn) iargs)]
198− let rhs = PRef fc (mkp pn_in)
199− let pclause = PClause fc pn lhs [] rhs []
200− return [pfnTy, PClauses fc [] pn [pclause]]
201−
202− implicitise (pa, t) = pa { getTm = t }
203−
204− -- If the 'pty' we're updating includes anything in 'substs', we're
205− -- updating the type as well, so use recty', otherwise just use
206− -- recty
207− mkUpdate recty inames extras fnames k num ((pn, pty), pos)
208− = do let setname = expandNS syn $ mkType pn
209− let valname = sMN 0 "updateval"
210− let pn_out = sMN 0 (show pn ++ "_out")
211− let pn_in = sMN 0 (show pn ++ "_in")
212− let recty_in = substMatches [(pn, PRef fc pn_in)] recty
213− let recty_out = substMatches [(pn, PRef fc pn_out)] recty
214− let pt = substMatches inames $
215− k (implBindUp extras inames (PPi expl pn_out pty
216− (PPi expl rec recty_in recty_out)))
217− let pfnTy = PTy emptyDocstring [] defaultSyntax fc [] setname pt
218−-- let pls = map (\x -> PRef fc (sMN x ("field" ++ show x))) [0..num-1]
219− let inames_imp = map (\ (x,_) -> (x, Placeholder)) inames
220− let pls = map (\x -> substMatches inames_imp (PRef fc x)) fnames
221− let lhsArgs = pls
222− let rhsArgs = take pos pls ++ (PRef fc valname) :
223− drop (pos + 1) pls
224− let before = pos
225− let pclause = PClause fc setname (PApp fc (PRef fc setname)
226− [pexp (PRef fc valname),
227− pexp (PApp fc (PRef fc cn)
228− (map pexp lhsArgs))])
229− []
230− (PApp fc (PRef fc cn)
231− (map pexp rhsArgs)) []
232− return (pn, pfnTy, PClauses fc [] setname [pclause])
233−
234− implBindUp [] is t = t
235− implBindUp ((n, ty):ns) is t
236− = let n' = case lookup n is of
237− Just (PRef _ x) -> x
238− _ -> n in
239− if n `elem` allNamesIn t
240− then PPi impl n' ty (implBindUp ns is t)
241− else implBindUp ns is t
409+ newArgs :: Int -> [PArg] -> [PArg]
410+ newArgs 0 (_ : rest) = (asArg plicity (nsroot cname) (PRef fc pname_in)) : rest
411+ newArgs i (x : rest) = x : (newArgs (i-1) rest)
412+ newArgs _ [] = []
413+
414+-- | Post-fixes a name with "_in".
415+in_name :: Name -> Name
416+in_name (UN n) = sMN 0 (str n ++ "_in")
417+in_name (MN i n) = sMN i (str n ++ "_in")
418+in_name (NS n s) = NS (in_name n) s
419+in_name n = n
420+
421+-- | Creates a PArg with a given plicity, name, and term.
422+asArg :: Plicity -> Name -> PTerm -> PArg
423+asArg (Imp os _ _ _) n t = PImp 0 False os n t
424+asArg (Exp os _ _) n t = PExp 0 os n t
425+asArg (Constraint os _) n t = PConstraint 0 os n t
426+asArg (TacImp os _ s) n t = PTacImplicit 0 os n s t
427+
428+-- | Machine name "rec".
429+recName :: Name
430+recName = sMN 0 "rec"
431+
432+recRef = PRef emptyFC recName
433+
434+projectInType :: [(Name, Name)] -> PTerm -> PTerm
435+projectInType xs = mapPT st
436+ where
437+ st :: PTerm -> PTerm
438+ st (PRef fc n)
439+ | Just pn <- lookup n xs = PApp fc (PRef fc pn) [pexp recRef]
440+ st t = t
441+
442+-- | Creates an PArg from a plicity and a name where the term is a PRef.
443+asPRefArg :: Plicity -> Name -> PArg
444+asPRefArg p n = asArg p (nsroot n) $ PRef emptyFC (nsroot n)
242445
src/Idris/ElabDecls.hs+6−4
@@ -238,14 +238,16 @@ elabDecl' what info (PClass doc s f cs n ps pdocs fds ds)
238238 elabClass info (s { syn_params = [] }) doc f cs n ps pdocs fds ds
239239elabDecl' what info (PInstance doc argDocs s f cs n ps t expn ds)
240240 = do iLOG $ "Elaborating instance " ++ show n
241− elabInstance info s doc argDocs what f cs n ps t expn ds
242−elabDecl' what info (PRecord doc s f tyn ty opts cdoc cn cty)
241+ elabInstance info s doc argDocs what f cs n ps t expn ds
242+elabDecl' what info (PRecord doc rsyn fc opts name ps pdocs fs cname cdoc csyn)
243243 | what /= ETypes
244− = do iLOG $ "Elaborating record " ++ show tyn
245− elabRecord info s doc f tyn ty opts cdoc cn cty
244+ = do iLOG $ "Elaborating record " ++ show name
245+ elabRecord info doc rsyn fc opts name ps pdocs fs cname cdoc csyn
246+{-
246247 | otherwise
247248 = do iLOG $ "Elaborating [type of] " ++ show tyn
248249 elabData info s doc [] f [] (PLaterdecl tyn ty)
250+-}
249251elabDecl' _ info (PDSL n dsl)
250252 = do i <- getIState
251253 putIState (i { idris_dsls = addDef n dsl (idris_dsls i) })
src/Idris/IBC.hs+6−2
@@ -1173,7 +1173,7 @@ instance (Binary t) => Binary (PDecl' t) where
11731173 PNamespace x1 x2 -> do putWord8 5
11741174 put x1
11751175 put x2
1176− PRecord x1 x2 x3 x4 x5 x6 x7 x8 x9 ->
1176+ PRecord x1 x2 x3 x4 x5 x6 x7 x8 x9 x10 x11 ->
11771177 do putWord8 6
11781178 put x1
11791179 put x2
@@ -1184,6 +1184,8 @@ instance (Binary t) => Binary (PDecl' t) where
11841184 put x7
11851185 put x8
11861186 put x9
1187+ put x10
1188+ put x11
11871189 PClass x1 x2 x3 x4 x5 x6 x7 x8 x9
11881190 -> do putWord8 7
11891191 put x1
@@ -1285,7 +1287,9 @@ instance (Binary t) => Binary (PDecl' t) where
12851287 x7 <- get
12861288 x8 <- get
12871289 x9 <- get
1288− return (PRecord x1 x2 x3 x4 x5 x6 x7 x8 x9)
1290+ x10 <- get
1291+ x11 <- get
1292+ return (PRecord x1 x2 x3 x4 x5 x6 x7 x8 x9 x10 x11)
12891293 7 -> do x1 <- get
12901294 x2 <- get
12911295 x3 <- get
src/Idris/ParseData.hs+83−16
@@ -42,31 +42,29 @@ Record ::=
4242 DocComment Accessibility? 'record' FnName TypeSig 'where' OpenBlock Constructor KeepTerminator CloseBlock;
4343-}
4444record :: SyntaxInfo -> IdrisParser PDecl
45−record syn = do (doc, argDocs, acc, opts) <- try (do
46− (doc, argDocs) <- option noDocs docComment
45+record syn = do (doc, paramDocs, acc, opts) <- try (do
46+ (doc, paramDocs) <- option noDocs docComment
4747 ist <- get
4848 let doc' = annotCode (tryFullExpr syn ist) doc
49− argDocs' = [ (n, annotCode (tryFullExpr syn ist) d)
50− | (n, d) <- argDocs ]
49+ paramDocs' = [ (n, annotCode (tryFullExpr syn ist) d)
50+ | (n, d) <- paramDocs ]
5151 acc <- optional accessibility
5252 opts <- dataOpts []
53− reserved "record"
54− return (doc', argDocs', acc, opts))
53+ co <- recordI
54+ return (doc', paramDocs', acc, opts ++ co))
5555 fc <- getFC
5656 tyn_in <- fnName
57− lchar ':'
58− ty <- typeExpr (allowImp syn)
5957 let tyn = expandNS syn tyn_in
60− reserved "where"
61− (cdoc, cargDocs, cn, cty, _, _) <- indentedBlockS (constructor syn)
62− accData acc tyn [cn]
6358 let rsyn = syn { syn_namespace = show (nsroot tyn) :
64− syn_namespace syn }
65− let fns = getRecNames rsyn cty
66− mapM_ (\n -> addAcc n acc) fns
67− return $ PRecord doc rsyn fc tyn ty opts cdoc cn cty
59+ syn_namespace syn }
60+ params <- manyTill (recordParameter rsyn) (reserved "where")
61+ (fields, cname, cdoc) <- indentedBlockS $ agdaStyleBody rsyn tyn
62+ case cname of
63+ Just cn' -> accData acc tyn [cn']
64+ Nothing -> return ()
65+ return $ PRecord doc rsyn fc opts tyn params paramDocs fields cname cdoc syn
6866 <?> "record type declaration"
69− where
67+ where
7068 getRecNames :: SyntaxInfo -> PTerm -> [Name]
7169 getRecNames syn (PPi _ n _ sc) = [expandNS syn n, expandNS syn (mkType n)]
7270 ++ getRecNames syn sc
@@ -76,6 +74,71 @@ record syn = do (doc, argDocs, acc, opts) <- try (do
7674 toFreeze (Just Frozen) = Just Hidden
7775 toFreeze x = x
7876
77+ agdaStyleBody :: SyntaxInfo -> Name -> IdrisParser ([((Maybe Name), Plicity, PTerm, Maybe (Docstring (Either Err PTerm)))], Maybe Name, Docstring (Either Err PTerm))
78+ agdaStyleBody syn tyn = do
79+ ist <- get
80+ fc <- getFC
81+
82+ (constructorName, constructorDoc) <- option (Nothing, emptyDocstring)
83+ (do (doc, _) <- option noDocs docComment
84+ n <- constructor
85+ return (Just n, doc))
86+
87+ let constructorDoc' = annotate syn ist constructorDoc
88+
89+ fields <- many . indented $ field syn
90+
91+ return (fields, constructorName, constructorDoc')
92+ where
93+ field :: SyntaxInfo -> IdrisParser ((Maybe Name), Plicity, PTerm, Maybe (Docstring (Either Err PTerm)))
94+ field syn = do doc <- optional docComment
95+ c <- optional $ lchar '{'
96+ n <- (do n <- fnName
97+ return $ Just (expandNS syn n))
98+ <|> (do symbol "_"
99+ return Nothing)
100+ lchar ':'
101+ t <- typeExpr (allowImp syn)
102+ p <- endPlicity c
103+ ist <- get
104+ let doc' = case doc of -- Temp: Throws away any possible arg docs
105+ Just (d,_) -> Just $ annotate syn ist d
106+ Nothing -> Nothing
107+ return (n, p, t, doc')
108+
109+ constructor :: IdrisParser Name
110+ constructor = (reserved "constructor") *> fnName
111+
112+ endPlicity :: Maybe Char -> IdrisParser Plicity
113+ endPlicity (Just _) = do lchar '}'
114+ return impl
115+ endPlicity Nothing = return expl
116+
117+ annotate :: SyntaxInfo -> IState -> Docstring () -> Docstring (Either Err PTerm)
118+ annotate syn ist = annotCode $ tryFullExpr syn ist
119+
120+recordParameter :: SyntaxInfo -> IdrisParser (Name, Plicity, PTerm)
121+recordParameter syn =
122+ (do lchar '('
123+ (n, pt) <- (namedTy syn <|> onlyName syn)
124+ lchar ')'
125+ return (n, expl, pt))
126+ <|>
127+ (do (n, pt) <- onlyName syn
128+ return (n, expl, pt))
129+
130+ where
131+ namedTy :: SyntaxInfo -> IdrisParser (Name, PTerm)
132+ namedTy syn =
133+ do n <- fnName
134+ lchar ':'
135+ ty <- typeExpr (allowImp syn)
136+ return (expandNS syn n, ty)
137+ onlyName :: SyntaxInfo -> IdrisParser (Name, PTerm)
138+ onlyName syn =
139+ do n <- fnName
140+ return (expandNS syn n, PType)
141+
79142{- | Parses data declaration type (normal or codata)
80143DataI ::= 'data' | 'codata';
81144-}
@@ -83,6 +146,10 @@ dataI :: IdrisParser DataOpts
83146dataI = do reserved "data"; return []
84147 <|> do reserved "codata"; return [Codata]
85148
149+recordI :: IdrisParser DataOpts
150+recordI = do reserved "record"; return []
151+ <|> do reserved "corecord"; return [Codata]
152+
86153{- | Parses if a data should not have a default eliminator
87154DefaultEliminator ::= 'noelim'?
88155 -}
src/Idris/ParseHelpers.hs+3−4
@@ -189,8 +189,6 @@ docComment = do dc <- pushIndent *> docCommentLine
189189 eol ; someSpace
190190 return (n, docs)
191191
192−
193−
194192-- | Parses some white space
195193whiteSpace :: MonadicParsing m => m ()
196194whiteSpace = Tok.whiteSpace
@@ -224,14 +222,15 @@ idrisStyle = IdentifierStyle _styleName _styleStart _styleLetter _styleReserved
224222 where _styleName = "Idris"
225223 _styleStart = satisfy isAlpha <|> oneOf "_"
226224 _styleLetter = satisfy isAlphaNum <|> oneOf "_'."
227− _styleReserved = HS.fromList ["let", "in", "data", "codata", "record", "Type",
225+ _styleReserved = HS.fromList ["let", "in", "data", "codata", "record", "corecord", "Type",
228226 "do", "dsl", "import", "impossible",
229227 "case", "of", "total", "partial", "mutual",
230228 "infix", "infixl", "infixr", "rewrite",
231229 "where", "with", "syntax", "proof", "postulate",
232230 "using", "namespace", "class", "instance", "parameters",
233231 "public", "private", "abstract", "implicit",
234− "quoteGoal", "if", "then", "else"]
232+ "quoteGoal", "constructor",
233+ "if", "then", "else"]
235234
236235char :: MonadicParsing m => Char -> m Char
237236char = Chr.char
test/basic001/reg005.dSYM/Contents/Info.plistnew file+20
@@ -0,0 +1,20 @@
1+<?xml version="1.0" encoding="UTF-8"?>
2+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3+<plist version="1.0">
4+ <dict>
5+ <key>CFBundleDevelopmentRegion</key>
6+ <string>English</string>
7+ <key>CFBundleIdentifier</key>
8+ <string>com.apple.xcode.dsym.reg005</string>
9+ <key>CFBundleInfoDictionaryVersion</key>
10+ <string>6.0</string>
11+ <key>CFBundlePackageType</key>
12+ <string>dSYM</string>
13+ <key>CFBundleSignature</key>
14+ <string>????</string>
15+ <key>CFBundleShortVersionString</key>
16+ <string>1.0</string>
17+ <key>CFBundleVersion</key>
18+ <string>1</string>
19+ </dict>
20+</plist>
test/basic001/reg005.dSYM/Contents/Resources/DWARF/reg005new file

Binary file not shown.

test/corecords001/corecords001.idrnew file+24
@@ -0,0 +1,24 @@
1+module Main
2+
3+corecord Str a where -- Current stream is codata, not a corecord
4+ constructor (::)
5+ head : a
6+ tail : Str a
7+
8+instance Functor Str where
9+ map f (x :: xs) = (f x) :: (map f xs)
10+
11+total -- marked total to check that corecords are indeed treated as coinductive types
12+zeros : Str Int
13+zeros = 0 :: zeros
14+
15+ones : Str Int
16+ones = map (1+) zeros
17+
18+main : IO ()
19+main = do let x = record { head = 1 } zeros
20+ printLn $ head zeros
21+ printLn $ head x
22+ printLn $ head (record { head = 3 } x)
23+ printLn $ head (tail ones)
24+ printLn $ head (tail (record { tail = zeros } ones))
test/corecords001/expectednew file+5
@@ -0,0 +1,5 @@
1+0
2+1
3+3
4+1
5+0
test/corecords001/runnew file+4
@@ -0,0 +1,4 @@
1+#!/usr/bin/env bash
2+idris $@ corecords001.idr -o corecords001
3+./corecords001
4+rm -f corecords001 corecords001.ibc
test/corecords002/corecords002.idrnew file+24
@@ -0,0 +1,24 @@
1+module Main
2+
3+corecord Foo (n : Nat) where
4+ constructor MkFoo
5+ bar : String
6+ baz : Foo n
7+
8+corecord Blargh where
9+ constructor MkBlargh
10+ num : Nat
11+ argh : Foo num
12+
13+total
14+foo : Foo 7
15+foo = MkFoo "Foo" foo
16+
17+total
18+blargh : Blargh
19+blargh = MkBlargh 7 foo
20+
21+main : IO ()
22+main = do printLn (record { argh->bar } blargh)
23+ printLn (record { argh->baz->bar } blargh)
24+ printLn (record { argh->baz->baz->bar } blargh)
test/corecords002/expectednew file+3
@@ -0,0 +1,3 @@
1+"Foo"
2+"Foo"
3+"Foo"
test/corecords002/runnew file+4
@@ -0,0 +1,4 @@
1+#!/usr/bin/env bash
2+idris $@ corecords002.idr -o corecords002
3+./corecords002
4+rm -f corecords002 corecords002.ibc
test/docs004/docs004.idrnew file+11
@@ -0,0 +1,11 @@
1+module Main
2+
3+||| Some record Foo
4+||| @a a type
5+record Foo a where
6+ ||| Constructor for Foo
7+ constructor MkFoo
8+ ||| A field bar
9+ bar : Nat
10+ ||| A field baz
11+ baz : Bool
test/docs004/expectednew file+15
@@ -0,0 +1,15 @@
1+MkFoo : (bar : Nat) -> (baz : Bool) -> Foo a
2+ Constructor for Foo
3+ Arguments:
4+ (implicit) a : Type -- a type
5+
6+ bar : Nat -- A field bar
7+
8+ baz : Bool -- A field baz
9+
10+bar : (rec : Foo a) -> Nat
11+ A field bar
12+
13+baz : (rec : Foo a) -> Bool
14+ A field baz
15+
test/docs004/inputnew file+3
@@ -0,0 +1,3 @@
1+:doc MkFoo
2+:doc bar
3+:doc baz
test/docs004/runnew file+3
@@ -0,0 +1,3 @@
1+#!/usr/bin/env bash
2+idris --quiet --nocolor --consolewidth 80 docs004.idr < input
3+rm *.ibc
test/records001/test011.idr+10−8
@@ -2,14 +2,16 @@ module Main
22
33import Data.Vect
44
5−record Foo : Nat -> Type where
6− MkFoo : (name : String) ->
7− (things : Vect n a) ->
8− (more_things : Vect m b) ->
9− Foo n
10−
11−record Person : Type where
12− MkPerson : (name : String) -> (age : Int) -> Person
5+record Foo (n : Nat) where
6+ constructor MkFoo
7+ name : String
8+ things : Vect n a
9+ more_things : Vect m b
10+
11+record Person where
12+ constructor MkPerson
13+ name : String
14+ age : Int
1315
1416testFoo : Foo 3
1517testFoo = MkFoo "name" [1,2,3] [4,5,6,7]
test/records002/record002.idr+7−6
@@ -1,11 +1,12 @@
1−
2−record Foo : Nat -> Type where
3− MkFoo : (param : Nat) -> (num : Int) -> Foo param
1+record Foo (param : Nat) where
2+ constructor MkFoo
3+ num : Int
44
55instance Show (Foo n) where
6− show f = show (param f) ++ ", " ++ show (num f)
6+ show f = show (param_param f) ++ ", " ++ show (num f)
77
88main : IO ()
9−main = do let x = MkFoo 10 20
10− putStrLn (show (record { param = 42 } x))
9+main = do let x = MkFoo {param=10} 20
10+ putStrLn (show (record { param_param = 42 } x))
1111 putStrLn (show (record { num = 42 } x))
12+
test/records003/records003.idr+24−25
@@ -1,47 +1,46 @@
1−record Person : Nat -> Type where
2− MkPerson : (name : String) ->
3− (age : Nat) ->
4− Person age
1+record Person (age : Nat) where
2+ constructor MkPerson
3+ name : String
54
6−record Event : Type where
7− MkEvent : (name : String) -> (organiser : Person a) -> Event
5+record Event where
6+ constructor MkEvent
7+ name : String
8+ organiser : Person a
89
9−record Meeting : Int -> Type where
10− MkMeeting : (event : Event) ->
11− (organiser : Person a) ->
12− (year : Int) ->
13− Meeting year
10+record Meeting (year : Int) where
11+ constructor MkMeeting
12+ event : Event
13+ organiser : Person a
1414
1515new_organiser : String -> List (Meeting x) -> List (Meeting x)
1616new_organiser n = map (record { event->organiser->name = n })
1717
1818next_year : Meeting x -> Meeting (x+1)
19−next_year m = record { organiser->age
20− = record { organiser->age } m + 1,
21− event->organiser->age
22− = record { event->organiser->age } m + 1,
23− year = _ } m
19+next_year m = record { organiser->param_age
20+ = record { organiser->param_age } m + 1,
21+ event->organiser->param_age
22+ = record { event->organiser->param_age } m + 1,
23+ param_year = _ } m
2424
2525fred : Person 20
26−fred = MkPerson "Fred" _
26+fred = MkPerson "Fred"
2727
2828jim : Person 29
29−jim = MkPerson "Jim" 29
29+jim = MkPerson {age=29} "Jim"
3030
3131idm : Event
3232idm = MkEvent "Idris Developers Meeting" fred
3333
3434idm_gbg : Meeting 2014
35−idm_gbg = MkMeeting idm jim _
35+idm_gbg = MkMeeting idm jim
3636
3737test : Meeting 2015
3838test = next_year idm_gbg
3939
4040main : IO ()
4141main = do printLn (record { event->organiser->name } test)
42− printLn (record { event->organiser->age } test)
43− printLn (record { event->organiser->age } idm_gbg)
44− printLn (record { organiser->age } test)
45− printLn (record { organiser->age } idm_gbg)
46− printLn (record { year } idm_gbg)
47−
42+ printLn (record { event->organiser->param_age } test)
43+ printLn (record { event->organiser->param_age } idm_gbg)
44+ printLn (record { organiser->param_age } test)
45+ printLn (record { organiser->param_age } idm_gbg)
46+ printLn (record { param_year } idm_gbg)