complete and total overhaul like i promised. things are much easier to reason about. still not working yet though.

This commit is contained in:
Andrew Gallant (Ocelot)
2012-04-30 02:40:55 -04:00
parent 3115c13e88
commit 05d8ec6a16
13 changed files with 1777 additions and 787 deletions

View File

@@ -4,7 +4,6 @@ import (
"encoding/xml"
"io/ioutil"
"log"
"time"
)
type XML struct {
@@ -18,231 +17,25 @@ type XML struct {
// 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"`
Imports XMLImports `xml:"import"`
Enums XMLEnums `xml:"enum"`
Xids XMLXids `xml:"xidtype"`
XidUnions XMLXids `xml:"xidunion"`
TypeDefs XMLTypeDefs `xml:"typedef"`
EventCopies XMLEventCopies `xml:"eventcopy"`
ErrorCopies XMLErrorCopies `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"`
Structs XMLStructs `xml:"struct"`
Unions XMLUnions `xml:"union"`
Requests XMLRequests `xml:"request"`
Events XMLEvents `xml:"event"`
Errors XMLErrors `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("")
type XMLImports []*XMLImport
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.Errors.Morph(c)
c.Putln("")
x.ErrorCopies.Morph(c)
c.Putln("")
x.Events.Morph(c)
c.Putln("")
x.EventCopies.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
// Union returns the 'Union' struct corresponding to this type, if
// one exists.
func (typ Type) Union(c *Context) *Union {
// If this is a typedef, use that instead.
if oldTyp, ok := typ.TypeDef(c); ok {
return oldTyp.Union(c)
}
// Otherwise, just look for a union type with 'typ' name.
for _, union := range c.xml.Unions {
if typ == union.Name {
return union
}
}
for _, imp := range c.xml.Imports {
for _, union := range imp.xml.Unions {
if typ == union.Name {
return union
}
}
}
return nil
}
// TypeDef returns the 'old' type corresponding to this type, if it's found
// in a type def. If not found, the second return value is false.
func (typ Type) TypeDef(c *Context) (Type, bool) {
for _, typedef := range c.xml.TypeDefs {
if typ == typedef.New {
return typedef.Old, true
}
}
for _, imp := range c.xml.Imports {
for _, typedef := range imp.xml.TypeDefs {
if typ == typedef.New {
return typedef.Old, true
}
}
}
return "", false
}
// Size is a nifty function that takes any type and digs until it finds
// its underlying base type. At which point, the size can be determined.
func (typ Type) Size(c *Context) uint {
// If this is a base type, we're done.
if size, ok := BaseTypeSizes[string(typ)]; ok {
return size
}
// If it's a resource, we're also done.
if c.xml.IsResource(typ) {
return BaseTypeSizes["Id"]
}
// It's not, so that implies there is *some* typedef declaring it
// in terms of another type. Just follow that chain until we get to
// a base type. We also need to check imported stuff.
for _, typedef := range c.xml.TypeDefs {
if typ == typedef.New {
return typedef.Old.Size(c)
}
}
for _, imp := range c.xml.Imports {
for _, typedef := range imp.xml.TypeDefs {
if typ == typedef.New {
return typedef.Old.Size(c)
}
}
}
log.Panicf("Could not find base size of type '%s'.", typ)
panic("unreachable")
}
type Imports []*Import
func (imports Imports) Eval() {
func (imports XMLImports) Eval() {
for _, imp := range imports {
xmlBytes, err := ioutil.ReadFile(*protoPath + "/" + imp.Name + ".xml")
if err != nil {
@@ -256,117 +49,101 @@ func (imports Imports) Eval() {
log.Fatal("Could not parse X protocol description for import " +
"'%s' because: %s", imp.Name, err)
}
// recursive imports...
imp.xml.Imports.Eval()
}
}
type Import struct {
type XMLImport struct {
Name string `xml:",chardata"`
xml *XML `xml:"-"`
}
type Enums []Enum
type XMLEnums []XMLEnum
// 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 XMLEnum struct {
Name string `xml:"name,attr"`
Items []*XMLEnumItem `xml:"item"`
}
type Enum struct {
Name Type `xml:"name,attr"`
Items []*EnumItem `xml:"item"`
type XMLEnumItem struct {
Name string `xml:"name,attr"`
Expr *XMLExpression `xml:",any"`
}
type EnumItem struct {
Name Name `xml:"name,attr"`
Expr *Expression `xml:",any"`
}
type XMLXids []*XMLXid
type Xids []*Xid
type Xid struct {
type XMLXid struct {
XMLName xml.Name
Name Type `xml:"name,attr"`
Name string `xml:"name,attr"`
}
type TypeDefs []*TypeDef
type XMLTypeDefs []*XMLTypeDef
type TypeDef struct {
Old Type `xml:"oldname,attr"`
New Type `xml:"newname,attr"`
type XMLTypeDef struct {
Old string `xml:"oldname,attr"`
New string `xml:"newname,attr"`
}
type EventCopies []*EventCopy
type XMLEventCopies []*XMLEventCopy
type EventCopy struct {
Name Type `xml:"name,attr"`
type XMLEventCopy struct {
Name string `xml:"name,attr"`
Number int `xml:"number,attr"`
Ref Type `xml:"ref,attr"`
Ref string `xml:"ref,attr"`
}
type ErrorCopies []*ErrorCopy
type XMLErrorCopies []*XMLErrorCopy
type ErrorCopy struct {
Name Type `xml:"name,attr"`
type XMLErrorCopy struct {
Name string `xml:"name,attr"`
Number int `xml:"number,attr"`
Ref Type `xml:"ref,attr"`
Ref string `xml:"ref,attr"`
}
type Structs []*Struct
type XMLStructs []*XMLStruct
type Struct struct {
Name Type `xml:"name,attr"`
Fields Fields `xml:",any"`
type XMLStruct struct {
Name string `xml:"name,attr"`
Fields XMLFields `xml:",any"`
}
type Unions []*Union
type XMLUnions []*XMLUnion
type Union struct {
Name Type `xml:"name,attr"`
Fields Fields `xml:",any"`
type XMLUnion struct {
Name string `xml:"name,attr"`
Fields XMLFields `xml:",any"`
}
type Requests []*Request
type XMLRequests []*XMLRequest
type Request struct {
Name Type `xml:"name,attr"`
type XMLRequest struct {
Name string `xml:"name,attr"`
Opcode int `xml:"opcode,attr"`
Combine bool `xml:"combine-adjacent,attr"`
Fields Fields `xml:",any"`
Reply *Reply `xml:"reply"`
Fields XMLFields `xml:",any"`
Reply *XMLReply `xml:"reply"`
}
type Reply struct {
Fields Fields `xml:",any"`
type XMLReply struct {
Fields XMLFields `xml:",any"`
}
type Events []*Event
type XMLEvents []*XMLEvent
type Event struct {
Name Type `xml:"name,attr"`
type XMLEvent struct {
Name string `xml:"name,attr"`
Number int `xml:"number,attr"`
NoSequence bool `xml:"no-sequence-number,true"`
Fields Fields `xml:",any"`
Fields XMLFields `xml:",any"`
}
type Errors []*Error
type XMLErrors []*XMLError
type Error struct {
Name Type `xml:"name,attr"`
type XMLError struct {
Name string `xml:"name,attr"`
Number int `xml:"number,attr"`
Fields Fields `xml:",any"`
Fields XMLFields `xml:",any"`
}