Skip to content

Commit 556eb16

Browse files
committed
simplify codes generator a bit
1 parent b570210 commit 556eb16

1 file changed

Lines changed: 34 additions & 53 deletions

File tree

evdev/src/Evdev/Codes/Generator.hs

Lines changed: 34 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -10,18 +10,11 @@ import Data.Map.Strict (Map)
1010
import Data.Map.Strict qualified as Map
1111
import Data.Maybe
1212
import Language.Haskell.TH
13-
import Numeric
1413

15-
-- | A raw define from the header file.
16-
data RawDefine
17-
= RawPrimary String Int -- ^ Name and numeric value
18-
| RawAlias String String -- ^ Alias name and target name
19-
deriving (Show)
20-
21-
-- | A processed define, after deduplication.
14+
-- | A define from the header file: either a primary (value is a number) or an alias (value is another name).
2215
data Define
23-
= Primary String -- ^ A name that should become a constructor
24-
| Alias String String -- ^ An alias name pointing to a target name
16+
= Primary String String -- ^ Name and raw value string (for dedup grouping)
17+
| Alias String String -- ^ Alias name and target name
2518
deriving (Show)
2619

2720
-- | Configuration for a group of defines that map to a single Haskell type.
@@ -51,68 +44,57 @@ skippedNames :: [String]
5144
skippedNames = ["KEY_MIN_INTERESTING"]
5245

5346
-- | Parse a single @#define@ line.
54-
parseLine :: String -> Maybe RawDefine
47+
parseLine :: String -> Maybe Define
5548
parseLine line = case words line of
5649
("#define" : name : value : _)
5750
| any (`isSuffixOf'` name) ["_MAX", "_CNT"] -> Nothing
5851
| name `elem` skippedNames -> Nothing
5952
| name == "_INPUT_EVENT_CODES_H" -> Nothing
60-
| Just n <- parseNumericValue value -> Just (RawPrimary name n)
61-
| "(" `isPrefixOf` value -> Nothing
62-
| all (\c -> isAlphaNum c || c == '_') value -> Just (RawAlias name value)
53+
| isDigit (head value) -> Just (Primary name value)
54+
| isAlpha (head value) -> Just (Alias name value)
6355
| otherwise -> Nothing
6456
_ -> Nothing
6557
where
6658
isSuffixOf' suffix str = drop (length str - length suffix) str == suffix
6759

68-
-- | Parse a numeric value (decimal or hex).
69-
parseNumericValue :: String -> Maybe Int
70-
parseNumericValue ('0' : 'x' : rest)
71-
| all isHexDigit rest, [(n, "")] <- readHex rest = Just n
72-
parseNumericValue ('0' : 'X' : rest)
73-
| all isHexDigit rest, [(n, "")] <- readHex rest = Just n
74-
parseNumericValue s
75-
| all isDigit s = Just (read s)
76-
parseNumericValue _ = Nothing
77-
78-
-- | Parse the header file, returning all raw defines.
79-
parseHeader :: String -> [RawDefine]
60+
-- | Parse the header file, returning all defines.
61+
parseHeader :: String -> [Define]
8062
parseHeader = mapMaybe parseLine . lines
8163

82-
-- | Get the C name from a 'RawDefine'.
83-
rawDefineName :: RawDefine -> String
84-
rawDefineName (RawPrimary n _) = n
85-
rawDefineName (RawAlias n _) = n
64+
-- | Get the C name from a 'Define'.
65+
defineName :: Define -> String
66+
defineName (Primary n _) = n
67+
defineName (Alias n _) = n
8668

8769
-- | Check if a define belongs to a group.
88-
defInGroup :: Group -> RawDefine -> Bool
89-
defInGroup grp def = any (`isPrefixOf` rawDefineName def) (groupPrefixes grp)
70+
defInGroup :: Group -> Define -> Bool
71+
defInGroup grp def = any (`isPrefixOf` defineName def) (groupPrefixes grp)
9072

91-
-- | Deduplicate primaries: when multiple primaries share a numeric value,
73+
-- | Deduplicate primaries: when multiple primaries share a value string,
9274
-- keep the last one as the constructor and turn earlier ones into aliases.
9375
-- This handles cases like @BTN_GAMEPAD 0x130@ followed by @BTN_SOUTH 0x130@,
9476
-- where @BTN_SOUTH@ becomes the constructor and @BTN_GAMEPAD@ becomes an alias.
95-
dedup :: [RawDefine] -> [Define]
96-
dedup rawDefs =
77+
dedup :: [Define] -> [Define]
78+
dedup defs =
9779
let -- First pass: find which name is the "winner" for each value (last one wins)
98-
valueToName :: Map Int String
80+
valueToName :: Map String String
9981
valueToName = foldl'
100-
(\m rd -> case rd of
101-
RawPrimary name val -> Map.insert val name m
102-
RawAlias _ _ -> m
82+
(\m d -> case d of
83+
Primary name val -> Map.insert val name m
84+
Alias _ _ -> m
10385
)
10486
Map.empty
105-
rawDefs
87+
defs
10688

107-
-- Second pass: convert, turning losers into aliases
108-
convert :: RawDefine -> Define
109-
convert (RawPrimary name val) =
89+
-- Second pass: convert losers into aliases pointing to the winner
90+
convert :: Define -> Define
91+
convert (Primary name val) =
11092
let winner = valueToName Map.! val
11193
in if name == winner
112-
then Primary name
94+
then Primary name val
11395
else Alias name winner
114-
convert (RawAlias name target) = Alias name target
115-
in map convert rawDefs
96+
convert a@Alias{} = a
97+
in map convert defs
11698

11799
-- | Transform a C name like @KEY_LEFT_SHIFT@ into a Haskell constructor name like @KeyLeftShift@.
118100
toCamelCase :: [String] -> String -> String
@@ -150,15 +132,14 @@ toRawName (c : cs) = toLower c : cs
150132
generateCodes :: Q [Dec]
151133
generateCodes = do
152134
contents <- runIO $ readFile "/nix/store/7iwv8dcgsjmkrnn752hnfdxh3f7wahmd-linux-headers-6.16.7/include/linux/input-event-codes.h"
153-
let rawDefs = parseHeader contents
154-
concat <$> mapM (generateGroup rawDefs) groups
135+
let defs = parseHeader contents
136+
concat <$> mapM (generateGroup defs) groups
155137

156138
-- | Generate declarations for a single group: data type, SimpleEnum instance, and pattern synonyms.
157-
generateGroup :: [RawDefine] -> Group -> Q [Dec]
158-
generateGroup allRawDefs grp = do
159-
let myRawDefs = filter (defInGroup grp) allRawDefs
160-
myDefs = dedup myRawDefs
161-
primaries = [n | Primary n <- myDefs]
139+
generateGroup :: [Define] -> Group -> Q [Dec]
140+
generateGroup allDefs grp = do
141+
let myDefs = dedup $ filter (defInGroup grp) allDefs
142+
primaries = [n | Primary n _ <- myDefs]
162143
aliases = [(a, t) | Alias a t <- myDefs]
163144
prefixes = groupPrefixes grp
164145
tyName = mkName (groupTypeName grp)

0 commit comments

Comments
 (0)