Changed xgbgen to support xcb-proto 1.12

* Added minimal support for switch fields.
* Changed the way Size is calculated to accomodate for lists inside structs
  (added to randr)
* Removed heuristic to place alignment gaps, they are now explicitly
  described in xml
This commit is contained in:
aarzilli 2017-01-18 09:53:26 +01:00 committed by Přemysl Janouch
parent a102c4056f
commit 1c01d79ba1
Signed by: p
GPG Key ID: A0420B94F92B9493
9 changed files with 174 additions and 158 deletions

View File

@ -1,120 +0,0 @@
package main
import (
"fmt"
"os"
)
func (p *Protocol) AddAlignGaps() {
for i := range p.Imports {
p.Imports[i].AddAlignGaps()
}
for i := range p.Types {
switch t := p.Types[i].(type) {
case *Struct:
t.Fields = addAlignGapsToFields(t.xmlName, t.Fields)
case *Event:
t.Fields = addAlignGapsToFields(t.xmlName, t.Fields)
case *Error:
t.Fields = addAlignGapsToFields(t.xmlName, t.Fields)
}
}
for i := range p.Requests {
p.Requests[i].Fields = addAlignGapsToFields(
p.Requests[i].xmlName, p.Requests[i].Fields)
if p.Requests[i].Reply != nil {
p.Requests[i].Reply.Fields = addAlignGapsToFields(
p.Requests[i].xmlName, p.Requests[i].Reply.Fields)
}
}
}
func addAlignGapsToFields(name string, fields []Field) []Field {
var i int
for i = 0; i < len(fields); i++ {
if _, ok := fields[i].(*ListField); ok {
break
}
}
if i >= len(fields) {
return fields
}
r := make([]Field, 0, len(fields)+2)
r = append(r, fields[:i]...)
r = append(r, fields[i])
for i = i + 1; i < len(fields); i++ {
switch f := fields[i].(type) {
case *ListField:
// ok, add padding
sz := xcbSizeOfType(f.Type)
switch {
case sz == 1:
// nothing
case sz == 2:
r = append(r, &PadField{0, 2})
case sz == 3:
panic(fmt.Errorf("Alignment is not a power of 2"))
case sz >= 4:
r = append(r, &PadField{0, 4})
}
case *LocalField:
// nothing
default:
fmt.Fprintf(os.Stderr,
"Can't add alignment gaps, mix of list and non-list "+
"fields: %s\n", name)
return fields
}
r = append(r, fields[i])
}
return r
}
func xcbSizeOfField(fld Field) int {
switch f := fld.(type) {
case *PadField:
return int(f.Bytes)
case *SingleField:
return xcbSizeOfType(f.Type)
case *ListField:
return 0
case *ExprField:
return xcbSizeOfType(f.Type)
case *ValueField:
return xcbSizeOfType(f.MaskType)
case *SwitchField:
return 0
default:
return 0
}
}
func xcbSizeOfType(typ Type) int {
switch t := typ.(type) {
case *Resource:
return 4
case *TypeDef:
return t.Size().Eval()
case *Base:
return t.Size().Eval()
case *Struct:
sz := 0
for i := range t.Fields {
sz += xcbSizeOfField(t.Fields[i])
}
return sz
case *Union:
sz := 0
for i := range t.Fields {
csz := xcbSizeOfField(t.Fields[i])
if csz > sz {
sz = csz
}
}
return sz
default:
return 0
}
}

View File

