1{-| Names in the concrete syntax are just strings (or lists of strings for
2    qualified names).
3-}
4module Agda.Syntax.Concrete.Name where
5
6import Control.DeepSeq
7
8import Data.ByteString.Char8 (ByteString)
9import Data.Function
10import qualified Data.Foldable as Fold
11import qualified Data.List as List
12import Data.Data (Data)
13
14import GHC.Generics (Generic)
15
16import System.FilePath
17
18import Agda.Syntax.Common
19import Agda.Syntax.Concrete.Glyph
20import Agda.Syntax.Position
21
22import Agda.Utils.FileName
23import Agda.Utils.Lens
24import Agda.Utils.List  (last1)
25import Agda.Utils.List1 (List1, pattern (:|), (<|))
26import qualified Agda.Utils.List1 as List1
27import Agda.Utils.Pretty
28import Agda.Utils.Singleton
29import Agda.Utils.Size
30import Agda.Utils.Suffix
31
32import Agda.Utils.Impossible
33
34{-| A name is a non-empty list of alternating 'Id's and 'Hole's. A normal name
35    is represented by a singleton list, and operators are represented by a list
36    with 'Hole's where the arguments should go. For instance: @[Hole,Id "+",Hole]@
37    is infix addition.
38
39    Equality and ordering on @Name@s are defined to ignore range so same names
40    in different locations are equal.
41-}
42data Name
43  = Name -- ^ A (mixfix) identifier.
44    { nameRange     :: Range
45    , nameInScope   :: NameInScope
46    , nameNameParts :: NameParts
47    }
48  | NoName -- ^ @_@.
49    { nameRange     :: Range
50    , nameId        :: NameId
51    }
52  deriving Data
53
54type NameParts = List1 NamePart
55
56-- | An open mixfix identifier is either prefix, infix, or suffix.
57--   That is to say: at least one of its extremities is a @Hole@
58
59isOpenMixfix :: Name -> Bool
60isOpenMixfix = \case
61  Name _ _ (x :| x' : xs) -> x == Hole || last1 x' xs == Hole
62  _ -> False
63
64instance Underscore Name where
65  underscore = NoName noRange __IMPOSSIBLE__
66  isUnderscore NoName{} = True
67  isUnderscore (Name {nameNameParts = Id x :| []}) = isUnderscore x
68  isUnderscore _ = False
69
70-- | Mixfix identifiers are composed of words and holes,
71--   e.g. @_+_@ or @if_then_else_@ or @[_/_]@.
72data NamePart
73  = Hole       -- ^ @_@ part.
74  | Id RawName  -- ^ Identifier part.
75  deriving (Data, Generic)
76
77-- | Define equality on @Name@ to ignore range so same names in different
78--   locations are equal.
79--
80--   Is there a reason not to do this? -Jeff
81--
82--   No. But there are tons of reasons to do it. For instance, when using
83--   names as keys in maps you really don't want to have to get the range
84--   right to be able to do a lookup. -Ulf
85
86instance Eq Name where
87    Name _ _ xs    == Name _ _ ys    = xs == ys
88    NoName _ i     == NoName _ j     = i == j
89    _              == _              = False
90
91instance Ord Name where
92    compare (Name _ _ xs)  (Name _ _ ys)      = compare xs ys
93    compare (NoName _ i)   (NoName _ j)       = compare i j
94    compare (NoName {})    (Name {})          = LT
95    compare (Name {})      (NoName {})        = GT
96
97instance Eq NamePart where
98  Hole  == Hole  = True
99  Id s1 == Id s2 = s1 == s2
100  _     == _     = False
101
102instance Ord NamePart where
103  compare Hole    Hole    = EQ
104  compare Hole    (Id {}) = LT
105  compare (Id {}) Hole    = GT
106  compare (Id s1) (Id s2) = compare s1 s2
107
108-- | @QName@ is a list of namespaces and the name of the constant.
109--   For the moment assumes namespaces are just @Name@s and not
110--     explicitly applied modules.
111--   Also assumes namespaces are generative by just using derived
112--     equality. We will have to define an equality instance to
113--     non-generative namespaces (as well as having some sort of
114--     lookup table for namespace names).
115data QName
116  = Qual  Name QName -- ^ @A.rest@.
117  | QName Name       -- ^ @x@.
118  deriving (Data, Eq, Ord)
119
120instance Underscore QName where
121  underscore = QName underscore
122  isUnderscore (QName x) = isUnderscore x
123  isUnderscore Qual{}    = False
124
125-- | Top-level module names.  Used in connection with the file system.
126--
127--   Invariant: The list must not be empty.
128
129data TopLevelModuleName = TopLevelModuleName
130  { moduleNameRange :: Range
131  , moduleNameParts :: List1 String
132  }
133  deriving (Show, Data, Generic)
134
135instance Eq    TopLevelModuleName where (==)    = (==)    `on` moduleNameParts
136instance Ord   TopLevelModuleName where compare = compare `on` moduleNameParts
137instance Sized TopLevelModuleName where size    = size     .   moduleNameParts
138
139------------------------------------------------------------------------
140-- * Constructing simple 'Name's.
141------------------------------------------------------------------------
142
143-- | Create an ordinary 'InScope' name.
144simpleName :: RawName -> Name
145simpleName = Name noRange InScope . singleton . Id
146
147-- | Create a binary operator name in scope.
148simpleBinaryOperator :: RawName -> Name
149simpleBinaryOperator s = Name noRange InScope $ Hole :| Id s : Hole : []
150
151-- | Create an ordinary 'InScope' name containing a single 'Hole'.
152simpleHole :: Name
153simpleHole = Name noRange InScope $ singleton Hole
154
155------------------------------------------------------------------------
156-- * Operations on 'Name' and 'NamePart'
157------------------------------------------------------------------------
158
159-- | Don't use on 'NoName{}'.
160lensNameParts :: Lens' NameParts Name
161lensNameParts f = \case
162  n@Name{} -> f (nameNameParts n) <&> \ ps -> n { nameNameParts = ps }
163  NoName{} -> __IMPOSSIBLE__
164
165nameToRawName :: Name -> RawName
166nameToRawName = prettyShow
167
168nameParts :: Name -> NameParts
169nameParts (Name _ _ ps)    = ps
170nameParts (NoName _ _)     = singleton $ Id "_" -- To not return an empty list
171
172nameStringParts :: Name -> [RawName]
173nameStringParts n = [ s | Id s <- List1.toList $ nameParts n ]
174
175-- | Parse a string to parts of a concrete name.
176--
177--   Note: @stringNameParts "_" == [Id "_"] == nameParts NoName{}@
178
179stringNameParts :: String -> NameParts
180stringNameParts ""  = singleton $ Id "_"  -- NoName
181stringNameParts "_" = singleton $ Id "_"  -- NoName
182stringNameParts s = List1.fromList $ loop s
183  where
184  loop ""                              = []
185  loop ('_':s)                         = Hole : loop s
186  loop s | (x, s') <- break (== '_') s = Id (stringToRawName x) : loop s'
187
188-- | Number of holes in a 'Name' (i.e., arity of a mixfix-operator).
189class NumHoles a where
190  numHoles :: a -> Int
191
192instance NumHoles NameParts where
193  numHoles = length . List1.filter (== Hole)
194
195instance NumHoles Name where
196  numHoles NoName{}         = 0
197  numHoles (Name { nameNameParts = parts }) = numHoles parts
198
199instance NumHoles QName where
200  numHoles (QName x)  = numHoles x
201  numHoles (Qual _ x) = numHoles x
202
203-- | Is the name an operator?
204--   Needs at least 2 'NamePart's.
205isOperator :: Name -> Bool
206isOperator = \case
207  Name _ _ (_ :| _ : _) -> True
208  _ -> False
209
210isHole :: NamePart -> Bool
211isHole Hole = True
212isHole _    = False
213
214isPrefix, isPostfix, isInfix, isNonfix :: Name -> Bool
215isPrefix  x = not (isHole (List1.head xs)) &&      isHole (List1.last xs)  where xs = nameParts x
216isPostfix x =      isHole (List1.head xs)  && not (isHole (List1.last xs)) where xs = nameParts x
217isInfix   x =      isHole (List1.head xs)  &&      isHole (List1.last xs)  where xs = nameParts x
218isNonfix  x = not (isHole (List1.head xs)) && not (isHole (List1.last xs)) where xs = nameParts x
219
220
221------------------------------------------------------------------------
222-- * Keeping track of which names are (not) in scope
223------------------------------------------------------------------------
224
225data NameInScope = InScope | NotInScope
226  deriving (Eq, Show, Data)
227
228class LensInScope a where
229  lensInScope :: Lens' NameInScope a
230
231  isInScope :: a -> NameInScope
232  isInScope x = x ^. lensInScope
233
234  mapInScope :: (NameInScope -> NameInScope) -> a -> a
235  mapInScope = over lensInScope
236
237  setInScope :: a -> a
238  setInScope = mapInScope $ const InScope
239
240  setNotInScope :: a -> a
241  setNotInScope = mapInScope $ const NotInScope
242
243instance LensInScope NameInScope where
244  lensInScope = id
245
246instance LensInScope Name where
247  lensInScope f = \case
248    n@Name{ nameInScope = nis } -> (\nis' -> n { nameInScope = nis' }) <$> f nis
249    n@NoName{} -> n <$ f InScope
250
251instance LensInScope QName where
252  lensInScope f = \case
253    Qual x xs -> (`Qual` xs) <$> lensInScope f x
254    QName x   -> QName <$> lensInScope f x
255
256------------------------------------------------------------------------
257-- * Generating fresh names
258------------------------------------------------------------------------
259
260-- | Method by which to generate fresh unshadowed names.
261data FreshNameMode
262  = UnicodeSubscript
263  -- ^ Append an integer Unicode subscript: x, x₁, x₂, …
264  | AsciiCounter
265  -- ^ Append an integer ASCII counter: x, x1, x2, …
266
267  -- Note that @Agda.Utils.Suffix@ supports an additional style, @Prime@, but
268  -- we currently only encounter it when extending an existing name of that
269  -- format, (x', x'', …), not for an initially-generated permutation. There's
270  -- no reason we couldn't, except that we currently choose between
271  -- subscript/counter styles based on the --no-unicode mode rather than any
272  -- finer-grained option.
273  --   | PrimeTickCount
274  --   ^ Append an ASCII prime/apostrophe: x, x', x'', …
275
276nextRawName :: FreshNameMode -> RawName -> RawName
277nextRawName freshNameMode s = addSuffix root (maybe initialSuffix nextSuffix suffix)
278  where
279  (root, suffix) = suffixView s
280  initialSuffix = case freshNameMode of
281    UnicodeSubscript -> Subscript 1
282    AsciiCounter -> Index 1
283
284-- | Get the next version of the concrete name. For instance,
285--   @nextName "x" = "x₁"@.  The name must not be a 'NoName'.
286nextName :: FreshNameMode -> Name -> Name
287nextName freshNameMode x@Name{} = setNotInScope $ over (lensNameParts . lastIdPart) (nextRawName freshNameMode) x
288nextName             _ NoName{} = __IMPOSSIBLE__
289
290-- | Zoom on the last non-hole in a name.
291lastIdPart :: Lens' RawName NameParts
292lastIdPart f = loop
293  where
294  loop = \case
295    Id s :| []     -> f s <&> \ s -> Id s :| []
296    Id s :| [Hole] -> f s <&> \ s -> Id s :| [Hole]
297    p1 :| p2 : ps  -> (p1 <|) <$> loop (p2 :| ps)
298    Hole :| []     -> __IMPOSSIBLE__
299
300-- | Get the first version of the concrete name that does not satisfy
301--   the given predicate.
302firstNonTakenName :: FreshNameMode -> (Name -> Bool) -> Name -> Name
303firstNonTakenName freshNameMode taken x =
304  if taken x
305  then firstNonTakenName freshNameMode taken (nextName freshNameMode x)
306  else x
307
308-- | Lens for accessing and modifying the suffix of a name.
309--   The suffix of a @NoName@ is always @Nothing@, and should not be
310--   changed.
311nameSuffix :: Lens' (Maybe Suffix) Name
312nameSuffix (f :: Maybe Suffix -> f (Maybe Suffix)) = \case
313
314  n@NoName{} -> f Nothing <&> \case
315    Nothing -> n
316    Just {} -> __IMPOSSIBLE__
317
318  n@Name{} -> lensNameParts (lastIdPart idSuf) n
319    where
320    idSuf s =
321      let (root, suffix) = suffixView s
322      in maybe root (addSuffix root) <$> (f suffix)
323
324-- | Split a name into a base name plus a suffix.
325nameSuffixView :: Name -> (Maybe Suffix, Name)
326nameSuffixView = nameSuffix (,Nothing)
327
328-- | Replaces the suffix of a name. Unless the suffix is @Nothing@,
329--   the name should not be @NoName@.
330setNameSuffix :: Maybe Suffix -> Name -> Name
331setNameSuffix = set nameSuffix
332
333-- | Get a raw version of the name with all suffixes removed. For
334--   instance, @nameRoot "x₁₂₃" = "x"@.
335nameRoot :: Name -> RawName
336nameRoot x = nameToRawName $ snd $ nameSuffixView x
337
338sameRoot :: Name -> Name -> Bool
339sameRoot = (==) `on` nameRoot
340
341------------------------------------------------------------------------
342-- * Operations on qualified names
343------------------------------------------------------------------------
344
345-- | Lens for the unqualified part of a QName
346lensQNameName :: Lens' Name QName
347lensQNameName f (QName n)  = QName <$> f n
348lensQNameName f (Qual m n) = Qual m <$> lensQNameName f n
349
350-- | @qualify A.B x == A.B.x@
351qualify :: QName -> Name -> QName
352qualify (QName m) x     = Qual m (QName x)
353qualify (Qual m m') x   = Qual m $ qualify m' x
354
355-- | @unqualify A.B.x == x@
356--
357-- The range is preserved.
358unqualify :: QName -> Name
359unqualify q = unqualify' q `withRangeOf` q
360  where
361  unqualify' (QName x)  = x
362  unqualify' (Qual _ x) = unqualify' x
363
364-- | @qnameParts A.B.x = [A, B, x]@
365qnameParts :: QName -> List1 Name
366qnameParts (Qual x q) = x <| qnameParts q
367qnameParts (QName x)  = singleton x
368
369-- | Is the name (un)qualified?
370
371isQualified :: QName -> Bool
372isQualified Qual{}  = True
373isQualified QName{} = False
374
375isUnqualified :: QName -> Maybe Name
376isUnqualified Qual{}    = Nothing
377isUnqualified (QName n) = Just n
378
379------------------------------------------------------------------------
380-- * Operations on 'TopLevelModuleName'
381------------------------------------------------------------------------
382
383-- | Turns a qualified name into a 'TopLevelModuleName'. The qualified
384-- name is assumed to represent a top-level module name.
385
386toTopLevelModuleName :: QName -> TopLevelModuleName
387toTopLevelModuleName q = TopLevelModuleName (getRange q) $
388  fmap nameToRawName $ qnameParts q
389
390-- | Turns a top-level module name into a file name with the given
391-- suffix.
392
393moduleNameToFileName :: TopLevelModuleName -> String -> FilePath
394moduleNameToFileName (TopLevelModuleName _ ms) ext =
395  joinPath (List1.init ms) </> List1.last ms <.> ext
396
397-- | Finds the current project's \"root\" directory, given a project
398-- file and the corresponding top-level module name.
399--
400-- Example: If the module \"A.B.C\" is located in the file
401-- \"/foo/A/B/C.agda\", then the root is \"/foo/\".
402--
403-- Precondition: The module name must be well-formed.
404
405projectRoot :: AbsolutePath -> TopLevelModuleName -> AbsolutePath
406projectRoot file (TopLevelModuleName _ m) =
407  mkAbsolute $
408    iterate takeDirectory (filePath file) !! length m
409
410------------------------------------------------------------------------
411-- * No name stuff
412------------------------------------------------------------------------
413
414-- | @noName_ = 'noName' 'noRange'@
415noName_ :: Name
416noName_ = noName noRange
417
418noName :: Range -> Name
419noName r = NoName r (NameId 0 noModuleNameHash)
420
421-- | Check whether a name is the empty name "_".
422class IsNoName a where
423  isNoName :: a -> Bool
424
425  default isNoName :: (Foldable t, IsNoName b, t b ~ a) => a -> Bool
426  isNoName = Fold.all isNoName
427
428instance IsNoName String where
429  isNoName = isUnderscore
430
431instance IsNoName ByteString where
432  isNoName = isUnderscore
433
434instance IsNoName Name where
435  isNoName = \case
436    NoName{}              -> True
437    Name _ _ (Hole :| []) -> True
438    Name _ _ (Id x :| []) -> isNoName x
439    _ -> False
440
441instance IsNoName QName where
442  isNoName (QName x) = isNoName x
443  isNoName Qual{}    = False        -- M.A._ does not qualify as empty name
444
445instance IsNoName a => IsNoName (Ranged a) where
446instance IsNoName a => IsNoName (WithOrigin a) where
447
448-- no instance for TopLevelModuleName
449
450------------------------------------------------------------------------
451-- * Showing names
452------------------------------------------------------------------------
453
454deriving instance Show Name
455deriving instance Show NamePart
456deriving instance Show QName
457
458------------------------------------------------------------------------
459-- * Printing names
460------------------------------------------------------------------------
461
462instance Pretty Name where
463  pretty (Name _ _ xs)    = hcat $ fmap pretty xs
464  pretty (NoName _ _)     = "_"
465
466instance Pretty NamePart where
467  pretty Hole   = "_"
468  pretty (Id s) = text $ rawNameToString s
469
470instance Pretty QName where
471  pretty (Qual m x)
472    | isUnderscore m = pretty x -- don't print anonymous modules
473    | otherwise      = pretty m <> "." <> pretty x
474  pretty (QName x)  = pretty x
475
476instance Pretty TopLevelModuleName where
477  pretty (TopLevelModuleName _ ms) = text $ List.intercalate "." $ List1.toList ms
478
479------------------------------------------------------------------------
480-- * Range instances
481------------------------------------------------------------------------
482
483instance HasRange Name where
484    getRange (Name r _ _ps) = r
485    getRange (NoName r _)   = r
486
487instance HasRange QName where
488    getRange (QName  x) = getRange x
489    getRange (Qual n x) = fuseRange n x
490
491instance HasRange TopLevelModuleName where
492  getRange = moduleNameRange
493
494instance SetRange Name where
495  setRange r (Name _ nis ps) = Name r nis ps
496  setRange r (NoName _ i)  = NoName r i
497
498instance SetRange QName where
499  setRange r (QName x)  = QName (setRange r x)
500  setRange r (Qual n x) = Qual (setRange r n) (setRange r x)
501
502instance SetRange TopLevelModuleName where
503  setRange r (TopLevelModuleName _ x) = TopLevelModuleName r x
504
505instance KillRange QName where
506  killRange (QName x) = QName $ killRange x
507  killRange (Qual n x) = killRange n `Qual` killRange x
508
509instance KillRange Name where
510  killRange (Name r nis ps)  = Name (killRange r) nis ps
511  killRange (NoName r i)     = NoName (killRange r) i
512
513instance KillRange TopLevelModuleName where
514  killRange (TopLevelModuleName _ x) = TopLevelModuleName noRange x
515
516------------------------------------------------------------------------
517-- * NFData instances
518------------------------------------------------------------------------
519
520instance NFData NameInScope where
521  rnf InScope    = ()
522  rnf NotInScope = ()
523
524-- | Ranges are not forced.
525
526instance NFData Name where
527  rnf (Name _ nis ns) = rnf nis `seq` rnf ns
528  rnf (NoName _ n)  = rnf n
529
530instance NFData NamePart where
531  rnf Hole   = ()
532  rnf (Id s) = rnf s
533
534instance NFData QName where
535  rnf (Qual a b) = rnf a `seq` rnf b
536  rnf (QName a)  = rnf a
537
538instance NFData TopLevelModuleName
539