aboutsummaryrefslogtreecommitdiff
path: root/nexgb/xgbgen/type.go
diff options
context:
space:
mode:
Diffstat (limited to 'nexgb/xgbgen/type.go')
-rw-r--r--nexgb/xgbgen/type.go390
1 files changed, 390 insertions, 0 deletions
diff --git a/nexgb/xgbgen/type.go b/nexgb/xgbgen/type.go
new file mode 100644
index 0000000..59f1a2d
--- /dev/null
+++ b/nexgb/xgbgen/type.go
@@ -0,0 +1,390 @@
+package main
+
+import (
+ "fmt"
+ "strings"
+)
+
+type Type interface {
+ Initialize(p *Protocol)
+ SrcName() string
+ XmlName() string
+ Size() Size
+
+ Define(c *Context)
+}
+
+type Types []Type
+
+func (ts Types) Len() int { return len(ts) }
+func (ts Types) Swap(i, j int) { ts[i], ts[j] = ts[j], ts[i] }
+func (ts Types) Less(i, j int) bool {
+ x1, x2 := ts[i].XmlName(), ts[j].XmlName()
+ s1, s2 := ts[i].SrcName(), ts[j].SrcName()
+ return (s1 == s2 && x1 < x2) || s1 < s2
+}
+
+// Translation is used *only* when transitioning from XML types to
+// our better representation. They are placeholders for the real types (below)
+// that will replace them.
+type Translation struct {
+ xmlName string
+}
+
+func newTranslation(name string) *Translation {
+ return &Translation{xmlName: name}
+}
+
+// RealType takes 'XmlName' and finds its real concrete type in our Protocol.
+// It is an error if we can't find such a type.
+func (t *Translation) RealType(p *Protocol) Type {
+ // Check to see if there is a namespace. If so, strip it and use it to
+ // make sure we only look for a type in that protocol.
+ namespace, typeName := "", t.XmlName()
+ if ni := strings.Index(t.XmlName(), ":"); ni > -1 {
+ namespace, typeName = strings.ToLower(typeName[:ni]), typeName[ni+1:]
+ }
+
+ if len(namespace) == 0 || namespace == strings.ToLower(p.Name) {
+ for _, typ := range p.Types {
+ if typeName == typ.XmlName() {
+ return typ
+ }
+ }
+ }
+ for _, imp := range p.Imports {
+ if len(namespace) == 0 || namespace == strings.ToLower(imp.Name) {
+ for _, typ := range imp.Types {
+ if typeName == typ.XmlName() {
+ return typ
+ }
+ }
+ }
+ }
+ panic("Could not find real type for translation type: " + t.XmlName())
+}
+
+func (t *Translation) SrcName() string {
+ panic("it is illegal to call SrcName on a translation type")
+}
+
+func (t *Translation) XmlName() string {
+ return t.xmlName
+}
+
+func (t *Translation) Size() Size {
+ panic("it is illegal to call Size on a translation type")
+}
+
+func (t *Translation) Define(c *Context) {
+ panic("it is illegal to call Define on a translation type")
+}
+
+func (t *Translation) Initialize(p *Protocol) {
+ panic("it is illegal to call Initialize on a translation type")
+}
+
+type Base struct {
+ srcName string
+ xmlName string
+ size Size
+}
+
+func (b *Base) SrcName() string {
+ return b.srcName
+}
+
+func (b *Base) XmlName() string {
+ return b.xmlName
+}
+
+func (b *Base) Size() Size {
+ return b.size
+}
+
+func (b *Base) Initialize(p *Protocol) {
+ b.srcName = TypeSrcName(p, b)
+}
+
+type Enum struct {
+ srcName string
+ xmlName string
+ Items []*EnumItem
+}
+
+type EnumItem struct {
+ srcName string
+ xmlName string
+ Expr Expression
+}
+
+func (enum *Enum) SrcName() string {
+ return enum.srcName
+}
+
+func (enum *Enum) XmlName() string {
+ return enum.xmlName
+}
+
+func (enum *Enum) Size() Size {
+ panic("Cannot take size of enum")
+}
+
+func (enum *Enum) Initialize(p *Protocol) {
+ enum.srcName = TypeSrcName(p, enum)
+ for _, item := range enum.Items {
+ item.srcName = SrcName(p, item.xmlName)
+ if item.Expr != nil {
+ item.Expr.Initialize(p)
+ }
+ }
+}
+
+type Resource struct {
+ srcName string
+ xmlName string
+}
+
+func (r *Resource) SrcName() string {
+ return r.srcName
+}
+
+func (r *Resource) XmlName() string {
+ return r.xmlName
+}
+
+func (r *Resource) Size() Size {
+ return newFixedSize(BaseTypeSizes["Id"], true)
+}
+
+func (r *Resource) Initialize(p *Protocol) {
+ r.srcName = TypeSrcName(p, r)
+}
+
+type TypeDef struct {
+ srcName string
+ xmlName string
+ Old Type
+}
+
+func (t *TypeDef) SrcName() string {
+ return t.srcName
+}
+
+func (t *TypeDef) XmlName() string {
+ return t.xmlName
+}
+
+func (t *TypeDef) Size() Size {
+ return t.Old.Size()
+}
+
+func (t *TypeDef) Initialize(p *Protocol) {
+ t.Old = t.Old.(*Translation).RealType(p)
+ t.srcName = TypeSrcName(p, t)
+}
+
+type Event struct {
+ srcName string
+ xmlName string
+ Number int
+ NoSequence bool
+ Fields []Field
+}
+
+func (e *Event) SrcName() string {
+ return e.srcName
+}
+
+func (e *Event) XmlName() string {
+ return e.xmlName
+}
+
+func (e *Event) Size() Size {
+ return newExpressionSize(&Value{v: 32}, true)
+}
+
+func (e *Event) Initialize(p *Protocol) {
+ e.srcName = TypeSrcName(p, e)
+ for _, field := range e.Fields {
+ field.Initialize(p)
+ }
+}
+
+func (e *Event) EvType() string {
+ return fmt.Sprintf("%sEvent", e.srcName)
+}
+
+type EventCopy struct {
+ srcName string
+ xmlName string
+ Old Type
+ Number int
+}
+
+func (e *EventCopy) SrcName() string {
+ return e.srcName
+}
+
+func (e *EventCopy) XmlName() string {
+ return e.xmlName
+}
+
+func (e *EventCopy) Size() Size {
+ return newExpressionSize(&Value{v: 32}, true)
+}
+
+func (e *EventCopy) Initialize(p *Protocol) {
+ e.srcName = TypeSrcName(p, e)
+ e.Old = e.Old.(*Translation).RealType(p)
+ if _, ok := e.Old.(*Event); !ok {
+ panic("an EventCopy's old type *must* be *Event")
+ }
+}
+
+func (e *EventCopy) EvType() string {
+ return fmt.Sprintf("%sEvent", e.srcName)
+}
+
+type Error struct {
+ srcName string
+ xmlName string
+ Number int
+ Fields []Field
+}
+
+func (e *Error) SrcName() string {
+ return e.srcName
+}
+
+func (e *Error) XmlName() string {
+ return e.xmlName
+}
+
+func (e *Error) Size() Size {
+ return newExpressionSize(&Value{v: 32}, true)
+}
+
+func (e *Error) Initialize(p *Protocol) {
+ e.srcName = TypeSrcName(p, e)
+ for _, field := range e.Fields {
+ field.Initialize(p)
+ }
+}
+
+func (e *Error) ErrConst() string {
+ return fmt.Sprintf("Bad%s", e.srcName)
+}
+
+func (e *Error) ErrType() string {
+ return fmt.Sprintf("%sError", e.srcName)
+}
+
+type ErrorCopy struct {
+ srcName string
+ xmlName string
+ Old Type
+ Number int
+}
+
+func (e *ErrorCopy) SrcName() string {
+ return e.srcName
+}
+
+func (e *ErrorCopy) XmlName() string {
+ return e.xmlName
+}
+
+func (e *ErrorCopy) Size() Size {
+ return newExpressionSize(&Value{v: 32}, true)
+}
+
+func (e *ErrorCopy) Initialize(p *Protocol) {
+ e.srcName = TypeSrcName(p, e)
+ e.Old = e.Old.(*Translation).RealType(p)
+ if _, ok := e.Old.(*Error); !ok {
+ panic("an ErrorCopy's old type *must* be *Event")
+ }
+}
+
+func (e *ErrorCopy) ErrConst() string {
+ return fmt.Sprintf("Bad%s", e.srcName)
+}
+
+func (e *ErrorCopy) ErrType() string {
+ return fmt.Sprintf("%sError", e.srcName)
+}
+
+type Struct struct {
+ srcName string
+ xmlName string
+ Fields []Field
+}
+
+func (s *Struct) SrcName() string {
+ return s.srcName
+}
+
+func (s *Struct) XmlName() string {
+ return s.xmlName
+}
+
+func (s *Struct) Size() Size {
+ size := newFixedSize(0, true)
+ for _, field := range s.Fields {
+ size = size.Add(field.Size())
+ }
+ return size
+}
+
+func (s *Struct) Initialize(p *Protocol) {
+ s.srcName = TypeSrcName(p, s)
+ for _, field := range s.Fields {
+ field.Initialize(p)
+ }
+}
+
+// HasList returns whether there is a field in this struct that is a list.
+// When true, a more involved calculation is necessary to compute this struct's
+// size.
+func (s *Struct) HasList() bool {
+ for _, field := range s.Fields {
+ if _, ok := field.(*ListField); ok {
+ return true
+ }
+ }
+ return false
+}
+
+type Union struct {
+ srcName string
+ xmlName string
+ Fields []Field
+}
+
+func (u *Union) SrcName() string {
+ return u.srcName
+}
+
+func (u *Union) XmlName() string {
+ return u.xmlName
+}
+
+// Size for Union is broken. At least, it's broken for XKB.
+// It *looks* like the protocol inherently relies on some amount of
+// memory unsafety, since some members of unions in XKB are *variable* in
+// length! The only thing I can come up with, maybe, is when a union has
+// variable size, simply return the raw bytes. Then it's up to the user to
+// pass those raw bytes into the appropriate New* constructor. GROSS!
+// As of now, just pluck out the first field and return that size. This
+// should work for union elements in randr.xml and xproto.xml.
+func (u *Union) Size() Size {
+ return u.Fields[0].Size()
+}
+
+func (u *Union) Initialize(p *Protocol) {
+ u.srcName = fmt.Sprintf("%sUnion", TypeSrcName(p, u))
+ for _, field := range u.Fields {
+ field.Initialize(p)
+ }
+}