diff options
| author | Andrew Gallant (Ocelot) <Andrew.Gallant@tufts.edu> | 2012-04-28 23:25:57 -0400 | 
|---|---|---|
| committer | Andrew Gallant (Ocelot) <Andrew.Gallant@tufts.edu> | 2012-04-28 23:25:57 -0400 | 
| commit | 52a21b415ad95b2c4649254447388cb329cee1a4 (patch) | |
| tree | 0897f4033cc6251c7feb85fe9765159a3d0608eb /nexgb/xgbgen/xml_fields.go | |
| download | haven-52a21b415ad95b2c4649254447388cb329cee1a4.tar.gz haven-52a21b415ad95b2c4649254447388cb329cee1a4.tar.xz haven-52a21b415ad95b2c4649254447388cb329cee1a4.zip  | |
initial commit. not currently in a working state.
Diffstat (limited to 'nexgb/xgbgen/xml_fields.go')
| -rw-r--r-- | nexgb/xgbgen/xml_fields.go | 147 | 
1 files changed, 147 insertions, 0 deletions
diff --git a/nexgb/xgbgen/xml_fields.go b/nexgb/xgbgen/xml_fields.go new file mode 100644 index 0000000..18be6e3 --- /dev/null +++ b/nexgb/xgbgen/xml_fields.go @@ -0,0 +1,147 @@ +package main +/* +	A series of fields should be taken as "structure contents", and *not* +	just the single 'field' elements. Namely, 'fields' subsumes 'field' +	elements. + +	More particularly, 'fields' corresponds to list, in order, of any of the +	follow elements: pad, field, list, localfield, exprfield, valueparm +	and switch. + +	Thus, the 'Field' type must contain the union of information corresponding +	to all aforementioned fields. + +	This would ideally be a better job for interfaces, but I could not figure +	out how to make them jive with Go's XML package. (And I don't really feel +	up to type translation.) +*/ + +import ( +	"encoding/xml" +	"fmt" +	"log" +	"strings" +) + +type Field struct { +	XMLName xml.Name + +	// For 'pad' element +	Bytes int `xml:"bytes,attr"` + +	// For 'field', 'list', 'localfield', 'exprfield' and 'switch' elements. +	Name string `xml:"name,attr"` + +	// For 'field', 'list', 'localfield', and 'exprfield' elements. +	Type Type `xml:"type,attr"` + +	// For 'list', 'exprfield' and 'switch' elements. +	Expr *Expression `xml:",any"` + +	// For 'valueparm' element. +	ValueMaskType Type `xml:"value-mask-type,attr"` +	ValueMaskName string `xml:"value-mask-name,attr"` +	ValueListName string `xml:"value-list-name,attr"` + +	// For 'switch' element. +	Bitcases []*Bitcase `xml:"bitcase"` + +	// I don't know which elements these are for. The documentation is vague. +	// They also seem to be completely optional. +	OptEnum Type `xml:"enum,attr"` +	OptMask Type `xml:"mask,attr"` +	OptAltEnum Type `xml:"altenum,attr"` +} + +// String is for debugging purposes. +func (f *Field) String() string { +	switch f.XMLName.Local { +	case "pad": +		return fmt.Sprintf("pad (%d bytes)", f.Bytes) +	case "field": +		return fmt.Sprintf("field (type = '%s', name = '%s')", f.Type, f.Name) +	case "list": +		return fmt.Sprintf("list (type = '%s', name = '%s', length = '%s')", +			f.Type, f.Name, f.Expr) +	case "localfield": +		return fmt.Sprintf("localfield (type = '%s', name = '%s')", +			f.Type, f.Name) +	case "exprfield": +		return fmt.Sprintf("exprfield (type = '%s', name = '%s', expr = '%s')", +			f.Type, f.Name, f.Expr) +	case "valueparam": +		return fmt.Sprintf("valueparam (type = '%s', name = '%s', list = '%s')", +			f.ValueMaskType, f.ValueMaskName, f.ValueListName) +	case "switch": +		bitcases := make([]string, len(f.Bitcases)) +		for i, bitcase := range f.Bitcases { +			bitcases[i] = bitcase.StringPrefix("\t") +		} +		return fmt.Sprintf("switch (name = '%s', expr = '%s')\n\t%s", +			f.Name, f.Expr, strings.Join(bitcases, "\n\t")) +	default: +		log.Panicf("Unrecognized field element: %s", f.XMLName.Local) +	} + +	panic("unreachable") +} + +// 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 Bitcase struct { +	Fields []*Field `xml:",any"` + +	// All the different expressions. +	// When it comes time to choose one, use the 'Expr' method. +	ExprOp *Expression `xml:"op"` +	ExprUnOp *Expression `xml:"unop"` +	ExprField *Expression `xml:"fieldref"` +	ExprValue *Expression `xml:"value"` +	ExprBit *Expression `xml:"bit"` +	ExprEnum *Expression `xml:"enumref"` +	ExprSum *Expression `xml:"sumof"` +	ExprPop *Expression `xml:"popcount"` +} + +// StringPrefix is for debugging purposes only. +// StringPrefix takes a string to prefix to every extra line for formatting. +func (b *Bitcase) StringPrefix(prefix string) string { +	fields := make([]string, len(b.Fields)) +	for i, field := range b.Fields { +		fields[i] = fmt.Sprintf("%s%s", prefix, field) +	} +	return fmt.Sprintf("%s\n\t%s%s", b.Expr(), prefix, +		strings.Join(fields, "\n\t")) +} + +// Expr chooses the only non-nil Expr* field from Bitcase. +// Panic if there is more than one non-nil expression. +func (b *Bitcase) Expr() *Expression { +	choices := []*Expression{ +		b.ExprOp, b.ExprUnOp, b.ExprField, b.ExprValue, +		b.ExprBit, b.ExprEnum, b.ExprSum, b.ExprPop, +	} + +	var choice *Expression = 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 +}  | 
