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 { type Context struct {
xml *XML protocol *Protocol
out *bytes.Buffer out *bytes.Buffer
} }
func newContext() *Context { func newContext() *Context {
return &Context{ return &Context{
xml: &XML{},
out: bytes.NewBuffer([]byte{}), out: bytes.NewBuffer([]byte{}),
} }
} }
@ -32,22 +31,24 @@ func (c *Context) Put(format string, v ...interface{}) {
} }
} }
// Morph is the big daddy of them all. It takes in an XML byte slice,
// Translate 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. // and writes Go code to the 'out' buffer.
func (c *Context) Translate(xmlBytes []byte) { func (c *Context) Morph(xmlBytes []byte) {
err := xml.Unmarshal(xmlBytes, c.xml) parsedXml := &XML{}
err := xml.Unmarshal(xmlBytes, parsedXml)
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
} }
// Parse all imports // Parse all imports
c.xml.Imports.Eval() parsedXml.Imports.Eval()
// Make sure all top level enumerations have expressions // Translate XML types to nice types
// (For when there are empty items.) c.protocol = parsedXml.Translate()
c.xml.Enums.Eval()
// It's Morphin' Time! // Now write Go source code
c.xml.Morph(c) 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 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 ( import (
"fmt" "fmt"
"log" "log"
"strings"
) )
/******************************************************************************/ // xgbResourceIdName is the name of the type used for all resource identifiers.
// Manual type and name overrides. // 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. // BaseTypeMap is a map from X base types to Go types.
// X base types should correspond to the smallest set of X types // X base types should correspond to the smallest set of X types
@ -50,6 +27,8 @@ var BaseTypeMap = map[string]string{
"float": "float64", "float": "float64",
"double": "float64", "double": "float64",
"char": "byte", "char": "byte",
"void": "byte",
"Id": "Id",
} }
// BaseTypeSizes should have precisely the same keys as in BaseTypeMap, // BaseTypeSizes should have precisely the same keys as in BaseTypeMap,
@ -66,6 +45,7 @@ var BaseTypeSizes = map[string]uint{
"float": 4, "float": 4,
"double": 8, "double": 8,
"char": 1, "char": 1,
"void": 1,
"Id": 4, "Id": 4,
} }
@ -82,483 +62,350 @@ var TypeMap = map[string]string{
// NameMap is the same as TypeMap, but for names. // NameMap is the same as TypeMap, but for names.
var NameMap = map[string]string{ } var NameMap = map[string]string{ }
/******************************************************************************/ // Reading, writing and defining...
// 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
)
/******************************************************************************/ // Base types
// Helper functions that aide in morphing repetitive constructs. func (b *Base) Define(c *Context) {
// i.e., type and identifier names, etc. c.Putln("// Skipping definition for base type '%s'", SrcName(b.XmlName()))
/******************************************************************************/
// 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(")")
}
c.Putln("") c.Putln("")
return byt + size
} }
func (fields Fields) MorphWrite(c *Context, kind int) { // Enum types
var nextByte uint func (enum *Enum) Define(c *Context) {
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) {
c.Putln("const (") c.Putln("const (")
for _, item := range enum.Items { for _, item := range enum.Items {
c.Putln("%s%s = %d", enum.Name.Morph(c), item.Name.Morph(c), c.Putln("%s%s = %d", enum.SrcName(), item.srcName, item.Expr.Eval())
item.Expr.Eval())
} }
c.Putln(")\n") c.Putln(")")
}
// 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("") c.Putln("")
c.Putln("func New%s(buf []byte) %sEvent {", name, name)
c.Putln("var v %sEvent", name) // Write function that reads bytes and produces this struct.
ev.Fields.MorphRead(c, FieldsEvent, ev.NoSequence, "v.", 1) s.Read(c)
c.Putln("return v")
// 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("") 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("")
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("") c.Putln("")
c.Putln("func init() {") 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("}")
c.Putln("") c.Putln("")
} }
// EventCopy morphing. // Error types
func (evcopy *EventCopy) Morph(c *Context) { func (e *Error) Define(c *Context) {
oldName, newName := evcopy.Ref.Morph(c), evcopy.Name.Morph(c) 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("")
c.Putln("type %sEvent %sEvent", newName, oldName) c.Putln("const %s = %d", e.ErrConst(), e.Number)
c.Putln("") c.Putln("")
c.Putln("func New%s(buf []byte) %sEvent {", newName, newName) c.Putln("type %s %s", e.ErrType(), e.Old.(*Error).ErrType())
c.Putln("return (%sEvent)(New%s(buf))", newName, oldName) 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("") c.Putln("")
c.Putln("func (err %sEvent) ImplementsEvent() { }", newName) c.Putln("func (err %s) ImplementsError() { }", e.ErrType())
c.Putln("") c.Putln("")
c.Putln("func (ev %sEvent) Bytes() []byte {", newName) c.Putln("func (err %s) Bytes() []byte {", e.ErrType())
c.Putln("return (%sEvent)(ev).Bytes()", oldName) c.Putln("return (%s)(err).Bytes()", e.Old.(*Error).ErrType())
c.Putln("}") c.Putln("}")
c.Putln("") c.Putln("")
c.Putln("func init() {") 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("}")
c.Putln("") c.Putln("")
} }
// Error morphing. // Field definitions, reads and writes.
func (err *Error) Morph(c *Context) {
// Pad fields
func (f *PadField) Define(c *Context) {
c.Putln("// padding: %d bytes", f.Bytes)
} }
// ErrorCopy morphing. func (f *PadField) Read(c *Context) {
func (errcopy *ErrorCopy) Morph(c *Context) { c.Putln("b += %s // padding", f.Size())
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("}")
c.Putln("") c.Putln("")
} }
/******************************************************************************/ // Single fields
// Collection morphing. func (f *SingleField) Define(c *Context) {
// Below are functions that morph a collections of units. c.Putln("%s %s", f.SrcName(), f.Type.SrcName())
// 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 ReadSimpleSingleField(c *Context, name string, typ Type) {
func (imports Imports) Morph(c *Context) { switch t := typ.(type) {
if len(imports) == 0 { case *Resource:
return 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("b += %s", typ.Size())
c.Putln("// a single package. Still these may be useful for ") }
c.Putln("// reference purposes.")
for _, imp := range imports { func (f *SingleField) Read(c *Context) {
imp.Morph(c) 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) { // List fields
c.Putln("// Enums\n") func (f *ListField) Define(c *Context) {
for _, enum := range enums { c.Putln("%s []%s // length: %s",
enum.Morph(c) 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) { // Local fields
c.Putln("// Xids\n") func (f *LocalField) Define(c *Context) {
for _, xid := range xids { c.Putln("// local field: %s %s", f.SrcName(), f.Type.SrcName())
xid.Morph(c)
}
} }
func (typedefs TypeDefs) Morph(c *Context) { func (f *LocalField) Read(c *Context) {
c.Putln("// TypeDefs\n") c.Putln("// reading local field: %s (%s) :: %s",
for _, typedef := range typedefs { f.SrcName(), f.Size(), f.Type.SrcName())
typedef.Morph(c)
}
} }
func (strct Structs) Morph(c *Context) { // Expr fields
c.Putln("// Structs\n") func (f *ExprField) Define(c *Context) {
for _, typedef := range strct { c.Putln("// expression field: %s %s (%s)",
typedef.Morph(c) f.SrcName(), f.Type.SrcName(), f.Expr)
}
} }
func (union Unions) Morph(c *Context) { func (f *ExprField) Read(c *Context) {
c.Putln("// Unions\n") c.Putln("// reading expression field: %s (%s) (%s) :: %s",
for _, typedef := range union { f.SrcName(), f.Size(), f.Expr, f.Type.SrcName())
typedef.Morph(c)
}
} }
func (request Requests) Morph(c *Context) { // Value field
c.Putln("// Requests\n") func (f *ValueField) Define(c *Context) {
for _, typedef := range request { c.Putln("// valueparam field: type: %s, mask name: %s, list name: %s",
typedef.Morph(c) f.MaskType.SrcName(), f.MaskName, f.ListName)
}
} }
func (event Events) Morph(c *Context) { func (f *ValueField) Read(c *Context) {
c.Putln("// Events\n") c.Putln("// reading valueparam: type: %s, mask name: %s, list name: %s",
for _, typedef := range event { f.MaskType.SrcName(), f.MaskName, f.ListName)
typedef.Morph(c)
}
} }
func (evcopy EventCopies) Morph(c *Context) { // Switch field
c.Putln("// Event Copies\n") func (f *SwitchField) Define(c *Context) {
for _, typedef := range evcopy { c.Putln("// switch field: %s (%s)", f.Name, f.Expr)
typedef.Morph(c)
}
} }
func (err Errors) Morph(c *Context) { func (f *SwitchField) Read(c *Context) {
c.Putln("// Errors\n") c.Putln("// reading switch field: %s (%s)", f.Name, f.Expr)
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)
}
} }

View File

@ -47,7 +47,7 @@ func main() {
// Initialize the buffer, parse it, and filter it through gofmt. // Initialize the buffer, parse it, and filter it through gofmt.
c := newContext() c := newContext()
c.Translate(xmlBytes) c.Morph(xmlBytes)
if !*gofmt { if !*gofmt {
c.out.WriteTo(os.Stdout) 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" "encoding/xml"
"io/ioutil" "io/ioutil"
"log" "log"
"time"
) )
type XML struct { type XML struct {
@ -18,231 +17,25 @@ type XML struct {
// Types for all top-level elements. // Types for all top-level elements.
// First are the simple ones. // First are the simple ones.
Imports Imports `xml:"import"` Imports XMLImports `xml:"import"`
Enums Enums `xml:"enum"` Enums XMLEnums `xml:"enum"`
Xids Xids `xml:"xidtype"` Xids XMLXids `xml:"xidtype"`
XidUnions Xids `xml:"xidunion"` XidUnions XMLXids `xml:"xidunion"`
TypeDefs TypeDefs `xml:"typedef"` TypeDefs XMLTypeDefs `xml:"typedef"`
EventCopies EventCopies `xml:"eventcopy"` EventCopies XMLEventCopies `xml:"eventcopy"`
ErrorCopies ErrorCopies `xml:"errorcopy"` ErrorCopies XMLErrorCopies `xml:"errorcopy"`
// Here are the complex ones, i.e., anything with "structure contents" // Here are the complex ones, i.e., anything with "structure contents"
Structs Structs `xml:"struct"` Structs XMLStructs `xml:"struct"`
Unions Unions `xml:"union"` Unions XMLUnions `xml:"union"`
Requests Requests `xml:"request"` Requests XMLRequests `xml:"request"`
Events Events `xml:"event"` Events XMLEvents `xml:"event"`
Errors Errors `xml:"error"` Errors XMLErrors `xml:"error"`
} }
// Morph cascades down all of the XML and calls each type's corresponding type XMLImports []*XMLImport
// 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) func (imports XMLImports) Eval() {
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() {
for _, imp := range imports { for _, imp := range imports {
xmlBytes, err := ioutil.ReadFile(*protoPath + "/" + imp.Name + ".xml") xmlBytes, err := ioutil.ReadFile(*protoPath + "/" + imp.Name + ".xml")
if err != nil { if err != nil {
@ -256,117 +49,101 @@ func (imports Imports) Eval() {
log.Fatal("Could not parse X protocol description for import " + log.Fatal("Could not parse X protocol description for import " +
"'%s' because: %s", imp.Name, err) "'%s' because: %s", imp.Name, err)
} }
// recursive imports...
imp.xml.Imports.Eval()
} }
} }
type Import struct { type XMLImport struct {
Name string `xml:",chardata"` Name string `xml:",chardata"`
xml *XML `xml:"-"` xml *XML `xml:"-"`
} }
type Enums []Enum type XMLEnums []XMLEnum
// Eval on the list of all enum types goes through and forces every enum type XMLEnum struct {
// item to have a valid expression. Name string `xml:"name,attr"`
// This is necessary because when an item is empty, it is defined to have Items []*XMLEnumItem `xml:"item"`
// 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 { type XMLEnumItem struct {
Name Type `xml:"name,attr"` Name string `xml:"name,attr"`
Items []*EnumItem `xml:"item"` Expr *XMLExpression `xml:",any"`
} }
type EnumItem struct { type XMLXids []*XMLXid
Name Name `xml:"name,attr"`
Expr *Expression `xml:",any"`
}
type Xids []*Xid type XMLXid struct {
type Xid struct {
XMLName xml.Name XMLName xml.Name
Name Type `xml:"name,attr"` Name string `xml:"name,attr"`
} }
type TypeDefs []*TypeDef type XMLTypeDefs []*XMLTypeDef
type TypeDef struct { type XMLTypeDef struct {
Old Type `xml:"oldname,attr"` Old string `xml:"oldname,attr"`
New Type `xml:"newname,attr"` New string `xml:"newname,attr"`
} }
type EventCopies []*EventCopy type XMLEventCopies []*XMLEventCopy
type EventCopy struct { type XMLEventCopy struct {
Name Type `xml:"name,attr"` Name string `xml:"name,attr"`
Number int `xml:"number,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 { type XMLErrorCopy struct {
Name Type `xml:"name,attr"` Name string `xml:"name,attr"`
Number int `xml:"number,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 { type XMLStruct struct {
Name Type `xml:"name,attr"` Name string `xml:"name,attr"`
Fields Fields `xml:",any"` Fields XMLFields `xml:",any"`
} }
type Unions []*Union type XMLUnions []*XMLUnion
type Union struct { type XMLUnion struct {
Name Type `xml:"name,attr"` Name string `xml:"name,attr"`
Fields Fields `xml:",any"` Fields XMLFields `xml:",any"`
} }
type Requests []*Request type XMLRequests []*XMLRequest
type Request struct { type XMLRequest struct {
Name Type `xml:"name,attr"` Name string `xml:"name,attr"`
Opcode int `xml:"opcode,attr"` Opcode int `xml:"opcode,attr"`
Combine bool `xml:"combine-adjacent,attr"` Combine bool `xml:"combine-adjacent,attr"`
Fields Fields `xml:",any"` Fields XMLFields `xml:",any"`
Reply *Reply `xml:"reply"` Reply *XMLReply `xml:"reply"`
} }
type Reply struct { type XMLReply struct {
Fields Fields `xml:",any"` Fields XMLFields `xml:",any"`
} }
type Events []*Event type XMLEvents []*XMLEvent
type Event struct { type XMLEvent struct {
Name Type `xml:"name,attr"` Name string `xml:"name,attr"`
Number int `xml:"number,attr"` Number int `xml:"number,attr"`
NoSequence bool `xml:"no-sequence-number,true"` NoSequence bool `xml:"no-sequence-number,true"`
Fields Fields `xml:",any"` Fields XMLFields `xml:",any"`
} }
type Errors []*Error type XMLErrors []*XMLError
type Error struct { type XMLError struct {
Name Type `xml:"name,attr"` Name string `xml:"name,attr"`
Number int `xml:"number,attr"` Number int `xml:"number,attr"`
Fields Fields `xml:",any"` Fields XMLFields `xml:",any"`
} }

View File

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

View File

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