@ -49,8 +49,23 @@ func (c *Context) Morph(xmlBytes []byte) {
// Translate XML types to nice types // Translate XML types to nice types
c.protocol = parsedXml.Translate(nil) c.protocol = parsedXml.Translate(nil)
c.protocol.AddAlignGaps() // For backwards compatibility we patch the type of the send_event field of
// PutImage to be byte
if c.protocol.Name == "shm" {
for _, req := range c.protocol.Requests {
if req.xmlName != "PutImage" {
continue
}
for _, ifield := range req.Fields {
field, ok := ifield.(*SingleField)
if !ok || field.xmlName != "send_event" {
continue
}
field.Type = &Base{ srcName: "byte", xmlName: "CARD8", size: newFixedSize(1, true) }
}
}
}
// Start with Go header. // Start with Go header.
c.Putln("// Package %s is the X client API for the %s extension.", c.Putln("// Package %s is the X client API for the %s extension.",

View File

@ -32,6 +32,9 @@ type Expression interface {
// Initialize makes sure all names in this expression and any subexpressions // Initialize makes sure all names in this expression and any subexpressions
// have been translated to Go source names. // have been translated to Go source names.
Initialize(p *Protocol) Initialize(p *Protocol)
// Makes all field references relative to path
Specialize(path string) Expression
} }
// Function is a custom expression not found in the XML. It's simply used // Function is a custom expression not found in the XML. It's simply used
@ -62,6 +65,12 @@ func (e *Function) Initialize(p *Protocol) {
e.Expr.Initialize(p) e.Expr.Initialize(p)
} }
func (e *Function) Specialize(path string) Expression {
r := *e
r.Expr = r.Expr.Specialize(path)
return &r
}
// BinaryOp is an expression that performs some operation (defined in the XML // BinaryOp is an expression that performs some operation (defined in the XML
// file) with Expr1 and Expr2 as operands. // file) with Expr1 and Expr2 as operands.
type BinaryOp struct { type BinaryOp struct {
@ -150,6 +159,13 @@ func (e *BinaryOp) Initialize(p *Protocol) {
e.Expr2.Initialize(p) e.Expr2.Initialize(p)
} }
func (e *BinaryOp) Specialize(path string) Expression {
r := *e
r.Expr1 = r.Expr1.Specialize(path)
r.Expr2 = r.Expr2.Specialize(path)
return &r
}
// UnaryOp is the same as BinaryOp, except it's a unary operator with only // UnaryOp is the same as BinaryOp, except it's a unary operator with only
// one sub-expression. // one sub-expression.
type UnaryOp struct { type UnaryOp struct {
@ -186,6 +202,12 @@ func (e *UnaryOp) Initialize(p *Protocol) {
e.Expr.Initialize(p) e.Expr.Initialize(p)
} }
func (e *UnaryOp) Specialize(path string) Expression {
r := *e
r.Expr = r.Expr.Specialize(path)
return &r
}
// Padding represents the application of the 'pad' function to some // Padding represents the application of the 'pad' function to some
// sub-expression. // sub-expression.
type Padding struct { type Padding struct {
@ -215,6 +237,12 @@ func (e *Padding) Initialize(p *Protocol) {
e.Expr.Initialize(p) e.Expr.Initialize(p)
} }
func (e *Padding) Specialize(path string) Expression {
r := *e
r.Expr = r.Expr.Specialize(path)
return &r
}
// PopCount represents the application of the 'PopCount' function to // PopCount represents the application of the 'PopCount' function to
// some sub-expression. // some sub-expression.
type PopCount struct { type PopCount struct {
@ -244,6 +272,12 @@ func (e *PopCount) Initialize(p *Protocol) {
e.Expr.Initialize(p) e.Expr.Initialize(p)
} }
func (e *PopCount) Specialize(path string) Expression {
r := *e
r.Expr = r.Expr.Specialize(path)
return &r
}
// Value represents some constant integer. // Value represents some constant integer.
type Value struct { type Value struct {
v int v int
@ -267,6 +301,10 @@ func (e *Value) String() string {
func (e *Value) Initialize(p *Protocol) {} func (e *Value) Initialize(p *Protocol) {}
func (e *Value) Specialize(path string) Expression {
return e
}
// Bit represents some bit whose value is computed by '1 << bit'. // Bit represents some bit whose value is computed by '1 << bit'.
type Bit struct { type Bit struct {
b int b int
@ -290,6 +328,10 @@ func (e *Bit) String() string {
func (e *Bit) Initialize(p *Protocol) {} func (e *Bit) Initialize(p *Protocol) {}
func (e *Bit) Specialize(path string) Expression {
return e
}
// FieldRef represents a reference to some variable in the generated code // FieldRef represents a reference to some variable in the generated code
// with name Name. // with name Name.
type FieldRef struct { type FieldRef struct {
@ -321,6 +363,10 @@ func (e *FieldRef) Initialize(p *Protocol) {
e.Name = SrcName(p, e.Name) e.Name = SrcName(p, e.Name)
} }
func (e *FieldRef) Specialize(path string) Expression {
return &FieldRef{Name: path + "." + e.Name}
}
// EnumRef represents a reference to some enumeration field. // EnumRef represents a reference to some enumeration field.
// EnumKind is the "group" an EnumItem is the name of the specific enumeration // EnumKind is the "group" an EnumItem is the name of the specific enumeration
// value inside that group. // value inside that group.
@ -351,6 +397,10 @@ func (e *EnumRef) Initialize(p *Protocol) {
e.EnumItem = SrcName(p, e.EnumItem) e.EnumItem = SrcName(p, e.EnumItem)
} }
func (e *EnumRef) Specialize(path string) Expression {
return e
}
// SumOf represents a summation of the variable in the generated code named by // SumOf represents a summation of the variable in the generated code named by
// Name. It is not currently used. (It's XKB voodoo.) // Name. It is not currently used. (It's XKB voodoo.)
type SumOf struct { type SumOf struct {
@ -380,3 +430,7 @@ func (e *SumOf) String() string {
func (e *SumOf) Initialize(p *Protocol) { func (e *SumOf) Initialize(p *Protocol) {
e.Name = SrcName(p, e.Name) e.Name = SrcName(p, e.Name)
} }
func (e *SumOf) Specialize(path string) Expression {
return e
}

View File

@ -73,6 +73,32 @@ func (p *PadField) Size() Size {
} }
} }
type RequiredStartAlign struct {
}
func (f *RequiredStartAlign) Initialize(p *Protocol) { }
func (f *RequiredStartAlign) SrcName() string {
panic("illegal to take source name of a required_start_align field")
}
func (f *RequiredStartAlign) XmlName() string {
panic("illegal to take XML name of a required_start_align field")
}
func (f *RequiredStartAlign) SrcType() string {
panic("it is illegal to call SrcType on a required_start_align field")
}
func (f *RequiredStartAlign) Size() Size {
return newFixedSize(0, true)
}
func (f *RequiredStartAlign) Define(c *Context) { }
func (f *RequiredStartAlign) Read(c *Context, prefix string) { }
func (f *RequiredStartAlign) Write(c *Context, prefix string) { }
// SingleField represents most of the fields in an XML protocol description. // SingleField represents most of the fields in an XML protocol description.
// It corresponds to any single value. // It corresponds to any single value.
type SingleField struct { type SingleField struct {
@ -289,35 +315,72 @@ func (f *ValueField) Initialize(p *Protocol) {
} }
// SwitchField represents a 'switch' element in the XML protocol description // SwitchField represents a 'switch' element in the XML protocol description
// file. It is not currently used. (i.e., it is XKB voodoo.) // file.
// Currently we translate this to a slice of uint32 and let the user sort
// through it.
type SwitchField struct { type SwitchField struct {
xmlName string
Name string Name string
MaskName string
Expr Expression Expr Expression
Bitcases []*Bitcase Bitcases []*Bitcase
} }
func (f *SwitchField) SrcName() string { func (f *SwitchField) SrcName() string {
panic("it is illegal to call SrcName on a SwitchField field") return f.Name
} }
func (f *SwitchField) XmlName() string { func (f *SwitchField) XmlName() string {
panic("it is illegal to call XmlName on a SwitchField field") return f.xmlName
} }
func (f *SwitchField) SrcType() string { func (f *SwitchField) SrcType() string {
panic("it is illegal to call SrcType on a SwitchField field") return "[]uint32"
} }
// 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 { func (f *SwitchField) Size() Size {
return newFixedSize(0, true) // TODO: size expression used here is not correct unless every element of
// the switch is 32 bit long. This assumption holds for xproto but may not
// hold for other protocols (xkb?)
listSize := newExpressionSize(&Function{
Name: "xgb.Pad",
Expr: &BinaryOp{
Op: "*",
Expr1: &Value{v: 4},
Expr2: &PopCount{
Expr: &Function{
Name: "int",
Expr: &FieldRef{
Name: f.MaskName,
},
},
},
},
}, true)
return listSize
}
func (f *SwitchField) ListLength() Size {
return newExpressionSize(&PopCount{
Expr: &Function{
Name: "int",
Expr: &FieldRef{
Name: f.MaskName,
},
},
}, true)
} }
func (f *SwitchField) Initialize(p *Protocol) { func (f *SwitchField) Initialize(p *Protocol) {
f.xmlName = f.Name
f.Name = SrcName(p, f.Name) f.Name = SrcName(p, f.Name)
f.Expr.Initialize(p) f.Expr.Initialize(p)
fieldref, ok := f.Expr.(*FieldRef)
if !ok {
panic("switch field's expression not a fieldref")
}
f.MaskName = SrcName(p, fieldref.Name)
for _, bitcase := range f.Bitcases { for _, bitcase := range f.Bitcases {
bitcase.Expr.Initialize(p) bitcase.Expr.Initialize(p)
for _, field := range bitcase.Fields { for _, field := range bitcase.Fields {

View File

@ -186,11 +186,8 @@ func (f *ValueField) Read(c *Context, prefix string) {
} }
func (f *ValueField) Write(c *Context, prefix string) { func (f *ValueField) Write(c *Context, prefix string) {
// big time mofos WriteSimpleSingleField(c,
if rq, ok := f.Parent.(*Request); !ok || rq.SrcName() != "ConfigureWindow" { fmt.Sprintf("%s%s", prefix, f.MaskName), f.MaskType)
WriteSimpleSingleField(c,
fmt.Sprintf("%s%s", prefix, f.MaskName), f.MaskType)
}
c.Putln("for i := 0; i < %s; i++ {", f.ListLength().Reduce(prefix)) c.Putln("for i := 0; i < %s; i++ {", f.ListLength().Reduce(prefix))
c.Putln("xgb.Put32(buf[b:], %s%s[i])", prefix, f.ListName) c.Putln("xgb.Put32(buf[b:], %s%s[i])", prefix, f.ListName)
c.Putln("b += 4") c.Putln("b += 4")
@ -200,16 +197,24 @@ func (f *ValueField) Write(c *Context, prefix string) {
// Switch field // Switch field
func (f *SwitchField) Define(c *Context) { func (f *SwitchField) Define(c *Context) {
c.Putln("// switch field: %s (%s)", f.Name, f.Expr) c.Putln("%s []uint32", f.Name)
panic("todo")
} }
func (f *SwitchField) Read(c *Context, prefix string) { func (f *SwitchField) Read(c *Context, prefix string) {
c.Putln("// reading switch field: %s (%s)", f.Name, f.Expr) c.Putln("")
panic("todo") c.Putln("%s%s = make([]uint32, %s)",
prefix, f.Name, f.ListLength().Reduce(prefix))
c.Putln("for i := 0; i < %s; i++ {", f.ListLength().Reduce(prefix))
c.Putln("%s%s[i] = xgb.Get32(buf[b:])", prefix, f.Name)
c.Putln("b += 4")
c.Putln("}")
c.Putln("b = xgb.Pad(b)")
} }
func (f *SwitchField) Write(c *Context, prefix string) { func (f *SwitchField) Write(c *Context, prefix string) {
c.Putln("// writing switch field: %s (%s)", f.Name, f.Expr) c.Putln("for i := 0; i < %s; i++ {", f.ListLength().Reduce(prefix))
panic("todo") c.Putln("xgb.Put32(buf[b:], %s%s[i])", prefix, f.Name)
c.Putln("b += 4")
c.Putln("}")
c.Putln("b = xgb.Pad(b)")
} }

View File

@ -205,10 +205,7 @@ func (r *Request) ParamNames() string {
for _, field := range r.Fields { for _, field := range r.Fields {
switch f := field.(type) { switch f := field.(type) {
case *ValueField: case *ValueField:
// mofos... names = append(names, f.MaskName)
if r.SrcName() != "ConfigureWindow" {
names = append(names, f.MaskName)
}
names = append(names, f.ListName) names = append(names, f.ListName)
case *PadField: case *PadField:
continue continue
@ -226,17 +223,16 @@ func (r *Request) ParamNameTypes() string {
for _, field := range r.Fields { for _, field := range r.Fields {
switch f := field.(type) { switch f := field.(type) {
case *ValueField: case *ValueField:
// mofos... nameTypes = append(nameTypes,
if r.SrcName() != "ConfigureWindow" { fmt.Sprintf("%s %s", f.MaskName, f.MaskType.SrcName()))
nameTypes = append(nameTypes,
fmt.Sprintf("%s %s", f.MaskName, f.MaskType.SrcName()))
}
nameTypes = append(nameTypes, nameTypes = append(nameTypes,
fmt.Sprintf("%s []uint32", f.ListName)) fmt.Sprintf("%s []uint32", f.ListName))
case *PadField: case *PadField:
continue continue
case *ExprField: case *ExprField:
continue continue
case *RequiredStartAlign:
continue
default: default:
nameTypes = append(nameTypes, nameTypes = append(nameTypes,
fmt.Sprintf("%s %s", field.SrcName(), field.SrcType())) fmt.Sprintf("%s %s", field.SrcName(), field.SrcType()))

View File

@ -105,17 +105,15 @@ func (r *Request) Size(c *Context) Size {
} }
for _, field := range r.Fields { for _, field := range r.Fields {
switch field.(type) { switch field := field.(type) {
case *LocalField: // local fields don't go over the wire case *LocalField: // local fields don't go over the wire
continue continue
case *SingleField: case *SingleField:
// mofos!!! fsz := field.Size()
if r.SrcName() == "ConfigureWindow" && if _, isstruct := field.Type.(*Struct); isstruct {
field.SrcName() == "ValueMask" { fsz.Expression = fsz.Expression.Specialize(field.SrcName())
continue
} }
size = size.Add(field.Size()) size = size.Add(fsz)
default: default:
size = size.Add(field.Size()) size = size.Add(field.Size())
} }

View File

@ -325,12 +325,14 @@ func (x *XMLField) Translate(parent interface{}) Field {
case "pad": case "pad":
return &PadField{ return &PadField{
Bytes: x.Bytes, Bytes: x.Bytes,
Align: x.Align,
} }
case "field": case "field":
return &SingleField{ s := &SingleField{
xmlName: x.Name, xmlName: x.Name,
Type: newTranslation(x.Type), Type: newTranslation(x.Type),
} }
return s
case "list": case "list":
return &ListField{ return &ListField{
xmlName: x.Name, xmlName: x.Name,
@ -365,6 +367,8 @@ func (x *XMLField) Translate(parent interface{}) Field {
swtch.Bitcases[i] = bitcase.Translate() swtch.Bitcases[i] = bitcase.Translate()
} }
return swtch return swtch
case "required_start_align":
return &RequiredStartAlign{}
} }
log.Panicf("Unrecognized field element: %s", x.XMLName.Local) log.Panicf("Unrecognized field element: %s", x.XMLName.Local)

View File

@ -10,6 +10,7 @@ type XMLField struct {
// For 'pad' element // For 'pad' element
Bytes uint `xml:"bytes,attr"` Bytes uint `xml:"bytes,attr"`
Align uint16 `xml:"align,attr"`
// For 'field', 'list', 'localfield', 'exprfield' and 'switch' elements. // For 'field', 'list', 'localfield', 'exprfield' and 'switch' elements.
Name string `xml:"name,attr"` Name string `xml:"name,attr"`