haven/nexgb/xgbgen/xml.go

299 lines
5.7 KiB
Go

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"`
}