summaryrefslogtreecommitdiff
path: root/tools/Scanner/Processor.lean
diff options
context:
space:
mode:
authorHannes Schulze <haschu0103@outlook.de>2026-04-03 23:38:07 +0200
committerHannes Schulze <haschu0103@outlook.de>2026-04-03 23:38:07 +0200
commit4119fa8c0c59bb39f9aeba7f479067fd834c4e20 (patch)
treed949428ac1697b6cb28dcdf2a628984200d9a7c2 /tools/Scanner/Processor.lean
parent09be9fb2701f0560aeb714f89fe0d1e750915ae0 (diff)
resolve types in protocols
Diffstat (limited to 'tools/Scanner/Processor.lean')
-rw-r--r--tools/Scanner/Processor.lean137
1 files changed, 137 insertions, 0 deletions
diff --git a/tools/Scanner/Processor.lean b/tools/Scanner/Processor.lean
new file mode 100644
index 0000000..fad25bc
--- /dev/null
+++ b/tools/Scanner/Processor.lean
@@ -0,0 +1,137 @@
+import Scanner.Protocol
+import Std.Data.TreeMap
+
+namespace WaylandScanner
+
+private structure InterfaceInfo where
+ moduleName : Identifier
+ enums : Array Identifier
+
+private abbrev InterfaceMap := Std.TreeMap String InterfaceInfo
+
+private structure Context where
+ interfaces : InterfaceMap
+ currentInterface : Identifier
+
+private abbrev Processor : Type → Type := ReaderT Context (Except String)
+
+private def processEnumEntry (raw : Raw.EnumEntryDesc) : Processor Client.EnumEntryDesc := do
+ return {
+ name := raw.name
+ value := raw.value
+ description := raw.description
+ since := raw.since
+ deprecatedSince := raw.deprecatedSince
+ }
+
+private def interfaceInfo (name : String) : Processor InterfaceInfo := do
+ match (← read).interfaces.get? name with
+ | .some info => pure info
+ | .none => .error s!"Unable to find referenced interface {name}"
+
+private def resolveInterface (name : String) : Processor Client.InterfaceRef := do
+ let info ← interfaceInfo name
+ return {
+ moduleName := info.moduleName
+ typeName := name
+ }
+
+private def resolveEnum (name : String) : Processor Client.EnumRef := do
+ let (interface, enum) ←
+ match (name.split ".").toArray with
+ | #[enum] => pure ((← read).currentInterface, enum.toString)
+ | #[interface, enum] => pure (interface.toString, enum.toString)
+ | _ => throw s!"Malformed enum reference {name}"
+ let info ← interfaceInfo interface
+ if not (info.enums.contains enum) then
+ throw s!"Interface {repr interface} does not contain enum {repr enum}"
+ return {
+ moduleName := info.moduleName
+ typeName := interface
+ enumName := enum
+ }
+
+private def processEnum (raw : Raw.EnumDesc) : Processor Client.EnumDesc := do
+ return {
+ name := raw.name
+ description := raw.description
+ since := raw.since
+ bitfield := raw.bitfield
+ entries := ← raw.entries.mapM processEnumEntry
+ }
+
+private def processArgument (raw : Raw.ArgumentDesc) : Processor Client.ArgumentDesc := do
+ return {
+ name := raw.name
+ type :=
+ ← match raw.type with
+ | .int => Client.ArgumentType.int <$> raw.enum.mapM resolveEnum
+ | .uInt => Client.ArgumentType.uInt <$> raw.enum.mapM resolveEnum
+ | .fixed => Client.ArgumentType.fixed |> pure
+ | .string => Client.ArgumentType.string (.ofAllowNull raw.allowNull) |> pure
+ | .array => Client.ArgumentType.array |> pure
+ | .fd => Client.ArgumentType.fd |> pure
+ | .newID => Client.ArgumentType.object .notNull <$> raw.interface.mapM resolveInterface
+ | .object => Client.ArgumentType.object (.ofAllowNull raw.allowNull) <$> raw.interface.mapM resolveInterface
+ description := raw.description
+ }
+
+private def processRequest (raw : Raw.MessageDesc) : Processor Client.RequestDesc := do
+ let newIDArgs := raw.arguments.filter fun arg ↦ arg.type == .newID
+ let otherArgs := raw.arguments.filter fun arg ↦ arg.type != .newID
+ let returnType ←
+ match newIDArgs with
+ | #[] => Client.ReturnType.unit |> pure
+ | #[arg] => Client.ReturnType.object <$> arg.interface.mapM resolveInterface
+ | _ => throw s!"Expected at most one new_id argument for request in {raw.name}"
+ return {
+ name := raw.name
+ opcode := raw.opcode
+ description := raw.description
+ isDestructor := raw.type == .destructor
+ since := raw.since
+ deprecatedSince := raw.deprecatedSince
+ arguments := ← otherArgs.mapM processArgument
+ returnType := returnType
+ }
+
+private def processEvent (raw : Raw.MessageDesc) : Processor Client.EventDesc := do
+ return {
+ name := raw.name
+ opcode := raw.opcode
+ description := raw.description
+ isDestructor := raw.type == .destructor
+ since := raw.since
+ deprecatedSince := raw.deprecatedSince
+ arguments := ← raw.arguments.mapM processArgument
+ }
+
+private def processInterface (raw : Raw.InterfaceDesc) : Processor Client.InterfaceDesc := do
+ return {
+ name := raw.name
+ version := raw.version
+ description := raw.description
+ enums := ← raw.enums.mapM processEnum
+ requests := ← raw.requests.mapM processRequest
+ events := ← raw.events.mapM processEvent
+ }
+
+private def processProtocol (interfaces : InterfaceMap) (raw : Raw.ProtocolDesc) : Except String Client.ProtocolDesc := do
+ return {
+ name := raw.name
+ copyright := raw.copyright
+ description := raw.description
+ interfaces := ← raw.interfaces.mapM
+ fun iface ↦ (processInterface iface).run {
+ interfaces := interfaces
+ currentInterface := iface.name
+ }
+ }
+
+def processProtocols (raw : Array Raw.ProtocolDesc) : Except String (Array Client.ProtocolDesc) :=
+ let interfaces : InterfaceMap := .ofArray <| raw.flatMap
+ fun protocol ↦ protocol.interfaces.map
+ fun iface ↦ (iface.name, (⟨protocol.name, iface.enums.map Raw.EnumDesc.name⟩ : InterfaceInfo))
+ raw.mapM (processProtocol interfaces)
+
+end WaylandScanner