aboutsummaryrefslogtreecommitdiff
path: root/nexgb/xgbgen/xml_fields.go
blob: b72159b99e621df93c7a1321aa4a9c10584b9d0f (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
package main

import (
	"encoding/xml"
	"log"
)

type XMLField struct {
	XMLName xml.Name

	// For 'pad' element
	Bytes uint   `xml:"bytes,attr"`
	Align uint16 `xml:"align,attr"`

	// For 'field', 'list', 'localfield', 'exprfield' and 'switch' elements.
	Name string `xml:"name,attr"`

	// For 'field', 'list', 'localfield', and 'exprfield' elements.
	Type string `xml:"type,attr"`

	// For 'list', 'exprfield' and 'switch' elements.
	Expr *XMLExpression `xml:",any"`

	// For 'valueparm' element.
	ValueMaskType string `xml:"value-mask-type,attr"`
	ValueMaskName string `xml:"value-mask-name,attr"`
	ValueListName string `xml:"value-list-name,attr"`

	// For 'switch' element.
	Bitcases []*XMLBitcase `xml:"bitcase"`

	// I don't know which elements these are for. The documentation is vague.
	// They also seem to be completely optional.
	OptEnum    string `xml:"enum,attr"`
	OptMask    string `xml:"mask,attr"`
	OptAltEnum string `xml:"altenum,attr"`
}

// Bitcase represents a single expression followed by any number of fields.
// Namely, if the switch's expression (all bitcases are inside a switch),
// and'd with the bitcase's expression is equal to the bitcase expression,
// then the fields should be included in its parent structure.
// Note that since a bitcase is unique in that expressions and fields are
// siblings, we must exhaustively search for one of them. Essentially,
// it's the closest thing to a Union I can get to in Go without interfaces.
// Would an '<expression>' tag have been too much to ask? :-(
type XMLBitcase struct {
	Fields []*XMLField `xml:",any"`

	// All the different expressions.
	// When it comes time to choose one, use the 'Expr' method.
	ExprOp    *XMLExpression `xml:"op"`
	ExprUnOp  *XMLExpression `xml:"unop"`
	ExprField *XMLExpression `xml:"fieldref"`
	ExprValue *XMLExpression `xml:"value"`
	ExprBit   *XMLExpression `xml:"bit"`
	ExprEnum  *XMLExpression `xml:"enumref"`
	ExprSum   *XMLExpression `xml:"sumof"`
	ExprPop   *XMLExpression `xml:"popcount"`
}

// Expr chooses the only non-nil Expr* field from Bitcase.
// Panic if there is more than one non-nil expression.
func (b *XMLBitcase) Expr() *XMLExpression {
	choices := []*XMLExpression{
		b.ExprOp, b.ExprUnOp, b.ExprField, b.ExprValue,
		b.ExprBit, b.ExprEnum, b.ExprSum, b.ExprPop,
	}

	var choice *XMLExpression = nil
	numNonNil := 0
	for _, c := range choices {
		if c != nil {
			numNonNil++
			choice = c
		}
	}

	if choice == nil {
		log.Panicf("No top level expression found in a bitcase.")
	}
	if numNonNil > 1 {
		log.Panicf("More than one top-level expression was found in a bitcase.")
	}
	return choice
}