aboutsummaryrefslogtreecommitdiff
path: root/nexgb/xgbgen/field.go
blob: 58f54c838ea3e63fc218f17bc52ef325511447a5 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
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
}