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 +} |