@@ -9,6 +9,7 @@
99{-# LANGUAGE RankNTypes #-}
1010{-# LANGUAGE RecordWildCards #-}
1111{-# LANGUAGE TemplateHaskell #-}
12+{-# LANGUAGE ViewPatterns #-}
1213
1314-- Module : Gen.Solve
1415-- Copyright : (c) 2015 Brendan Hay
@@ -27,6 +28,8 @@ import Control.Monad.State.Strict
2728import Data.CaseInsensitive (CI)
2829import qualified Data.CaseInsensitive as CI
2930import Data.Char (toLower)
31+import Data.Hashable
32+import qualified Data.HashMap.Strict as Map
3033import qualified Data.HashMap.Strict as Map
3134import qualified Data.HashSet as Set
3235import Data.List (intersect)
@@ -36,6 +39,7 @@ import Data.Text (Text)
3639import qualified Data.Text as Text
3740import Data.Text.Manipulate
3841import Gen.Formatting
42+import Gen.Text
3943import Gen.Types
4044import Prelude hiding (sum)
4145
@@ -154,17 +158,80 @@ derive k = loc "derive" k $ memo derived k go
154158 base = [DEq, DRead, DShow, DData, DTypeable, DGeneric]
155159
156160prefix :: Id -> AST Pre
157−prefix k = loc "prefix" k $ memo prefixed k go
161+prefix k = loc "prefix" k $ memo prefixed k typ
162+ where
163+ typ = \case
164+ Obj i rs -> field rs >> pure (Pre k)
165+ Enum i vs ds -> pure (Pre k)
166+ _ -> pure (Pre k)
167+
168+ field (keys -> ks) = do
169+ p <- uniq fields (acronymPrefixes k) ks
170+ forM_ ks $ \n ->
171+ prefixed %= Map.insert (k <> key n) (Pre (key p <> key n))
172+ pure (Pre (key p))
173+
174+ key = idFromText . CI.foldedCase
175+
176+ uniq :: Lens' Memo Seen
177+ -> [CI Text]
178+ -> Set (CI Text)
179+ -> AST (CI Text)
180+ uniq _ [] ks = failure ("Unable to generate unique prefix: " % fid) k
181+ uniq seen (x:xs) ks = do
182+ m <- uses seen (Map.lookup x)
183+ case m of
184+ Just ys | overlap ys ks
185+ -> uniq seen xs ks
186+ _ -> do
187+ seen %= Map.insertWith (<>) x ks
188+ return x
189+
190+overlap :: (Eq a, Hashable a) => Set a -> Set a -> Bool
191+overlap xs ys = not . Set.null $ Set.intersection xs ys
192+
193+keys :: Map Id a -> Set (CI Text)
194+keys = Set.fromList . map (CI.mk . idToText) . Map.keys
195+
196+acronymPrefixes :: Id -> [CI Text]
197+acronymPrefixes (idToText -> n) = map CI.mk (xs ++ map suffix ys)
158198 where
159− go (Obj i rs) = Map.traverseWithKey prop rs >> pure (Pre k)
160− go s = pure (Pre k)
199+ -- Take the next char
200+ suffix x = Text.snoc x c
201+ where
202+ c | Text.length x >= 2 = Text.head (Text.drop 1 x)
203+ | otherwise = Text.head x
204+
205+ xs = catMaybes [r1, r2, r3, r4, r5, r6]
206+ ys = catMaybes [r1, r2, r3, r4, r6]
207+
208+ a = camelAcronym n
209+ a' = upperAcronym n
210+
211+ limit = 3
212+
213+ -- Full name if leq limit
214+ r1 | Text.length n <= limit = Just n
215+ | otherwise = Nothing
216+
217+ -- VpcPeeringInfo -> VPI
218+ r2 = toAcronym a
219+
220+ -- VpcPeeringInfo -> VPCPI
221+ r3 | x /= r2 = x
222+ | otherwise = Nothing
223+ where
224+ x = toAcronym a'
225+
226+ -- SomeTestTType -> S
227+ r4 = Text.toUpper <$> safeHead n
161228
162− prop n _ = do
163− let p = Pre (idFromText (acronym $ idToText k) <> n)
164− prefixed %= Map.insert (k <> n) p
165− pure p
229+ -- SomeTypes -> STS (retain pural)
230+ r5 | Text.isSuffixOf "s" n = flip Text.snoc 's' <$> (r2 <|> r3)
231+ | otherwise = Nothing
166232
167− acronym = foldMap (Text.singleton . toLower . Text.head) . splitWords
233+ -- SomeTestTType -> Som
234+ r6 = Text.take limit <$> listToMaybe (splitWords a)
168235
169236loc :: String -> Id -> a -> a
170237loc _ _ = id -- trace (n ++ ": " ++ Text.unpack (refToText r))