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

@ -8,13 +8,12 @@ import (
)
type Context struct {
xml *XML
protocol *Protocol
out *bytes.Buffer
}
func newContext() *Context {
return &Context{
xml: &XML{},
out: bytes.NewBuffer([]byte{}),
}
}
@ -32,22 +31,24 @@ func (c *Context) Put(format string, v ...interface{}) {
}
}
// Translate is the big daddy of them all. It takes in an XML byte slice
// Morph is the big daddy of them all. It takes in an XML byte slice,
// parse it, transforms the XML types into more usable types,
// and writes Go code to the 'out' buffer.
func (c *Context) Translate(xmlBytes []byte) {
err := xml.Unmarshal(xmlBytes, c.xml)
func (c *Context) Morph(xmlBytes []byte) {
parsedXml := &XML{}
err := xml.Unmarshal(xmlBytes, parsedXml)
if err != nil {
log.Fatal(err)
}
// Parse all imports
c.xml.Imports.Eval()
parsedXml.Imports.Eval()
// Make sure all top level enumerations have expressions
// (For when there are empty items.)
c.xml.Enums.Eval()
// Translate XML types to nice types
c.protocol = parsedXml.Translate()
// It's Morphin' Time!
c.xml.Morph(c)
// Now write Go source code
for _, typ := range c.protocol.Types {
typ.Define(c)
}
}

276
nexgb/xgbgen/expression.go Normal file
View File

@ -0,0 +1,276 @@
package main
import (
"fmt"
"log"
)
type Expression interface {
Concrete() bool
Eval() uint
Reduce(prefix, fun string) string
String() string
Initialize(p *Protocol)
}
type BinaryOp struct {
Op string
Expr1 Expression
Expr2 Expression
}
func newBinaryOp(op string, expr1, expr2 Expression) Expression {
switch {
case expr1 != nil && expr2 != nil:
return &BinaryOp{
Op: op,
Expr1: expr1,
Expr2: expr2,
}
case expr1 != nil && expr2 == nil:
return expr1
case expr1 == nil && expr2 != nil:
return expr2
case expr1 == nil && expr2 == nil:
return nil
}
panic("unreachable")
}
func (e *BinaryOp) Concrete() bool {
return e.Expr1.Concrete() && e.Expr2.Concrete()
}
func (e *BinaryOp) Eval() uint {
switch e.Op {
case "+":
return e.Expr1.Eval() + e.Expr2.Eval()
case "-":
return e.Expr1.Eval() - e.Expr2.Eval()
case "*":
return e.Expr1.Eval() * e.Expr2.Eval()
case "/":
return e.Expr1.Eval() / e.Expr2.Eval()
case "&":
return e.Expr1.Eval() & e.Expr2.Eval()
case "<<":
return e.Expr1.Eval() << e.Expr2.Eval()
}
log.Fatalf("Invalid binary operator '%s' for expression.", e.Op)
panic("unreachable")
}
func (e *BinaryOp) Reduce(prefix, fun string) string {
if e.Concrete() {
return fmt.Sprintf("%d", e.Eval())
}
return fmt.Sprintf("(%s %s %s)",
e.Expr1.Reduce(prefix, fun), e.Op, e.Expr2.Reduce(prefix, fun))
}
func (e *BinaryOp) String() string {
return e.Reduce("", "")
}
func (e *BinaryOp) Initialize(p *Protocol) {
e.Expr1.Initialize(p)
e.Expr2.Initialize(p)
}
type UnaryOp struct {
Op string
Expr Expression
}
func (e *UnaryOp) Concrete() bool {
return e.Expr.Concrete()
}
func (e *UnaryOp) Eval() uint {
switch e.Op {
case "~":
return ^e.Expr.Eval()
}
log.Fatalf("Invalid unary operator '%s' for expression.", e.Op)
panic("unreachable")
}
func (e *UnaryOp) Reduce(prefix, fun string) string {
if e.Concrete() {
return fmt.Sprintf("%d", e.Eval())
}
return fmt.Sprintf("(%s (%s))", e.Op, e.Expr.Reduce(prefix, fun))
}
func (e *UnaryOp) String() string {
return e.Reduce("", "")
}
func (e *UnaryOp) Initialize(p *Protocol) {
e.Expr.Initialize(p)
}
type PopCount struct {
Expr Expression
}
func (e *PopCount) Concrete() bool {
return e.Expr.Concrete()
}
func (e *PopCount) Eval() uint {
return popCount(e.Expr.Eval())
}
func (e *PopCount) Reduce(prefix, fun string) string {
if e.Concrete() {
return fmt.Sprintf("%d", e.Eval())
}
return fmt.Sprintf("popCount(%s)", e.Expr.Reduce(prefix, fun))
}
func (e *PopCount) String() string {
return e.Reduce("", "")
}
func (e *PopCount) Initialize(p *Protocol) {
e.Expr.Initialize(p)
}
type Value struct {
v uint
}
func (e *Value) Concrete() bool {
return true
}
func (e *Value) Eval() uint {
return e.v
}
func (e *Value) Reduce(prefix, fun string) string {
return fmt.Sprintf("%d", e.v)
}
func (e *Value) String() string {
return e.Reduce("", "")
}
func (e *Value) Initialize(p *Protocol) { }
type Bit struct {
b uint
}
func (e *Bit) Concrete() bool {
return true
}
func (e *Bit) Eval() uint {
return 1 << e.b
}
func (e *Bit) Reduce(prefix, fun string) string {
return fmt.Sprintf("%d", e.Eval())
}
func (e *Bit) String() string {
return e.Reduce("", "")
}
func (e *Bit) Initialize(p *Protocol) { }
type FieldRef struct {
Name string
}
func (e *FieldRef) Concrete() bool {
return false
}
func (e *FieldRef) Eval() uint {
log.Fatalf("Cannot evaluate a 'FieldRef'. It is not concrete.")
panic("unreachable")
}
func (e *FieldRef) Reduce(prefix, fun string) string {
val := e.Name
if len(prefix) > 0 {
val = fmt.Sprintf("%s%s", prefix, val)
}
if len(fun) > 0 {
val = fmt.Sprintf("%s(%s)", fun, val)
}
return val
}
func (e *FieldRef) String() string {
return e.Reduce("", "")
}
func (e *FieldRef) Initialize(p *Protocol) {
e.Name = SrcName(e.Name)
}
type EnumRef struct {
EnumKind Type
EnumItem string
}
func (e *EnumRef) Concrete() bool {
return false
}
func (e *EnumRef) Eval() uint {
log.Fatalf("Cannot evaluate an 'EnumRef'. It is not concrete.")
panic("unreachable")
}
func (e *EnumRef) Reduce(prefix, fun string) string {
val := fmt.Sprintf("%s%s", e.EnumKind, e.EnumItem)
if len(fun) > 0 {
val = fmt.Sprintf("%s(%s)", fun, val)
}
return val
}
func (e *EnumRef) String() string {
return e.Reduce("", "")
}
func (e *EnumRef) Initialize(p *Protocol) {
e.EnumKind = e.EnumKind.(*Translation).RealType(p)
e.EnumItem = SrcName(e.EnumItem)
}
type SumOf struct {
Name string
}
func (e *SumOf) Concrete() bool {
return false
}
func (e *SumOf) Eval() uint {
log.Fatalf("Cannot evaluate a 'SumOf'. It is not concrete.")
panic("unreachable")
}
func (e *SumOf) Reduce(prefix, fun string) string {
if len(prefix) > 0 {
return fmt.Sprintf("sum(%s%s)", prefix, e.Name)
}
return fmt.Sprintf("sum(%s)", e.Name)
}
func (e *SumOf) String() string {
return e.Reduce("", "")
}
func (e *SumOf) Initialize(p *Protocol) {
e.Name = SrcName(e.Name)
}

170
nexgb/xgbgen/field.go Normal file
View File

@ -0,0 +1,170 @@
package main
type Field interface {
Initialize(p *Protocol)
SrcName() string
XmlName() string
Size() Size
Define(c *Context)
Read(c *Context)
}
func (pad *PadField) Initialize(p *Protocol) {}
type PadField struct {
Bytes uint
}
func (p *PadField) SrcName() string {
panic("illegal to take source name of a pad field")
}
func (p *PadField) XmlName() string {
panic("illegal to take XML name of a pad field")
}
func (p *PadField) Size() Size {
return newFixedSize(p.Bytes)
}
type SingleField struct {
srcName string
xmlName string
Type Type
}
func (f *SingleField) Initialize(p *Protocol) {
f.srcName = SrcName(f.XmlName())
f.Type = f.Type.(*Translation).RealType(p)
}
func (f *SingleField) SrcName() string {
return f.srcName
}
func (f *SingleField) XmlName() string {
return f.xmlName
}
func (f *SingleField) Size() Size {
return f.Type.Size()
}
type ListField struct {
srcName string
xmlName string
Type Type
LengthExpr Expression
}
func (f *ListField) SrcName() string {
return f.srcName
}
func (f *ListField) XmlName() string {
return f.xmlName
}
func (f *ListField) Size() Size {
return newExpressionSize(f.LengthExpr).Multiply(f.Type.Size())
}
func (f *ListField) Initialize(p *Protocol) {
f.srcName = SrcName(f.XmlName())
f.Type = f.Type.(*Translation).RealType(p)
if f.LengthExpr != nil {
f.LengthExpr.Initialize(p)
}
}
type LocalField struct {
*SingleField
}
type ExprField struct {
srcName string
xmlName string
Type Type
Expr Expression
}
func (f *ExprField) SrcName() string {
return f.srcName
}
func (f *ExprField) XmlName() string {
return f.xmlName
}
func (f *ExprField) Size() Size {
return f.Type.Size()
}
func (f *ExprField) Initialize(p *Protocol) {
f.srcName = SrcName(f.XmlName())
f.Type = f.Type.(*Translation).RealType(p)
f.Expr.Initialize(p)
}
type ValueField struct {
MaskType Type
MaskName string
ListName string
}
func (f *ValueField) SrcName() string {
panic("it is illegal to call SrcName on a ValueField field")
}
func (f *ValueField) XmlName() string {
panic("it is illegal to call XmlName on a ValueField field")
}
func (f *ValueField) Size() Size {
return f.MaskType.Size()
}
func (f *ValueField) Initialize(p *Protocol) {
f.MaskType = f.MaskType.(*Translation).RealType(p)
f.MaskName = SrcName(f.MaskName)
f.ListName = SrcName(f.ListName)
}
type SwitchField struct {
Name string
Expr Expression
Bitcases []*Bitcase
}
func (f *SwitchField) SrcName() string {
panic("it is illegal to call SrcName on a SwitchField field")
}
func (f *SwitchField) XmlName() string {
panic("it is illegal to call XmlName on a SwitchField field")
}
// XXX: This is a bit tricky. The size has to be represented as a non-concrete
// expression that finds *which* bitcase fields are included, and sums the
// sizes of those fields.
func (f *SwitchField) Size() Size {
return newFixedSize(0)
}
func (f *SwitchField) Initialize(p *Protocol) {
f.Name = SrcName(f.Name)
f.Expr.Initialize(p)
for _, bitcase := range f.Bitcases {
bitcase.Expr.Initialize(p)
for _, field := range bitcase.Fields {
field.Initialize(p)
}
}
}
type Bitcase struct {
Fields []Field
Expr Expression
}

View File

@ -1,36 +1,13 @@
package main
/*
To the best of my ability, these are all of the Go specific formatting
functions. If I've designed xgbgen correctly, this should be only the
place that you change things to generate code for a new language.
This file is organized as follows:
* Imports and helper variables.
* Manual type and name override maps.
* Constants for tweaking various morphing functions.
* Helper morphing functions.
* Morphing functions for each "sub-unit."
* Morphing functions for each "unit".
* Morphing functions for collections of "units".
Units can be thought of as the top-level elements in an XML protocol
description file. Namely, structs, xidtypes, imports, enums, unions, etc.
Collections of units are simply "all of the UNIT in the XML file."
Sub-units can be thought of as recurring bits like struct contents (which
is used in events, replies, requests, errors, etc.) and expression
evaluation.
*/
import (
"fmt"
"log"
"strings"
)
/******************************************************************************/
// Manual type and name overrides.
/******************************************************************************/
// xgbResourceIdName is the name of the type used for all resource identifiers.
// As of right now, it needs to be declared somewhere manually.
var xgbGenResourceIdName = "Id"
// BaseTypeMap is a map from X base types to Go types.
// X base types should correspond to the smallest set of X types
@ -50,6 +27,8 @@ var BaseTypeMap = map[string]string{
"float": "float64",
"double": "float64",
"char": "byte",
"void": "byte",
"Id": "Id",
}
// BaseTypeSizes should have precisely the same keys as in BaseTypeMap,
@ -66,6 +45,7 @@ var BaseTypeSizes = map[string]uint{
"float": 4,
"double": 8,
"char": 1,
"void": 1,
"Id": 4,
}
@ -82,483 +62,350 @@ var TypeMap = map[string]string{
// NameMap is the same as TypeMap, but for names.
var NameMap = map[string]string{ }
/******************************************************************************/
// Constants for changing the semantics of morphing functions.
// These are mainly used to tweaking the writing of fields.
// Namely, reading/writing is not exactly the same across events,
// requests/replies and errors.
/******************************************************************************/
const (
FieldsEvent = iota
FieldsRequestReply
FieldsError
)
// Reading, writing and defining...
/******************************************************************************/
// Helper functions that aide in morphing repetitive constructs.
// i.e., type and identifier names, etc.
/******************************************************************************/
// Morph changes every TYPE (not names) into something suitable
// for your language. It also handles adding suffixes like 'Event'
// and 'Union'. (A 'Union' suffix is used in Go because unions aren't
// supported at the language level.)
func (typ Type) Morph(c *Context) string {
t := string(typ)
// If this is a base type, then write the raw Go type.
if newt, ok := BaseTypeMap[t]; ok {
return newt
}
// If it's in the type map, use that translation.
if newt, ok := TypeMap[t]; ok {
return newt
}
// If it's a resource type, just use 'Id'.
if c.xml.IsResource(typ) {
return "Id"
}
// If there's a namespace to this type, just use it and be done.
if colon := strings.Index(t, ":"); colon > -1 {
namespace := t[:colon]
rest := t[colon+1:]
return splitAndTitle(namespace) + splitAndTitle(rest)
}
// Since there is no namespace, we need to look for a namespace
// in the current context.
return typ.Prefix(c) + splitAndTitle(t)
}
// Prefix searches the parsed XML for a type matching 'typ'.
// It then returns the appropriate prefix to be used in source code.
// Note that the core X protocol *is* a namespace, but does not have a prefix.
// Also note that you should probably check the BaseTypeMap and TypeMap
// before calling this function.
func (typ Type) Prefix(c *Context) string {
// If this is xproto, quit. No prefixes needed.
if c.xml.Header == "xproto" {
return ""
}
// First check for the type in the current namespace.
if c.xml.HasType(typ) {
return strings.Title(c.xml.Header)
}
// Now check each of the imports...
for _, imp := range c.xml.Imports {
if imp.xml.Header != "xproto" && imp.xml.HasType(typ) {
return strings.Title(imp.xml.Header)
}
}
return ""
}
// Morph changes every identifier (NOT type) into something suitable
// for your language.
func (name Name) Morph(c *Context) string {
n := string(name)
// If it's in the name map, use that translation.
if newn, ok := NameMap[n]; ok {
return newn
}
return splitAndTitle(n)
}
/******************************************************************************/
// Sub-unit morphing.
// Below are functions that morph sub-units. Like collections of fields,
// expressions, etc.
// Note that collections of fields can be used in three different contexts:
// definitions, reading from the wire and writing to the wire. Thus, there
// exists 'MorphDefine', 'MorphRead', 'MorphWrite' defined on Fields.
/******************************************************************************/
func (fields Fields) MorphDefine(c *Context) {
for _, field := range fields {
field.MorphDefine(c)
}
}
func (field *Field) MorphDefine(c *Context) {
// We omit 'pad' and 'exprfield'
switch field.XMLName.Local {
case "field":
c.Putln("%s %s", field.Name.Morph(c), field.Type.Morph(c))
case "list":
c.Putln("%s []%s", field.Name.Morph(c), field.Type.Morph(c))
case "localfield":
c.Putln("%s %s", field.Name.Morph(c), field.Type.Morph(c))
case "valueparam":
c.Putln("%s %s", field.ValueMaskName.Morph(c),
field.ValueMaskType.Morph(c))
c.Putln("%s []%s", field.ValueListName.Morph(c),
field.ValueMaskType.Morph(c))
case "switch":
field.Bitcases.MorphDefine(c)
}
}
func (bitcases Bitcases) MorphDefine(c *Context) {
for _, bitcase := range bitcases {
bitcase.MorphDefine(c)
}
}
func (bitcase *Bitcase) MorphDefine(c *Context) {
bitcase.Fields.MorphDefine(c)
}
func (fields Fields) MorphRead(c *Context, kind int, evNoSeq bool,
prefix string, byt uint) uint {
nextByte := byt
for _, field := range fields {
nextByte = field.MorphRead(c, kind, nextByte, prefix)
switch kind {
case FieldsEvent:
// Skip the sequence id
if !evNoSeq && (nextByte == 2 || nextByte == 3) {
nextByte = 4
}
}
}
return nextByte
}
func (field *Field) MorphRead(c *Context, kind int, byt uint,
prefix string) uint {
nextByte := byt
switch field.XMLName.Local {
case "pad":
nextByte += uint(field.Bytes)
case "field":
nextByte = field.MorphReadField(c, kind, nextByte, prefix)
case "list":
typ := field.Type.Morph(c)
// Create a temporary Field so we can use MorphReadField.
// temp := &Field{
// XMLName: xml.Name{Local: "field"},
// Name: field.Name,
// Type: field.Type,
// }
// Special case: if the list is just raw bytes, use copy!
if typ == "byte" {
c.Putln("copy(%s%s, buf[%d:])", prefix, field.Name.Morph(c),
byt)
nextByte = byt + 20
} else {
c.Putln("//list!")
}
}
return nextByte
}
func (field *Field) MorphReadField(c *Context, kind int, byt uint,
prefix string) uint {
if union := field.Type.Union(c); union != nil {
c.Putln("")
c.Putln("%s%s = %s{}", prefix, field.Name.Morph(c), field.Type.Morph(c))
union.Fields.MorphRead(c, kind, false,
fmt.Sprintf("%s%s.", prefix, field.Name.Morph(c)), byt)
c.Putln("")
return byt
}
size := field.Type.Size(c)
typ := field.Type.Morph(c)
name := field.Name.Morph(c)
_, isBase := BaseTypeMap[string(field.Type)]
c.Put("%s%s = ", prefix, name)
if !isBase {
c.Put("%s(", typ)
}
switch size {
case 1: c.Put("buf[%d]", byt)
case 2: c.Put("get16(buf[%d:])", byt)
case 4: c.Put("get32(buf[%d:])", byt)
case 8: c.Put("get64(buf[%d:])", byt)
default:
log.Fatalf("Unsupported field size '%d' for field '%s'.",
size, field)
}
if !isBase {
c.Put(")")
}
// Base types
func (b *Base) Define(c *Context) {
c.Putln("// Skipping definition for base type '%s'", SrcName(b.XmlName()))
c.Putln("")
return byt + size
}
func (fields Fields) MorphWrite(c *Context, kind int) {
var nextByte uint
switch kind {
case FieldsEvent:
nextByte = 1
}
for _, field := range fields {
nextByte = field.MorphWrite(c, kind, nextByte)
}
}
func (field *Field) MorphWrite(c *Context, kind int, byt uint) uint {
consumed := uint(0)
switch field.XMLName.Local {
case "pad":
consumed = uint(field.Bytes)
case "field":
size := field.Type.Size(c)
typ := field.Type.Morph(c)
name := field.Name.Morph(c)
switch size {
case 1:
c.Putln("v.%s = %s(buf[%d])", name, typ, byt)
case 2:
c.Putln("v.%s = %s(get16(buf[%d:]))", name, typ, byt)
case 4:
c.Putln("v.%s = %s(get32(buf[%d:]))", name, typ, byt)
case 8:
c.Putln("v.%s = %s(get64(buf[%d:]))", name, typ, byt)
}
consumed = size
case "list":
c.Putln("IDK")
}
return byt + consumed
}
/******************************************************************************/
// Per element morphing.
// Below are functions that morph a single unit.
/******************************************************************************/
// Import morphing.
func (imp *Import) Morph(c *Context) {
c.Putln("// import \"%s\"", imp.Name)
}
// Enum morphing.
func (enum *Enum) Morph(c *Context) {
// Enum types
func (enum *Enum) Define(c *Context) {
c.Putln("const (")
for _, item := range enum.Items {
c.Putln("%s%s = %d", enum.Name.Morph(c), item.Name.Morph(c),
item.Expr.Eval())
c.Putln("%s%s = %d", enum.SrcName(), item.srcName, item.Expr.Eval())
}
c.Putln(")\n")
}
// Xid morphing.
func (xid *Xid) Morph(c *Context) {
// Don't emit anything for xid types for now.
// We're going to force them all to simply be 'Id'
// to avoid excessive type converting.
// c.Putln("type %s Id", xid.Name.Morph(c))
}
// TypeDef morphing.
func (typedef *TypeDef) Morph(c *Context) {
c.Putln("type %s %s", typedef.New.Morph(c), typedef.Old.Morph(c))
}
// Struct morphing.
func (strct *Struct) Morph(c *Context) {
c.Putln("type %s struct {", strct.Name.Morph(c))
strct.Fields.MorphDefine(c)
c.Putln("}")
c.Putln("\n")
}
// Union morphing.
func (union *Union) Morph(c *Context) {
c.Putln("type %s struct {", union.Name.Morph(c))
union.Fields.MorphDefine(c)
c.Putln("}")
c.Putln("\n")
}
// Request morphing.
func (request *Request) Morph(c *Context) {
}
// Event morphing.
func (ev *Event) Morph(c *Context) {
name := ev.Name.Morph(c)
c.Putln("const %s = %d", name, ev.Number)
c.Putln(")")
c.Putln("")
c.Putln("type %sEvent struct {", name)
ev.Fields.MorphDefine(c)
}
// Resource types
func (res *Resource) Define(c *Context) {
c.Putln("// Skipping resource definition of '%s'", SrcName(res.XmlName()))
c.Putln("")
}
// TypeDef types
func (td *TypeDef) Define(c *Context) {
c.Putln("type %s %s", td.srcName, td.Old.SrcName())
c.Putln("")
}
// Struct types
func (s *Struct) Define(c *Context) {
c.Putln("// '%s' struct definition", s.SrcName())
c.Putln("// Size: %s", s.Size())
c.Putln("type %s struct {", s.SrcName())
for _, field := range s.Fields {
field.Define(c)
}
c.Putln("}")
c.Putln("")
c.Putln("func New%s(buf []byte) %sEvent {", name, name)
c.Putln("var v %sEvent", name)
ev.Fields.MorphRead(c, FieldsEvent, ev.NoSequence, "v.", 1)
c.Putln("return v")
// Write function that reads bytes and produces this struct.
s.Read(c)
// Write function that reads a list of this structs.
s.ReadList(c)
// Write function that writes bytes given this struct.
s.Write(c)
// Write function that writes a list of this struct.
s.WriteList(c)
}
// Read for a struct creates a function 'NewStructName' that takes a byte
// slice and produces TWO values: an instance of 'StructName' and the number
// of bytes read from the byte slice.
// 'NewStructName' should only be used to read raw reply data from the wire.
func (s *Struct) Read(c *Context) {
c.Putln("// Struct read %s", s.SrcName())
c.Putln("func New%s(buf []byte) (%s, int) {", s.SrcName(), s.SrcName())
c.Putln("v := %s{}", s.SrcName())
c.Putln("b := 0")
c.Putln("consumed := 0")
c.Putln("consumed = 0 + consumed // no-op") // dirty hack for a no-op
c.Putln("")
for _, field := range s.Fields {
field.Read(c)
}
c.Putln("return v, b")
c.Putln("}")
c.Putln("")
c.Putln("func (err %sEvent) ImplementsEvent() { }", name)
}
// ReadList for a struct creates a function 'ReadStructNameList' that takes
// a byte slice and a length and produces TWO values: an slice of StructName
// and the number of bytes read from the byte slice.
func (s *Struct) ReadList(c *Context) {
c.Putln("// Struct list read %s", s.SrcName())
c.Putln("func Read%sList(buf []byte, length int) ([]%s, int) {",
s.SrcName(), s.SrcName())
c.Putln("v := make([]%s, length)", s.SrcName())
c.Putln("b := 0")
c.Putln("consumed := 0")
c.Putln("consumed = 0 + consumed // no-op") // dirty hack for a no-op
c.Putln("for i := 0; i < length; i++ {")
c.Putln("v[i], consumed = New%s(buf[b:])", s.SrcName())
c.Putln("b += consumed")
c.Putln("}")
c.Putln("return v, pad(b)")
c.Putln("}")
c.Putln("")
c.Putln("func (ev %sEvent) Bytes() []byte {", name)
// ev.Fields.MorphWrite(c, FieldsEvent)
}
func (s *Struct) Write(c *Context) {
c.Putln("// Struct write %s", s.SrcName())
c.Putln("")
}
func (s *Struct) WriteList(c *Context) {
c.Putln("// Write struct list %s", s.SrcName())
c.Putln("")
}
// Union types
func (u *Union) Define(c *Context) {
c.Putln("// Union definition %s", u.SrcName())
}
func (u *Union) Read(c *Context, prefix string) {
c.Putln("// Union read %s", u.SrcName())
}
func (u *Union) Write(c *Context, prefix string) {
c.Putln("// Union write %s", u.SrcName())
}
// Event types
func (e *Event) Define(c *Context) {
c.Putln("// Event definition %s (%d)", e.SrcName(), e.Number)
}
func (e *Event) Read(c *Context, prefix string) {
c.Putln("// Event read %s", e.SrcName())
}
func (e *Event) Write(c *Context, prefix string) {
c.Putln("// Event write %s", e.SrcName())
}
// EventCopy types
func (e *EventCopy) Define(c *Context) {
c.Putln("// EventCopy definition %s (%d)", e.SrcName(), e.Number)
c.Putln("")
c.Putln("const %s = %d", e.SrcName(), e.Number)
c.Putln("")
c.Putln("type %s %s", e.EvType(), e.Old.(*Event).EvType())
c.Putln("")
c.Putln("func New%s(buf []byte) %s {", e.SrcName(), e.EvType())
c.Putln("return (%s)(New%s(buf))", e.EvType(), e.Old.SrcName())
c.Putln("}")
c.Putln("")
c.Putln("func (ev %s) ImplementsEvent() { }", e.EvType())
c.Putln("")
c.Putln("func (ev %s) Bytes() []byte {", e.EvType())
c.Putln("return (%s)(ev).Bytes()", e.Old.(*Event).EvType())
c.Putln("}")
c.Putln("")
c.Putln("func init() {")
c.Putln("newEventFuncs[%d] = New%s", ev.Number, name)
c.Putln("newEventFuncs[%d] = New%s", e.Number, e.SrcName())
c.Putln("}")
c.Putln("")
}
// EventCopy morphing.
func (evcopy *EventCopy) Morph(c *Context) {
oldName, newName := evcopy.Ref.Morph(c), evcopy.Name.Morph(c)
// Error types
func (e *Error) Define(c *Context) {
c.Putln("// Error definition %s (%d)", e.SrcName(), e.Number)
c.Putln("")
}
c.Putln("const %s = %d", newName, evcopy.Number)
func (e *Error) Read(c *Context, prefix string) {
c.Putln("// Error read %s", e.SrcName())
}
func (e *Error) Write(c *Context, prefix string) {
c.Putln("// Error write %s", e.SrcName())
}
// ErrorCopy types
func (e *ErrorCopy) Define(c *Context) {
c.Putln("// ErrorCopy definition %s (%d)", e.SrcName(), e.Number)
c.Putln("")
c.Putln("type %sEvent %sEvent", newName, oldName)
c.Putln("const %s = %d", e.ErrConst(), e.Number)
c.Putln("")
c.Putln("func New%s(buf []byte) %sEvent {", newName, newName)
c.Putln("return (%sEvent)(New%s(buf))", newName, oldName)
c.Putln("type %s %s", e.ErrType(), e.Old.(*Error).ErrType())
c.Putln("")
c.Putln("func New%s(buf []byte) %s {", e.SrcName(), e.ErrType())
c.Putln("return (%s)(New%s(buf))", e.ErrType(), e.Old.SrcName())
c.Putln("}")
c.Putln("")
c.Putln("func (err %sEvent) ImplementsEvent() { }", newName)
c.Putln("func (err %s) ImplementsError() { }", e.ErrType())
c.Putln("")
c.Putln("func (ev %sEvent) Bytes() []byte {", newName)
c.Putln("return (%sEvent)(ev).Bytes()", oldName)
c.Putln("func (err %s) Bytes() []byte {", e.ErrType())
c.Putln("return (%s)(err).Bytes()", e.Old.(*Error).ErrType())
c.Putln("}")
c.Putln("")
c.Putln("func init() {")
c.Putln("newEventFuncs[%d] = New%s", evcopy.Number, newName)
c.Putln("newErrorFuncs[%d] = New%s", e.Number, e.SrcName())
c.Putln("}")
c.Putln("")
}
// Error morphing.
func (err *Error) Morph(c *Context) {
// Field definitions, reads and writes.
// Pad fields
func (f *PadField) Define(c *Context) {
c.Putln("// padding: %d bytes", f.Bytes)
}
// ErrorCopy morphing.
func (errcopy *ErrorCopy) Morph(c *Context) {
oldName, newName := errcopy.Ref.Morph(c), errcopy.Name.Morph(c)
c.Putln("const Bad%s = %d", newName, errcopy.Number)
c.Putln("")
c.Putln("type %sError %sError", newName, oldName)
c.Putln("")
c.Putln("func New%sError(buf []byte) %sError {", newName, newName)
c.Putln("return (%sError)(New%sError(buf))", newName, oldName)
c.Putln("}")
c.Putln("")
c.Putln("func (err %sError) ImplementsError() { }", newName)
c.Putln("")
c.Putln("func (err %sError) Bytes() []byte {", newName)
c.Putln("return (%sError)(err).Bytes()", oldName)
c.Putln("}")
c.Putln("")
c.Putln("func init() {")
c.Putln("newErrorFuncs[%d] = New%sError", errcopy.Number, newName)
c.Putln("}")
func (f *PadField) Read(c *Context) {
c.Putln("b += %s // padding", f.Size())
c.Putln("")
}
/******************************************************************************/
// Collection morphing.
// Below are functions that morph a collections of units.
// Most of these can probably remain unchanged, but they are useful if you
// need to group all of some "unit" in a single block or something.
/******************************************************************************/
func (imports Imports) Morph(c *Context) {
if len(imports) == 0 {
return
// Single fields
func (f *SingleField) Define(c *Context) {
c.Putln("%s %s", f.SrcName(), f.Type.SrcName())
}
func ReadSimpleSingleField(c *Context, name string, typ Type) {
switch t := typ.(type) {
case *Resource:
c.Putln("%s = get32(buf[b:])", name)
case *TypeDef:
switch t.Size().Eval() {
case 1:
c.Putln("%s = %s(buf[b])", name, t.SrcName())
case 2:
c.Putln("%s = %s(get16(buf[b:]))", name, t.SrcName())
case 4:
c.Putln("%s = %s(get32(buf[b:]))", name, t.SrcName())
case 8:
c.Putln("%s = %s(get64(buf[b:]))", name, t.SrcName())
}
case *Base:
var val string
switch t.Size().Eval() {
case 1:
val = fmt.Sprintf("buf[b]")
case 2:
val = fmt.Sprintf("get16(buf[b:])")
case 4:
val = fmt.Sprintf("get32(buf[b:])")
case 8:
val = fmt.Sprintf("get64(buf[b:])")
}
// We need to convert base types if they aren't uintXX or byte
ty := t.SrcName()
if ty != "byte" && ty != "uint16" && ty != "uint32" && ty != "uint64" {
val = fmt.Sprintf("%s(%s)", ty, val)
}
c.Putln("%s = %s", name, val)
default:
log.Fatalf("Cannot read field '%s' as a simple field with %T type.",
name, typ)
}
c.Putln("// Imports are not required for XGB since everything is in")
c.Putln("// a single package. Still these may be useful for ")
c.Putln("// reference purposes.")
for _, imp := range imports {
imp.Morph(c)
c.Putln("b += %s", typ.Size())
}
func (f *SingleField) Read(c *Context) {
switch t := f.Type.(type) {
case *Resource:
ReadSimpleSingleField(c, fmt.Sprintf("v.%s", f.SrcName()), t)
case *TypeDef:
ReadSimpleSingleField(c, fmt.Sprintf("v.%s", f.SrcName()), t)
case *Base:
ReadSimpleSingleField(c, fmt.Sprintf("v.%s", f.SrcName()), t)
case *Struct:
c.Putln("v.%s, consumed = New%s(buf[b:])", f.SrcName(), t.SrcName())
c.Putln("b += consumed")
c.Putln("")
default:
log.Fatalf("Cannot read field '%s' with %T type.", f.XmlName(), f.Type)
}
}
func (enums Enums) Morph(c *Context) {
c.Putln("// Enums\n")
for _, enum := range enums {
enum.Morph(c)
// List fields
func (f *ListField) Define(c *Context) {
c.Putln("%s []%s // length: %s",
f.SrcName(), f.Type.SrcName(), f.Size())
}
func (f *ListField) Read(c *Context) {
switch t := f.Type.(type) {
case *Resource:
length := f.LengthExpr.Reduce("v.", "")
c.Putln("v.%s = make([]Id, %s)", f.SrcName(), length)
c.Putln("for i := 0; i < %s; i++ {", length)
ReadSimpleSingleField(c, fmt.Sprintf("v.%s[i]", f.SrcName()), t)
c.Putln("}")
c.Putln("")
case *Base:
length := f.LengthExpr.Reduce("v.", "")
c.Putln("v.%s = make([]%s, %s)", f.SrcName(), t.SrcName(), length)
c.Putln("for i := 0; i < %s; i++ {", length)
ReadSimpleSingleField(c, fmt.Sprintf("v.%s[i]", f.SrcName()), t)
c.Putln("}")
c.Putln("")
case *Struct:
c.Putln("v.%s, consumed = Read%sList(buf[b:], %s)",
f.SrcName(), t.SrcName(), f.LengthExpr.Reduce("v.", ""))
c.Putln("b += consumed")
c.Putln("")
default:
log.Fatalf("Cannot read list field '%s' with %T type.",
f.XmlName(), f.Type)
}
}
func (xids Xids) Morph(c *Context) {
c.Putln("// Xids\n")
for _, xid := range xids {
xid.Morph(c)
}
// Local fields
func (f *LocalField) Define(c *Context) {
c.Putln("// local field: %s %s", f.SrcName(), f.Type.SrcName())
}
func (typedefs TypeDefs) Morph(c *Context) {
c.Putln("// TypeDefs\n")
for _, typedef := range typedefs {
typedef.Morph(c)
}
func (f *LocalField) Read(c *Context) {
c.Putln("// reading local field: %s (%s) :: %s",
f.SrcName(), f.Size(), f.Type.SrcName())
}
func (strct Structs) Morph(c *Context) {
c.Putln("// Structs\n")
for _, typedef := range strct {
typedef.Morph(c)
}
// Expr fields
func (f *ExprField) Define(c *Context) {
c.Putln("// expression field: %s %s (%s)",
f.SrcName(), f.Type.SrcName(), f.Expr)
}
func (union Unions) Morph(c *Context) {
c.Putln("// Unions\n")
for _, typedef := range union {
typedef.Morph(c)
}
func (f *ExprField) Read(c *Context) {
c.Putln("// reading expression field: %s (%s) (%s) :: %s",
f.SrcName(), f.Size(), f.Expr, f.Type.SrcName())
}
func (request Requests) Morph(c *Context) {
c.Putln("// Requests\n")
for _, typedef := range request {
typedef.Morph(c)
}
// Value field
func (f *ValueField) Define(c *Context) {
c.Putln("// valueparam field: type: %s, mask name: %s, list name: %s",
f.MaskType.SrcName(), f.MaskName, f.ListName)
}
func (event Events) Morph(c *Context) {
c.Putln("// Events\n")
for _, typedef := range event {
typedef.Morph(c)
}
func (f *ValueField) Read(c *Context) {
c.Putln("// reading valueparam: type: %s, mask name: %s, list name: %s",
f.MaskType.SrcName(), f.MaskName, f.ListName)
}
func (evcopy EventCopies) Morph(c *Context) {
c.Putln("// Event Copies\n")
for _, typedef := range evcopy {
typedef.Morph(c)
}
// Switch field
func (f *SwitchField) Define(c *Context) {
c.Putln("// switch field: %s (%s)", f.Name, f.Expr)
}
func (err Errors) Morph(c *Context) {
c.Putln("// Errors\n")
for _, typedef := range err {
typedef.Morph(c)
}
}
func (errcopy ErrorCopies) Morph(c *Context) {
c.Putln("// Error copies\n")
for _, typedef := range errcopy {
typedef.Morph(c)
}
func (f *SwitchField) Read(c *Context) {
c.Putln("// reading switch field: %s (%s)", f.Name, f.Expr)
}

View File

@ -47,7 +47,7 @@ func main() {
// Initialize the buffer, parse it, and filter it through gofmt.
c := newContext()
c.Translate(xmlBytes)
c.Morph(xmlBytes)
if !*gofmt {
c.out.WriteTo(os.Stdout)

50
nexgb/xgbgen/morph.go Normal file
View File

@ -0,0 +1,50 @@
// 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.Errors.Morph(c)
c.Putln("")
x.ErrorCopies.Morph(c)
c.Putln("")
x.Events.Morph(c)
c.Putln("")
x.EventCopies.Morph(c)
c.Putln("")
}

View File

@ -0,0 +1,56 @@
package main
type Protocol struct {
Name string
ExtXName string
ExtName string
MajorVersion string
MinorVersion string
Imports []*Protocol
Types []Type
Requests []*Request
}
// Initialize traverses all structures, looks for 'Translation' type,
// and looks up the real type in the namespace. It also sets the source
// name for all relevant fields/structures.
// This is necessary because we don't traverse the XML in order initially.
func (p *Protocol) Initialize() {
for _, typ := range p.Types {
typ.Initialize(p)
}
for _, req := range p.Requests {
req.Initialize(p)
}
}
type Request struct {
srcName string
xmlName string
Opcode int
Combine bool
Fields []Field
Reply *Reply
}
func (r *Request) Initialize(p *Protocol) {
r.srcName = SrcName(r.xmlName)
if r.Reply != nil {
r.Reply.Initialize(p)
}
for _, field := range r.Fields {
field.Initialize(p)
}
}
type Reply struct {
Fields []Field
}
func (r *Reply) Initialize(p *Protocol) {
for _, field := range r.Fields {
field.Initialize(p)
}
}

22
nexgb/xgbgen/size.go Normal file
View File

@ -0,0 +1,22 @@
package main
type Size struct {
Expression
}
func newFixedSize(fixed uint) Size {
return Size{&Value{v: fixed}}
}
func newExpressionSize(variable Expression) Size {
return Size{variable}
}
func (s1 Size) Add(s2 Size) Size {
return Size{newBinaryOp("+", s1, s2)}
}
func (s1 Size) Multiply(s2 Size) Size {
return Size{newBinaryOp("*", s1, s2)}
}

426
nexgb/xgbgen/translation.go Normal file
View File

@ -0,0 +1,426 @@
package main
/*
translation.go provides a 'Translate' method on every XML type that converts
the XML type into our "better" representation.
i.e., the representation of Fields and Expressions is just too general.
We end up losing a lot of the advantages of static typing if we keep
the types that encoding/xml forces us into.
Please see 'representation.go' for the type definitions that we're
translating to.
*/
import (
"log"
"strconv"
"strings"
)
func (xml *XML) Translate() *Protocol {
protocol := &Protocol{
Name: xml.Header,
ExtXName: xml.ExtensionXName,
ExtName: xml.ExtensionName,
MajorVersion: xml.MajorVersion,
MinorVersion: xml.MinorVersion,
Imports: make([]*Protocol, 0),
Types: make([]Type, 0),
Requests: make([]*Request, len(xml.Requests)),
}
for _, imp := range xml.Imports {
if imp.xml != nil {
protocol.Imports = append(protocol.Imports, imp.xml.Translate())
}
}
for xmlName, srcName := range BaseTypeMap {
newBaseType := &Base{
srcName: srcName,
xmlName: xmlName,
size: newFixedSize(BaseTypeSizes[xmlName]),
}
protocol.Types = append(protocol.Types, newBaseType)
}
for _, enum := range xml.Enums {
protocol.Types = append(protocol.Types, enum.Translate())
}
for _, xid := range xml.Xids {
protocol.Types = append(protocol.Types, xid.Translate())
}
for _, xidunion := range xml.XidUnions {
protocol.Types = append(protocol.Types, xidunion.Translate())
}
for _, typedef := range xml.TypeDefs {
protocol.Types = append(protocol.Types, typedef.Translate())
}
for _, s := range xml.Structs {
protocol.Types = append(protocol.Types, s.Translate())
}
for _, union := range xml.Unions {
protocol.Types = append(protocol.Types, union.Translate())
}
for _, ev := range xml.Events {
protocol.Types = append(protocol.Types, ev.Translate())
}
for _, evcopy := range xml.EventCopies {
protocol.Types = append(protocol.Types, evcopy.Translate())
}
for _, err := range xml.Errors {
protocol.Types = append(protocol.Types, err.Translate())
}
for _, errcopy := range xml.ErrorCopies {
protocol.Types = append(protocol.Types, errcopy.Translate())
}
for i, request := range xml.Requests {
protocol.Requests[i] = request.Translate()
}
// Now load all of the type and source name information.
protocol.Initialize()
// Make sure all enums have concrete values.
for _, typ := range protocol.Types {
enum, ok := typ.(*Enum)
if !ok {
continue
}
nextValue := uint(0)
for _, item := range enum.Items {
if item.Expr == nil {
item.Expr = &Value{v: nextValue}
nextValue++
} else {
nextValue = item.Expr.Eval() + 1
}
}
}
return protocol
}
func (x *XMLEnum) Translate() *Enum {
enum := &Enum{
xmlName: x.Name,
Items: make([]*EnumItem, len(x.Items)),
}
for i, item := range x.Items {
enum.Items[i] = &EnumItem{
xmlName: item.Name,
Expr: item.Expr.Translate(),
}
}
return enum
}
func (x *XMLXid) Translate() *Resource {
return &Resource{
xmlName: x.Name,
}
}
func (x *XMLTypeDef) Translate() *TypeDef {
return &TypeDef{
xmlName: x.New,
Old: newTranslation(x.Old),
}
}
func (x *XMLEvent) Translate() *Event {
ev := &Event{
xmlName: x.Name,
Number: x.Number,
NoSequence: x.NoSequence,
Fields: make([]Field, len(x.Fields)),
}
for i, field := range x.Fields {
ev.Fields[i] = field.Translate()
}
return ev
}
func (x *XMLEventCopy) Translate() *EventCopy {
return &EventCopy{
xmlName: x.Name,
Number: x.Number,
Old: newTranslation(x.Ref),
}
}
func (x *XMLError) Translate() *Error {
err := &Error{
xmlName: x.Name,
Number: x.Number,
Fields: make([]Field, len(x.Fields)),
}
for i, field := range x.Fields {
err.Fields[i] = field.Translate()
}
return err
}
func (x *XMLErrorCopy) Translate() *ErrorCopy {
return &ErrorCopy{
xmlName: x.Name,
Number: x.Number,
Old: newTranslation(x.Ref),
}
}
func (x *XMLStruct) Translate() *Struct {
s := &Struct{
xmlName: x.Name,
Fields: make([]Field, len(x.Fields)),
}
for i, field := range x.Fields {
s.Fields[i] = field.Translate()
}
return s
}
func (x *XMLUnion) Translate() *Union {
u := &Union{
xmlName: x.Name,
Fields: make([]Field, len(x.Fields)),
}
for i, field := range x.Fields {
u.Fields[i] = field.Translate()
}
return u
}
func (x *XMLRequest) Translate() *Request {
r := &Request{
xmlName: x.Name,
Opcode: x.Opcode,
Combine: x.Combine,
Fields: make([]Field, len(x.Fields)),
Reply: x.Reply.Translate(),
}
for i, field := range x.Fields {
r.Fields[i] = field.Translate()
}
// Address bug (or legacy code) in QueryTextExtents.
// The XML protocol description references 'string_len' in the
// computation of the 'odd_length' field. However, 'string_len' is not
// defined. Therefore, let's forcefully add it as a 'local field'.
// (i.e., a parameter in the caller but does not get send over the wire.)
stringLenLocal := &LocalField{&SingleField{
xmlName: "string_len",
Type: newTranslation("CARD16"),
}}
r.Fields = append(r.Fields, stringLenLocal)
return r
}
func (x *XMLReply) Translate() *Reply {
if x == nil {
return nil
}
r := &Reply{
Fields: make([]Field, len(x.Fields)),
}
for i, field := range x.Fields {
r.Fields[i] = field.Translate()
}
return r
}
func (x *XMLExpression) Translate() Expression {
if x == nil {
return nil
}
switch x.XMLName.Local {
case "op":
if len(x.Exprs) != 2 {
log.Panicf("'op' found %d expressions; expected 2.", len(x.Exprs))
}
return &BinaryOp{
Op: x.Op,
Expr1: x.Exprs[0].Translate(),
Expr2: x.Exprs[1].Translate(),
}
case "unop":
if len(x.Exprs) != 1 {
log.Panicf("'unop' found %d expressions; expected 1.", len(x.Exprs))
}
return &UnaryOp{
Op: x.Op,
Expr: x.Exprs[0].Translate(),
}
case "popcount":
if len(x.Exprs) != 1 {
log.Panicf("'popcount' found %d expressions; expected 1.",
len(x.Exprs))
}
return &PopCount{
Expr: x.Exprs[0].Translate(),
}
case "value":
val, err := strconv.Atoi(x.Data)
if err != nil {
log.Panicf("Could not convert '%s' in 'value' expression to int.",
x.Data)
}
return &Value{
v: uint(val),
}
case "bit":
bit, err := strconv.Atoi(x.Data)
if err != nil {
log.Panicf("Could not convert '%s' in 'bit' expression to int.",
x.Data)
}
if bit < 0 || bit > 31 {
log.Panicf("A 'bit' literal must be in the range [0, 31], but " +
" is %d", bit)
}
return &Bit{
b: uint(bit),
}
case "fieldref":
return &FieldRef{
Name: x.Data,
}
case "enumref":
return &EnumRef{
EnumKind: newTranslation(x.Ref),
EnumItem: x.Data,
}
case "sumof":
return &SumOf{
Name: x.Ref,
}
}
log.Panicf("Unrecognized tag '%s' in expression context. Expected one of " +
"op, fieldref, value, bit, enumref, unop, sumof or popcount.",
x.XMLName.Local)
panic("unreachable")
}
func (x *XMLField) Translate() Field {
switch x.XMLName.Local {
case "pad":
return &PadField{
Bytes: x.Bytes,
}
case "field":
return &SingleField{
xmlName: x.Name,
Type: newTranslation(x.Type),
}
case "list":
return &ListField{
xmlName: x.Name,
Type: newTranslation(x.Type),
LengthExpr: x.Expr.Translate(),
}
case "localfield":
return &LocalField{&SingleField{
xmlName: x.Name,
Type: newTranslation(x.Type),
}}
case "exprfield":
return &ExprField{
xmlName: x.Name,
Type: newTranslation(x.Type),
Expr: x.Expr.Translate(),
}
case "valueparam":
return &ValueField{
MaskType: newTranslation(x.ValueMaskType),
MaskName: x.ValueMaskName,
ListName: x.ValueListName,
}
case "switch":
swtch := &SwitchField{
Name: x.Name,
Expr: x.Expr.Translate(),
Bitcases: make([]*Bitcase, len(x.Bitcases)),
}
for i, bitcase := range x.Bitcases {
swtch.Bitcases[i] = bitcase.Translate()
}
return swtch
}
log.Panicf("Unrecognized field element: %s", x.XMLName.Local)
panic("unreachable")
}
func (x *XMLBitcase) Translate() *Bitcase {
b := &Bitcase{
Expr: x.Expr().Translate(),
Fields: make([]Field, len(x.Fields)),
}
for i, field := range x.Fields {
b.Fields[i] = field.Translate()
}
return b
}
// SrcName is used to translate any identifier into a Go name.
// Mostly used for fields, but used in a couple other places too (enum items).
func SrcName(name string) string {
// If it's in the name map, use that translation.
if newn, ok := NameMap[name]; ok {
return newn
}
return splitAndTitle(name)
}
func TypeSrcName(p *Protocol, typ Type) string {
t := typ.XmlName()
// If this is a base type, then write the raw Go type.
if baseType, ok := typ.(*Base); ok {
return baseType.SrcName()
}
// If it's in the type map, use that translation.
if newt, ok := TypeMap[t]; ok {
return newt
}
// If it's a resource type, just use 'Id'.
if _, ok := typ.(*Resource); ok {
return xgbGenResourceIdName
}
// If there's a namespace to this type, just use it and be done.
if colon := strings.Index(t, ":"); colon > -1 {
namespace := t[:colon]
rest := t[colon+1:]
return splitAndTitle(namespace) + splitAndTitle(rest)
}
// Since there is no namespace, we need to look for a namespace
// in the current context.
niceType := splitAndTitle(t)
if p.Name != "xproto" {
for _, typ2 := range p.Types {
if t == typ2.XmlName() {
return strings.Title(p.Name) + niceType
}
}
for _, imp := range p.Imports {
for _, typ2 := range imp.Types {
if t == typ2.XmlName() {
return strings.Title(imp.Name) + niceType
}
}
}
}
// We couldn't find one, so return it without a prefix.
return niceType
}

365
nexgb/xgbgen/type.go Normal file
View File

@ -0,0 +1,365 @@
package main
import (
"fmt"
"strings"
)
type Type interface {
Initialize(p *Protocol)
SrcName() string
XmlName() string
Size() Size
Define(c *Context)
}
// Translation is used *only* when transitioning from XML types to
// our better representation. They are placeholders for the real types (below)
// that will replace them.
type Translation struct {
xmlName string
}
func newTranslation(name string) *Translation {
return &Translation{xmlName: name}
}
// RealType takes 'XmlName' and finds its real concrete type in our Protocol.
// It is an error if we can't find such a type.
func (t *Translation) RealType(p *Protocol) Type {
// Check to see if there is a namespace. If so, strip it and use it to
// make sure we only look for a type in that protocol.
namespace, typeName := "", t.XmlName()
if ni := strings.Index(t.XmlName(), ":"); ni > -1 {
namespace, typeName = strings.ToLower(typeName[:ni]), typeName[ni+1:]
}
if len(namespace) == 0 || namespace == strings.ToLower(p.Name) {
for _, typ := range p.Types {
if typeName == typ.XmlName() {
return typ
}
}
}
for _, imp := range p.Imports {
if len(namespace) == 0 || namespace == strings.ToLower(imp.Name) {
for _, typ := range imp.Types {
if typeName == typ.XmlName() {
return typ
}
}
}
}
panic("Could not find real type for translation type: " + t.XmlName())
}
func (t *Translation) SrcName() string {
panic("it is illegal to call SrcName on a translation type")
}
func (t *Translation) XmlName() string {
return t.xmlName
}
func (t *Translation) Size() Size {
panic("it is illegal to call Size on a translation type")
}
func (t *Translation) Define(c *Context) {
panic("it is illegal to call Define on a translation type")
}
func (t *Translation) Initialize(p *Protocol) {
panic("it is illegal to call Initialize on a translation type")
}
type Base struct {
srcName string
xmlName string
size Size
}
func (b *Base) SrcName() string {
return b.srcName
}
func (b *Base) XmlName() string {
return b.xmlName
}
func (b *Base) Size() Size {
return b.size
}
func (b *Base) Initialize(p *Protocol) {
b.srcName = TypeSrcName(p, b)
}
type Enum struct {
srcName string
xmlName string
Items []*EnumItem
}
type EnumItem struct {
srcName string
xmlName string
Expr Expression
}
func (enum *Enum) SrcName() string {
return enum.srcName
}
func (enum *Enum) XmlName() string {
return enum.xmlName
}
func (enum *Enum) Size() Size {
panic("Cannot take size of enum")
}
func (enum *Enum) Initialize(p *Protocol) {
enum.srcName = TypeSrcName(p, enum)
for _, item := range enum.Items {
item.srcName = SrcName(item.xmlName)
if item.Expr != nil {
item.Expr.Initialize(p)
}
}
}
type Resource struct {
srcName string
xmlName string
}
func (r *Resource) SrcName() string {
return r.srcName
}
func (r *Resource) XmlName() string {
return r.xmlName
}
func (r *Resource) Size() Size {
return newFixedSize(BaseTypeSizes["Id"])
}
func (r *Resource) Initialize(p *Protocol) {
r.srcName = TypeSrcName(p, r)
}
type TypeDef struct {
srcName string
xmlName string
Old Type
}
func (t *TypeDef) SrcName() string {
return t.srcName
}
func (t *TypeDef) XmlName() string {
return t.xmlName
}
func (t *TypeDef) Size() Size {
return t.Old.Size()
}
func (t *TypeDef) Initialize(p *Protocol) {
t.Old = t.Old.(*Translation).RealType(p)
t.srcName = TypeSrcName(p, t)
}
type Event struct {
srcName string
xmlName string
Number int
NoSequence bool
Fields []Field
}
func (e *Event) SrcName() string {
return e.srcName
}
func (e *Event) XmlName() string {
return e.xmlName
}
func (e *Event) Size() Size {
panic("Cannot take size of Event type.")
}
func (e *Event) Initialize(p *Protocol) {
e.srcName = TypeSrcName(p, e)
for _, field := range e.Fields {
field.Initialize(p)
}
}
func (e *Event) EvType() string {
return fmt.Sprintf("%sEvent", e.srcName)
}
type EventCopy struct {
srcName string
xmlName string
Old Type
Number int
}
func (e *EventCopy) SrcName() string {
return e.srcName
}
func (e *EventCopy) XmlName() string {
return e.xmlName
}
func (e *EventCopy) Size() Size {
panic("Cannot take size of EventCopy type.")
}
func (e *EventCopy) Initialize(p *Protocol) {
e.srcName = TypeSrcName(p, e)
e.Old = e.Old.(*Translation).RealType(p)
if _, ok := e.Old.(*Event); !ok {
panic("an EventCopy's old type *must* be *Event")
}
}
func (e *EventCopy) EvType() string {
return fmt.Sprintf("%sEvent", e.srcName)
}
type Error struct {
srcName string
xmlName string
Number int
Fields []Field
}
func (e *Error) SrcName() string {
return e.srcName
}
func (e *Error) XmlName() string {
return e.xmlName
}
func (e *Error) Size() Size {
panic("Cannot take size of Error type.")
}
func (e *Error) Initialize(p *Protocol) {
e.srcName = TypeSrcName(p, e)
}
func (e *Error) ErrConst() string {
return fmt.Sprintf("Bad%s", e.srcName)
}
func (e *Error) ErrType() string {
return fmt.Sprintf("%sError", e.srcName)
}
type ErrorCopy struct {
srcName string
xmlName string
Old Type
Number int
}
func (e *ErrorCopy) SrcName() string {
return e.srcName
}
func (e *ErrorCopy) XmlName() string {
return e.xmlName
}
func (e *ErrorCopy) Size() Size {
panic("Cannot take size of ErrorCopy type.")
}
func (e *ErrorCopy) Initialize(p *Protocol) {
e.srcName = TypeSrcName(p, e)
e.Old = e.Old.(*Translation).RealType(p)
if _, ok := e.Old.(*Error); !ok {
panic("an ErrorCopy's old type *must* be *Event")
}
}
func (e *ErrorCopy) ErrConst() string {
return fmt.Sprintf("Bad%s", e.srcName)
}
func (e *ErrorCopy) ErrType() string {
return fmt.Sprintf("%sError", e.srcName)
}
type Struct struct {
srcName string
xmlName string
Fields []Field
}
func (s *Struct) SrcName() string {
return s.srcName
}
func (s *Struct) XmlName() string {
return s.xmlName
}
func (s *Struct) Size() Size {
size := newFixedSize(0)
for _, field := range s.Fields {
size = size.Add(field.Size())
}
return size
}
func (s *Struct) Initialize(p *Protocol) {
s.srcName = TypeSrcName(p, s)
for _, field := range s.Fields {
field.Initialize(p)
}
}
type Union struct {
srcName string
xmlName string
Fields []Field
}
func (u *Union) SrcName() string {
return u.srcName
}
func (u *Union) XmlName() string {
return u.xmlName
}
// Size for Union is broken. At least, it's broken for XKB.
// It *looks* like the protocol inherently relies on some amount of
// memory unsafety, since some members of unions in XKB are *variable* in
// length! The only thing I can come up with, maybe, is when a union has
// variable size, simply return the raw bytes. Then it's up to the user to
// pass those raw bytes into the appropriate New* constructor. GROSS!
// As of now, just pluck out the first field and return that size. This
// should work for union elements in randr.xml and xproto.xml.
func (u *Union) Size() Size {
return u.Fields[0].Size()
}
func (u *Union) Initialize(p *Protocol) {
u.srcName = TypeSrcName(p, u)
for _, field := range u.Fields {
field.Initialize(p)
}
}

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

View File

@ -7,25 +7,25 @@ import (
"strconv"
)
type Expression struct {
type XMLExpression struct {
XMLName xml.Name
Exprs []*Expression `xml:",any"`
Exprs []*XMLExpression `xml:",any"`
Data string `xml:",chardata"`
Op string `xml:"op,attr"`
Ref string `xml:"ref,attr"`
}
func newValueExpression(v uint) *Expression {
return &Expression{
func newValueExpression(v uint) *XMLExpression {
return &XMLExpression{
XMLName: xml.Name{Local: "value"},
Data: fmt.Sprintf("%d", v),
}
}
// String is for debugging. For actual use, please use 'Morph'.
func (e *Expression) String() string {
func (e *XMLExpression) String() string {
switch e.XMLName.Local {
case "op":
return fmt.Sprintf("(%s %s %s)", e.Exprs[0], e.Op, e.Exprs[1])
@ -55,7 +55,7 @@ func (e *Expression) String() string {
// empty items in enums.
// We can't compute a concrete value for expressions that rely on a context,
// i.e., some field value.
func (e *Expression) Eval() uint {
func (e *XMLExpression) Eval() uint {
switch e.XMLName.Local {
case "op":
if len(e.Exprs) != 2 {
@ -108,7 +108,7 @@ func (e *Expression) Eval() uint {
panic("unreachable")
}
func (e *Expression) BinaryOp(operand1, operand2 *Expression) *Expression {
func (e *XMLExpression) BinaryOp(oprnd1, oprnd2 *XMLExpression) *XMLExpression {
if e.XMLName.Local != "op" {
log.Panicf("Cannot perform binary operation on non-op expression: %s",
e.XMLName.Local)
@ -121,17 +121,17 @@ func (e *Expression) BinaryOp(operand1, operand2 *Expression) *Expression {
wrap := newValueExpression
switch e.Op {
case "+":
return wrap(operand1.Eval() + operand2.Eval())
return wrap(oprnd1.Eval() + oprnd2.Eval())
case "-":
return wrap(operand1.Eval() + operand2.Eval())
return wrap(oprnd1.Eval() + oprnd2.Eval())
case "*":
return wrap(operand1.Eval() * operand2.Eval())
return wrap(oprnd1.Eval() * oprnd2.Eval())
case "/":
return wrap(operand1.Eval() / operand2.Eval())
return wrap(oprnd1.Eval() / oprnd2.Eval())
case "&amp;":
return wrap(operand1.Eval() & operand2.Eval())
return wrap(oprnd1.Eval() & oprnd2.Eval())
case "&lt;&lt;":
return wrap(operand1.Eval() << operand2.Eval())
return wrap(oprnd1.Eval() << oprnd2.Eval())
}
log.Panicf("Invalid binary operator '%s' for '%s' expression.",
@ -139,7 +139,7 @@ func (e *Expression) BinaryOp(operand1, operand2 *Expression) *Expression {
panic("unreachable")
}
func (e *Expression) UnaryOp(operand *Expression) *Expression {
func (e *XMLExpression) UnaryOp(oprnd *XMLExpression) *XMLExpression {
if e.XMLName.Local != "unop" {
log.Panicf("Cannot perform unary operation on non-unop expression: %s",
e.XMLName.Local)
@ -151,7 +151,7 @@ func (e *Expression) UnaryOp(operand *Expression) *Expression {
switch e.Op {
case "~":
return newValueExpression(^operand.Eval())
return newValueExpression(^oprnd.Eval())
}
log.Panicf("Invalid unary operator '%s' for '%s' expression.",

View File

@ -23,40 +23,40 @@ import (
"strings"
)
type Fields []*Field
type XMLFields []*XMLField
type Field struct {
type XMLField struct {
XMLName xml.Name
// For 'pad' element
Bytes int `xml:"bytes,attr"`
Bytes uint `xml:"bytes,attr"`
// For 'field', 'list', 'localfield', 'exprfield' and 'switch' elements.
Name Name `xml:"name,attr"`
Name string `xml:"name,attr"`
// For 'field', 'list', 'localfield', and 'exprfield' elements.
Type Type `xml:"type,attr"`
Type string `xml:"type,attr"`
// For 'list', 'exprfield' and 'switch' elements.
Expr *Expression `xml:",any"`
Expr *XMLExpression `xml:",any"`
// For 'valueparm' element.
ValueMaskType Type `xml:"value-mask-type,attr"`
ValueMaskName Name `xml:"value-mask-name,attr"`
ValueListName Name `xml:"value-list-name,attr"`
ValueMaskType string `xml:"value-mask-type,attr"`
ValueMaskName string `xml:"value-mask-name,attr"`
ValueListName string `xml:"value-list-name,attr"`
// For 'switch' element.
Bitcases Bitcases `xml:"bitcase"`
Bitcases XMLBitcases `xml:"bitcase"`
// I don't know which elements these are for. The documentation is vague.
// They also seem to be completely optional.
OptEnum Type `xml:"enum,attr"`
OptMask Type `xml:"mask,attr"`
OptAltEnum Type `xml:"altenum,attr"`
OptEnum string `xml:"enum,attr"`
OptMask string `xml:"mask,attr"`
OptAltEnum string `xml:"altenum,attr"`
}
// String is for debugging purposes.
func (f *Field) String() string {
func (f *XMLField) String() string {
switch f.XMLName.Local {
case "pad":
return fmt.Sprintf("pad (%d bytes)", f.Bytes)
@ -88,7 +88,7 @@ func (f *Field) String() string {
panic("unreachable")
}
type Bitcases []*Bitcase
type XMLBitcases []*XMLBitcase
// Bitcase represents a single expression followed by any number of fields.
// Namely, if the switch's expression (all bitcases are inside a switch),
@ -98,24 +98,24 @@ type Bitcases []*Bitcase
// siblings, we must exhaustively search for one of them. Essentially,
// it's the closest thing to a Union I can get to in Go without interfaces.
// Would an '<expression>' tag have been too much to ask? :-(
type Bitcase struct {
Fields Fields `xml:",any"`
type XMLBitcase struct {
Fields XMLFields `xml:",any"`
// All the different expressions.
// When it comes time to choose one, use the 'Expr' method.
ExprOp *Expression `xml:"op"`
ExprUnOp *Expression `xml:"unop"`
ExprField *Expression `xml:"fieldref"`
ExprValue *Expression `xml:"value"`
ExprBit *Expression `xml:"bit"`
ExprEnum *Expression `xml:"enumref"`
ExprSum *Expression `xml:"sumof"`
ExprPop *Expression `xml:"popcount"`
ExprOp *XMLExpression `xml:"op"`
ExprUnOp *XMLExpression `xml:"unop"`
ExprField *XMLExpression `xml:"fieldref"`
ExprValue *XMLExpression `xml:"value"`
ExprBit *XMLExpression `xml:"bit"`
ExprEnum *XMLExpression `xml:"enumref"`
ExprSum *XMLExpression `xml:"sumof"`
ExprPop *XMLExpression `xml:"popcount"`
}
// StringPrefix is for debugging purposes only.
// StringPrefix takes a string to prefix to every extra line for formatting.
func (b *Bitcase) StringPrefix(prefix string) string {
func (b *XMLBitcase) StringPrefix(prefix string) string {
fields := make([]string, len(b.Fields))
for i, field := range b.Fields {
fields[i] = fmt.Sprintf("%s%s", prefix, field)
@ -126,13 +126,13 @@ func (b *Bitcase) StringPrefix(prefix string) string {
// Expr chooses the only non-nil Expr* field from Bitcase.
// Panic if there is more than one non-nil expression.
func (b *Bitcase) Expr() *Expression {
choices := []*Expression{
func (b *XMLBitcase) Expr() *XMLExpression {
choices := []*XMLExpression{
b.ExprOp, b.ExprUnOp, b.ExprField, b.ExprValue,
b.ExprBit, b.ExprEnum, b.ExprSum, b.ExprPop,
}
var choice *Expression = nil
var choice *XMLExpression = nil
numNonNil := 0
for _, c := range choices {
if c != nil {