diff options
Diffstat (limited to 'nexgb/xgbgen/xml.go')
-rw-r--r-- | nexgb/xgbgen/xml.go | 298 |
1 files changed, 298 insertions, 0 deletions
diff --git a/nexgb/xgbgen/xml.go b/nexgb/xgbgen/xml.go new file mode 100644 index 0000000..0f632b4 --- /dev/null +++ b/nexgb/xgbgen/xml.go @@ -0,0 +1,298 @@ +package main + +import ( + "encoding/xml" + "io/ioutil" + "log" + "time" +) + +type XML struct { + // Root 'xcb' element properties. + XMLName xml.Name `xml:"xcb"` + Header string `xml:"header,attr"` + ExtensionXName string `xml:"extension-xname,attr"` + ExtensionName string `xml:"extension-name,attr"` + MajorVersion string `xml:"major-version,attr"` + MinorVersion string `xml:"minor-version,attr"` + + // Types for all top-level elements. + // First are the simple ones. + Imports Imports `xml:"import"` + Enums Enums `xml:"enum"` + Xids Xids `xml:"xidtype"` + XidUnions Xids `xml:"xidunion"` + TypeDefs TypeDefs `xml:"typedef"` + EventCopies EventCopies `xml:"eventcopy"` + ErrorCopies ErrorCopies `xml:"errorcopy"` + + // Here are the complex ones, i.e., anything with "structure contents" + Structs Structs `xml:"struct"` + Unions Unions `xml:"union"` + Requests Requests `xml:"request"` + Events Events `xml:"event"` + Errors Errors `xml:"error"` +} + +// Morph cascades down all of the XML and calls each type's corresponding +// Morph function with itself as an argument (the context). +func (x *XML) Morph(c *Context) { + // Start the header... + c.Putln("package xgb") + c.Putln("/*") + c.Putln("\tX protocol API for '%s.xml'.", c.xml.Header) + c.Putln("\tThis file is automatically generated. Edit at your own peril!") + c.Putln("\tGenerated on %s", + time.Now().Format("Jan 2, 2006 at 3:04:05pm MST")) + c.Putln("*/") + c.Putln("") + + x.Imports.Morph(c) + c.Putln("") + + x.Enums.Morph(c) + c.Putln("") + + x.Xids.Morph(c) + c.Putln("") + + x.XidUnions.Morph(c) + c.Putln("") + + x.TypeDefs.Morph(c) + c.Putln("") + + x.Structs.Morph(c) + c.Putln("") + + x.Unions.Morph(c) + c.Putln("") + + x.Requests.Morph(c) + c.Putln("") + + x.Events.Morph(c) + c.Putln("") + + x.Errors.Morph(c) + c.Putln("") + + x.EventCopies.Morph(c) + c.Putln("") + + x.ErrorCopies.Morph(c) + c.Putln("") +} + +// IsResource returns true if the 'needle' type is a resource type. +// i.e., an "xid" +func (x *XML) IsResource(needle Type) bool { + for _, xid := range x.Xids { + if needle == xid.Name { + return true + } + } + for _, xidunion := range x.XidUnions { + if needle == xidunion.Name { + return true + } + } + for _, imp := range x.Imports { + if imp.xml.IsResource(needle) { + return true + } + } + return false +} + +// HasType returns true if the 'needle' type can be found in the protocol +// description represented by 'x'. +func (x *XML) HasType(needle Type) bool { + for _, enum := range x.Enums { + if needle == enum.Name { + return true + } + } + for _, xid := range x.Xids { + if needle == xid.Name { + return true + } + } + for _, xidunion := range x.XidUnions { + if needle == xidunion.Name { + return true + } + } + for _, typedef := range x.TypeDefs { + if needle == typedef.New { + return true + } + } + for _, evcopy := range x.EventCopies { + if needle == evcopy.Name { + return true + } + } + for _, errcopy := range x.ErrorCopies { + if needle == errcopy.Name { + return true + } + } + for _, strct := range x.Structs { + if needle == strct.Name { + return true + } + } + for _, union := range x.Unions { + if needle == union.Name { + return true + } + } + for _, ev := range x.Events { + if needle == ev.Name { + return true + } + } + for _, err := range x.Errors { + if needle == err.Name { + return true + } + } + + return false +} + +type Name string + +type Type string + +type Imports []*Import + +func (imports Imports) Eval() { + for _, imp := range imports { + xmlBytes, err := ioutil.ReadFile(*protoPath + "/" + imp.Name + ".xml") + if err != nil { + log.Fatalf("Could not read X protocol description for import " + + "'%s' because: %s", imp.Name, err) + } + + imp.xml = &XML{} + err = xml.Unmarshal(xmlBytes, imp.xml) + if err != nil { + log.Fatal("Could not parse X protocol description for import " + + "'%s' because: %s", imp.Name, err) + } + } +} + +type Import struct { + Name string `xml:",chardata"` + xml *XML `xml:"-"` +} + +type Enums []Enum + +// Eval on the list of all enum types goes through and forces every enum +// item to have a valid expression. +// This is necessary because when an item is empty, it is defined to have +// the value of "one more than that of the previous item, or 0 for the first +// item". +func (enums Enums) Eval() { + for _, enum := range enums { + nextValue := uint(0) + for _, item := range enum.Items { + if item.Expr == nil { + item.Expr = newValueExpression(nextValue) + nextValue++ + } else { + nextValue = item.Expr.Eval() + 1 + } + } + } +} + +type Enum struct { + Name Type `xml:"name,attr"` + Items []*EnumItem `xml:"item"` +} + +type EnumItem struct { + Name Name `xml:"name,attr"` + Expr *Expression `xml:",any"` +} + +type Xids []*Xid + +type Xid struct { + XMLName xml.Name + Name Type `xml:"name,attr"` +} + +type TypeDefs []*TypeDef + +type TypeDef struct { + Old Type `xml:"oldname,attr"` + New Type `xml:"newname,attr"` +} + +type EventCopies []*EventCopy + +type EventCopy struct { + Name Type `xml:"name,attr"` + Number string `xml:"number,attr"` + Ref Type `xml:"ref,attr"` +} + +type ErrorCopies []*ErrorCopy + +type ErrorCopy struct { + Name Type `xml:"name,attr"` + Number string `xml:"number,attr"` + Ref Type `xml:"ref,attr"` +} + +type Structs []*Struct + +type Struct struct { + Name Type `xml:"name,attr"` + Fields []*Field `xml:",any"` +} + +type Unions []*Union + +type Union struct { + Name Type `xml:"name,attr"` + Fields []*Field `xml:",any"` +} + +type Requests []*Request + +type Request struct { + Name Type `xml:"name,attr"` + Opcode int `xml:"opcode,attr"` + Combine bool `xml:"combine-adjacent,attr"` + Fields []*Field `xml:",any"` + Reply *Reply `xml:"reply"` +} + +type Reply struct { + Fields []*Field `xml:",any"` +} + +type Events []*Event + +type Event struct { + Name Type `xml:"name,attr"` + Number int `xml:"number,attr"` + NoSequence bool `xml:"no-sequence-number,true"` + Fields []*Field `xml:",any"` +} + +type Errors []*Error + +type Error struct { + Name Type `xml:"name,attr"` + Number int `xml:"number,attr"` + Fields []*Field `xml:",any"` +} + |