summaryrefslogtreecommitdiff
path: root/protocols/codegen/Wayland/CodeGen/Utils.hs
diff options
context:
space:
mode:
authorHannes Schulze <haschu0103@outlook.de>2024-08-10 02:45:20 +0200
committerHannes Schulze <haschu0103@outlook.de>2024-08-10 02:45:20 +0200
commit68aa2b10c8ad9782a61a6699262751ec5cb93709 (patch)
tree8d940e0f884064371c43a1633d44f1a788d5f840 /protocols/codegen/Wayland/CodeGen/Utils.hs
parentea6a270a481ae9c5ce6d3d2508c61734b8fd137d (diff)
wip codegen
Diffstat (limited to 'protocols/codegen/Wayland/CodeGen/Utils.hs')
-rw-r--r--protocols/codegen/Wayland/CodeGen/Utils.hs88
1 files changed, 88 insertions, 0 deletions
diff --git a/protocols/codegen/Wayland/CodeGen/Utils.hs b/protocols/codegen/Wayland/CodeGen/Utils.hs
new file mode 100644
index 0000000..fa04286
--- /dev/null
+++ b/protocols/codegen/Wayland/CodeGen/Utils.hs
@@ -0,0 +1,88 @@
+module Wayland.CodeGen.Utils
+ ( pascalCase
+ , camelCase
+ , recordField
+ , protocolModule
+ , interfaceModule
+ , fullModule
+ , FlatModules
+ , flattenModules
+ , resolveTypes
+ ) where
+
+import Data.Char (toUpper, toLower)
+import Wayland.CodeGen.Types
+import qualified Data.Map as M
+import Control.Monad.State.Strict (State, runState, gets, modify)
+import Data.Functor (($>))
+
+type FlatModules = M.Map String (TypedProtocol, TypedInterfaceDesc)
+
+pascalCase :: String -> String
+pascalCase (c:cs) = toUpper c : camelCase cs
+pascalCase [] = []
+
+camelCase :: String -> String
+camelCase ('_':cs) = pascalCase cs
+camelCase (c :cs) = c : camelCase cs
+camelCase [] = []
+
+recordField :: String -> String -> String
+recordField name field = applyFirst toLower name ++ applyFirst toUpper field
+ where applyFirst _ [] = []
+ applyFirst f (x:xs) = f x : xs
+
+protocolModule :: ProtocolT i -> String
+protocolModule = fromName . protName
+ where fromName "wayland" = "Core"
+ fromName name = pascalCase name
+
+interfaceModule :: InterfaceDesc -> String
+interfaceModule = pascalCase . ifName
+
+fullModule :: ProtocolT i -> InterfaceDesc -> String
+fullModule p i = "Wayland.Protocols." ++ protocolModule p ++ "." ++ interfaceModule i
+
+flattenModules :: [TypedProtocol] -> FlatModules
+flattenModules protocols = M.unions $ fmap flattenProtocol protocols
+ where flattenProtocol p = M.fromList $ fmap (flattenInterface p) (protInterfaces p)
+ flattenInterface p i = (ifName (fst i), (p, i))
+
+resolveTypes :: Protocol -> TypedProtocol
+resolveTypes p = Protocol { protName = protName p
+ , protDescription = protDescription p
+ , protCopyright = protCopyright p
+ , protInterfaces = runInterface <$> protInterfaces p
+ }
+ where runInterface i = runState (resolveInterfaceTypes i $> i) emptyTypeInfo
+
+resolveInterfaceTypes :: InterfaceDesc -> State TypeInfo ()
+resolveInterfaceTypes i = do
+ let assignRequestArgs r a (TypeInfo requests events enums) = TypeInfo (M.insert r a requests) events enums
+ let assignEventArgs e a (TypeInfo requests events enums) = TypeInfo requests (M.insert e a events) enums
+ let assignEnumName e n (TypeInfo requests events enums) = TypeInfo requests events (M.insert e n enums)
+ let resolveAndAssign res ass = do x <- res; modify $ ass x
+ mapM_ (\m -> resolveAndAssign (resolveMessageType m) (assignEventArgs (msgName m))) (ifEvents i)
+ mapM_ (\m -> resolveAndAssign (resolveMessageType m) (assignRequestArgs (msgName m))) (ifRequests i)
+ mapM_ (\e -> resolveAndAssign (resolveEnumType e) (assignEnumName (enumName e))) (ifEnums i)
+
+resolveMessageType :: MessageDesc -> State TypeInfo ArgumentMode
+resolveMessageType m = case msgArguments m of
+ [] -> pure ArgumentModeNone
+ [a] -> pure $ ArgumentModeSingle a
+ as -> ArgumentModeRecord as <$> getFreeTypeName (pascalCase (msgName m)) Nothing
+
+resolveEnumType :: EnumDesc -> State TypeInfo String
+resolveEnumType e = getFreeTypeName (pascalCase (enumName e)) $ if enumBitfield e then Just "Flags" else Nothing
+
+getFreeTypeName :: String -> Maybe String -> State TypeInfo String
+getFreeTypeName requested conflictSuffix = attemptRequested
+ where attemptName :: String -> State TypeInfo Bool
+ attemptName name = gets $ isTypeFree name
+ attemptRequested = attemptName requested >>= \s -> if s then pure requested else attemptSuffix
+ attemptSuffix = case conflictSuffix of
+ Just suffix -> let n = requested ++ suffix
+ in attemptName n >>= \s -> if s then pure n else attemptPrime n
+ Nothing -> attemptPrime requested
+ attemptPrime n = let n' = n ++ "'"
+ in attemptName n' >>= \s -> if s then pure n' else attemptPrime n'