package main import ( "fmt" "log" "strings" ) // Field corresponds to any field described in an XML protocol description // file. This includes struct fields, union fields, request fields, // reply fields and so on. // To make code generation easier, fields that have types are also stored. // Note that not all fields support all methods defined in this interface. // For instance, a padding field does not have a source name. type Field interface { // Initialize sets up the source name of this field. Initialize(p *Protocol) // SrcName is the Go source name of this field. SrcName() string // XmlName is the name of this field from the XML file. XmlName() string // SrcType is the Go source type name of this field. SrcType() string // Size returns an expression that computes the size (in bytes) // of this field. Size() Size // Define writes the Go code to declare this field (in a struct definition). Define(c *Context) // Read writes the Go code to convert a byte slice to a Go value // of this field. // 'prefix' is the prefix of the name of the Go value. Read(c *Context, prefix string) // Write writes the Go code to convert a Go value to a byte slice of // this field. // 'prefix' is the prefix of the name of the Go value. Write(c *Context, prefix string) } func (pad *PadField) Initialize(p *Protocol) {} // PadField represents any type of padding. It is omitted from // definitions, but is used in Read/Write to increment the buffer index. // It is also used in size calculation. type PadField struct { Bytes uint Align uint16 } 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 (f *PadField) SrcType() string { panic("it is illegal to call SrcType on a PadField field") } func (p *PadField) Size() Size { if p.Align > 0 { return newFixedSize(uint(p.Align), false) } else { return newFixedSize(p.Bytes, true) } } 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. // It corresponds to any single value. type SingleField struct { srcName string xmlName string Type Type } func (f *SingleField) Initialize(p *Protocol) { f.srcName = SrcName(p, f.XmlName()) f.Type = f.Type.(*Translation).RealType(p) } func (f *SingleField) SrcName() string { if f.srcName == "Bytes" { return "Bytes_" } return f.srcName } func (f *SingleField) XmlName() string { return f.xmlName } func (f *SingleField) SrcType() string { return f.Type.SrcName() } func (f *SingleField) Size() Size { return f.Type.Size() } // ListField represents a list of values. 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) SrcType() string { if strings.ToLower(f.Type.XmlName()) == "char" { return fmt.Sprintf("string") } return fmt.Sprintf("[]%s", f.Type.SrcName()) } // Length computes the *number* of values in a list. // If this ListField does not have any length expression, we throw our hands // up and simply compute the 'len' of the field name of this list. func (f *ListField) Length() Size { if f.LengthExpr == nil { return newExpressionSize(&Function{ Name: "len", Expr: &FieldRef{ Name: f.SrcName(), }, }, true) } return newExpressionSize(f.LengthExpr, true) } // Size computes the *size* of a list (in bytes). // It it typically a simple matter of multiplying the length of the list by // the size of the type of the list. // But if it's a list of struct where the struct has a list field, we use a // special function written in go_struct.go to compute the size (since the // size in this case can only be computed recursively). func (f *ListField) Size() Size { elsz := f.Type.Size() simpleLen := &Padding{ Expr: newBinaryOp("*", f.Length().Expression, elsz.Expression), } switch field := f.Type.(type) { case *Struct: if field.HasList() { sizeFun := &Function{ Name: fmt.Sprintf("%sListSize", f.Type.SrcName()), Expr: &FieldRef{Name: f.SrcName()}, } return newExpressionSize(sizeFun, elsz.exact) } else { return newExpressionSize(simpleLen, elsz.exact) } case *Union: return newExpressionSize(simpleLen, elsz.exact) case *Base: return newExpressionSize(simpleLen, elsz.exact) case *Resource: return newExpressionSize(simpleLen, elsz.exact) case *TypeDef: return newExpressionSize(simpleLen, elsz.exact) default: log.Panicf("Cannot compute list size with type '%T'.", f.Type) } panic("unreachable") } func (f *ListField) Initialize(p *Protocol) { f.srcName = SrcName(p, f.XmlName()) f.Type = f.Type.(*Translation).RealType(p) if f.LengthExpr != nil { f.LengthExpr.Initialize(p) } } // LocalField is exactly the same as a regular SingleField, except it isn't // sent over the wire. (i.e., it's probably used to compute an ExprField). type LocalField struct { *SingleField } // ExprField is a field that is not parameterized, but is computed from values // of other fields. 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) SrcType() string { return f.Type.SrcName() } func (f *ExprField) Size() Size { return f.Type.Size() } func (f *ExprField) Initialize(p *Protocol) { f.srcName = SrcName(p, f.XmlName()) f.Type = f.Type.(*Translation).RealType(p) f.Expr.Initialize(p) } // ValueField represents two fields in one: a mask and a list of 4-byte // integers. The mask specifies which kinds of values are in the list. // (i.e., See ConfigureWindow, CreateWindow, ChangeWindowAttributes, etc.) type ValueField struct { Parent interface{} 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) SrcType() string { return f.MaskType.SrcName() } // Size computes the size in bytes of the combination of the mask and list // in this value field. // The expression to compute this looks complicated, but it's really just // the number of bits set in the mask multiplied 4 (and padded of course). func (f *ValueField) Size() Size { maskSize := f.MaskType.Size() 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 maskSize.Add(listSize) } func (f *ValueField) ListLength() Size { return newExpressionSize(&PopCount{ Expr: &Function{ Name: "int", Expr: &FieldRef{ Name: f.MaskName, }, }, }, true) } func (f *ValueField) Initialize(p *Protocol) { f.MaskType = f.MaskType.(*Translation).RealType(p) f.MaskName = SrcName(p, f.MaskName) f.ListName = SrcName(p, f.ListName) } // SwitchField represents a 'switch' element in the XML protocol description // file. // Currently we translate this to a slice of uint32 and let the user sort // through it. type SwitchField struct { xmlName string Name string MaskName string Expr Expression Bitcases []*Bitcase } func (f *SwitchField) SrcName() string { return f.Name } func (f *SwitchField) XmlName() string { return f.xmlName } func (f *SwitchField) SrcType() string { return "[]uint32" } func (f *SwitchField) Size() Size { // 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) { f.xmlName = f.Name f.Name = SrcName(p, f.Name) 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 { bitcase.Expr.Initialize(p) for _, field := range bitcase.Fields { field.Initialize(p) } } } // Bitcase represents a single bitcase inside a switch expression. // It is not currently used. (i.e., it's XKB voodoo.) type Bitcase struct { Fields []Field Expr Expression }