diff options
| -rw-r--r-- | nexgb/xgbgen/field.go | 27 | ||||
| -rw-r--r-- | nexgb/xgbgen/go_error.go | 30 | ||||
| -rw-r--r-- | nexgb/xgbgen/go_event.go | 97 | ||||
| -rw-r--r-- | nexgb/xgbgen/go_list.go | 10 | ||||
| -rw-r--r-- | nexgb/xgbgen/go_single_field.go | 36 | ||||
| -rw-r--r-- | nexgb/xgbgen/go_struct.go | 9 | ||||
| -rw-r--r-- | nexgb/xgbgen/go_union.go | 134 | ||||
| -rw-r--r-- | nexgb/xgbgen/type.go | 4 | 
8 files changed, 313 insertions, 34 deletions
| diff --git a/nexgb/xgbgen/field.go b/nexgb/xgbgen/field.go index 0f2323e..6d39af2 100644 --- a/nexgb/xgbgen/field.go +++ b/nexgb/xgbgen/field.go @@ -9,6 +9,7 @@ type Field interface {  	Initialize(p *Protocol)  	SrcName() string  	XmlName() string +	SrcType() string  	Size() Size  	Define(c *Context) @@ -30,6 +31,10 @@ 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 SwitchField field") +} +  func (p *PadField) Size() Size {  	return newFixedSize(p.Bytes)  } @@ -53,6 +58,10 @@ 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()  } @@ -72,9 +81,9 @@ func (f *ListField) XmlName() string {  	return f.xmlName  } -// func (f *ListField) Size() Size {  -	// return newExpressionSize(f.LengthExpr).Multiply(f.Type.Size())  -// }  +func (f *ListField) SrcType() string { +	return fmt.Sprintf("[]%s", f.Type.SrcName()) +}  func (f *ListField) Size() Size {  	simpleLen := &Function{ @@ -126,6 +135,10 @@ 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()  } @@ -150,6 +163,10 @@ 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() +} +  func (f *ValueField) Size() Size {  	return f.MaskType.Size()  } @@ -174,6 +191,10 @@ func (f *SwitchField) XmlName() string {  	panic("it is illegal to call XmlName on a SwitchField field")  } +func (f *SwitchField) SrcType() string { +	panic("it is illegal to call SrcType on a SwitchField field") +} +  // XXX: This is a bit tricky. The size has to be represented as a non-concrete  // expression that finds *which* bitcase fields are included, and sums the  // sizes of those fields. diff --git a/nexgb/xgbgen/go_error.go b/nexgb/xgbgen/go_error.go index 0cb77cc..493a8b9 100644 --- a/nexgb/xgbgen/go_error.go +++ b/nexgb/xgbgen/go_error.go @@ -22,18 +22,36 @@ func (e *ErrorCopy) Define(c *Context) {  	c.Putln("")  	c.Putln("type %s %s", e.ErrType(), e.Old.(*Error).ErrType())  	c.Putln("") + +	// Read defines a function that transforms a byte slice into this +	// error struct. +	e.Read(c) + +	// Write defines a function that transoforms this error struct into +	// a byte slice. +	e.Write(c) + +	// Makes sure that this error type is an Error interface. +	c.Putln("func (err %s) ImplementsError() { }", e.ErrType()) +	c.Putln("") + +	// Let's the XGB know how to read this error. +	c.Putln("func init() {") +	c.Putln("newErrorFuncs[%d] = New%s", e.Number, e.SrcName()) +	c.Putln("}") +	c.Putln("") +} + +func (e *ErrorCopy) Read(c *Context) {  	c.Putln("func New%s(buf []byte) %s {", e.SrcName(), e.ErrType())  	c.Putln("return (%s)(New%s(buf))", e.ErrType(), e.Old.SrcName())  	c.Putln("}")  	c.Putln("") -	c.Putln("func (err %s) ImplementsError() { }", e.ErrType()) -	c.Putln("") +} + +func (e *ErrorCopy) Write(c *Context) {  	c.Putln("func (err %s) Bytes() []byte {", e.ErrType())  	c.Putln("return (%s)(err).Bytes()", e.Old.(*Error).ErrType())  	c.Putln("}")  	c.Putln("") -	c.Putln("func init() {") -	c.Putln("newErrorFuncs[%d] = New%s", e.Number, e.SrcName()) -	c.Putln("}") -	c.Putln("")  } diff --git a/nexgb/xgbgen/go_event.go b/nexgb/xgbgen/go_event.go index d91fd7a..e6d40b0 100644 --- a/nexgb/xgbgen/go_event.go +++ b/nexgb/xgbgen/go_event.go @@ -3,14 +3,75 @@ package main  // Event types  func (e *Event) Define(c *Context) {  	c.Putln("// Event definition %s (%d)", e.SrcName(), e.Number) +	c.Putln("// Size: %s", e.Size()) +	c.Putln("type %s struct {", e.EvType()) +	c.Putln("Sequence uint16") +	for _, field := range e.Fields { +		field.Define(c) +	} +	c.Putln("}") +	c.Putln("") + +	// Read defines a function that transforms a byte slice into this +	// event struct. +	e.Read(c) + +	// Write defines a function that transoforms this event struct into +	// a byte slice. +	e.Write(c) + +	// Makes sure that this event type is an Event interface. +	c.Putln("func (v %s) ImplementsEvent() { }", e.EvType()) +	c.Putln("") + +	// Let's the XGB event loop read this event. +	c.Putln("func init() {") +	c.Putln("newEventFuncs[%d] = New%s", e.Number, e.SrcName()) +	c.Putln("}") +	c.Putln("")  } -func (e *Event) Read(c *Context, prefix string) { +func (e *Event) Read(c *Context) {  	c.Putln("// Event read %s", e.SrcName()) +	c.Putln("func New%s(buf []byte) %s {", e.SrcName(), e.EvType()) +	c.Putln("v := %s{}", e.EvType()) +	c.Putln("b := 1 // don't read event number") +	c.Putln("") +	for i, field := range e.Fields { +		if i == 1 && !e.NoSequence { +			c.Putln("v.Sequence = get16(buf[b:])") +			c.Putln("b += 2") +			c.Putln("") +		} +		field.Read(c) +		c.Putln("") +	} +	c.Putln("return v") +	c.Putln("}") +	c.Putln("")  } -func (e *Event) Write(c *Context, prefix string) { +func (e *Event) Write(c *Context) {  	c.Putln("// Event write %s", e.SrcName()) +	c.Putln("func (v %s) Bytes() []byte {", e.EvType()) +	c.Putln("buf := make([]byte, %s)", e.Size()) +	c.Putln("b := 0") +	c.Putln("") +	c.Putln("// write event number") +	c.Putln("buf[b] = %d", e.Number) +	c.Putln("b += 1") +	c.Putln("") +	for i, field := range e.Fields { +		if i == 1 && !e.NoSequence { +			c.Putln("b += 2 // skip sequence number") +			c.Putln("") +		} +		field.Write(c) +		c.Putln("") +	} +	c.Putln("return buf") +	c.Putln("}") +	c.Putln("")  }  // EventCopy types @@ -21,18 +82,36 @@ func (e *EventCopy) Define(c *Context) {  	c.Putln("")  	c.Putln("type %s %s", e.EvType(), e.Old.(*Event).EvType())  	c.Putln("") + +	// Read defines a function that transforms a byte slice into this +	// event struct. +	e.Read(c) + +	// Write defines a function that transoforms this event struct into +	// a byte slice. +	e.Write(c) + +	// Makes sure that this event type is an Event interface. +	c.Putln("func (v %s) ImplementsEvent() { }", e.EvType()) +	c.Putln("") + +	// Let's the XGB event loop read this event. +	c.Putln("func init() {") +	c.Putln("newEventFuncs[%d] = New%s", e.Number, e.SrcName()) +	c.Putln("}") +	c.Putln("") +} + +func (e *EventCopy) Read(c *Context) {  	c.Putln("func New%s(buf []byte) %s {", e.SrcName(), e.EvType())  	c.Putln("return (%s)(New%s(buf))", e.EvType(), e.Old.SrcName())  	c.Putln("}")  	c.Putln("") -	c.Putln("func (ev %s) ImplementsEvent() { }", e.EvType()) -	c.Putln("") -	c.Putln("func (ev %s) Bytes() []byte {", e.EvType()) +} + +func (e *EventCopy) Write(c *Context) { +	c.Putln("func (v %s) Bytes() []byte {", e.EvType())  	c.Putln("return (%s)(ev).Bytes()", e.Old.(*Event).EvType())  	c.Putln("}")  	c.Putln("") -	c.Putln("func init() {") -	c.Putln("newEventFuncs[%d] = New%s", e.Number, e.SrcName()) -	c.Putln("}") -	c.Putln("")  } diff --git a/nexgb/xgbgen/go_list.go b/nexgb/xgbgen/go_list.go index 03da22e..a95ba71 100644 --- a/nexgb/xgbgen/go_list.go +++ b/nexgb/xgbgen/go_list.go @@ -12,8 +12,6 @@ func (f *ListField) Define(c *Context) {  }  func (f *ListField) Read(c *Context) { -	c.Putln("") -  	switch t := f.Type.(type) {  	case *Resource:  		length := f.LengthExpr.Reduce("v.", "") @@ -34,6 +32,10 @@ func (f *ListField) Read(c *Context) {  			c.Putln("}")  			c.Putln("b = pad(b)")  		} +	case *Union: +		c.Putln("v.%s = make([]%s, %s)", +			f.SrcName(), t.SrcName(), f.LengthExpr.Reduce("v.", "")) +		c.Putln("b += Read%sList(buf[b:], v.%s)", t.SrcName(), f.SrcName())  	case *Struct:  		c.Putln("v.%s = make([]%s, %s)",  			f.SrcName(), t.SrcName(), f.LengthExpr.Reduce("v.", "")) @@ -45,8 +47,6 @@ func (f *ListField) Read(c *Context) {  }  func (f *ListField) Write(c *Context) { -	c.Putln("") -  	switch t := f.Type.(type) {  	case *Resource:  		length := f.LengthExpr.Reduce("v.", "") @@ -65,6 +65,8 @@ func (f *ListField) Write(c *Context) {  			c.Putln("}")  			c.Putln("b = pad(b)")  		} +	case *Union: +		c.Putln("b += %sListBytes(buf[b:], v.%s)", t.SrcName(), f.SrcName())  	case *Struct:  		c.Putln("b += %sListBytes(buf[b:], v.%s)", t.SrcName(), f.SrcName())  	default: diff --git a/nexgb/xgbgen/go_single_field.go b/nexgb/xgbgen/go_single_field.go index 3c354e7..bf31259 100644 --- a/nexgb/xgbgen/go_single_field.go +++ b/nexgb/xgbgen/go_single_field.go @@ -25,6 +25,16 @@ func ReadSimpleSingleField(c *Context, name string, typ Type) {  			c.Putln("%s = %s(get64(buf[b:]))", name, t.SrcName())  		}  	case *Base: +		// If this is a bool, stop short and do something special. +		if t.SrcName() == "bool" { +			c.Putln("if buf[b] == 1 {") +			c.Putln("%s = true", name) +			c.Putln("} else {") +			c.Putln("%s = false", name) +			c.Putln("}") +			break +		} +  		var val string  		switch t.Size().Eval() {  		case 1: @@ -44,7 +54,7 @@ func ReadSimpleSingleField(c *Context, name string, typ Type) {  		}  		c.Putln("%s = %s", name, val)  	default: -		log.Fatalf("Cannot read field '%s' as a simple field with %T type.", +		log.Panicf("Cannot read field '%s' as a simple field with %T type.",  			name, typ)  	} @@ -62,9 +72,11 @@ func (f *SingleField) Read(c *Context) {  	case *Struct:  		c.Putln("v.%s = %s{}", f.SrcName(), t.SrcName())  		c.Putln("b += Read%s(buf[b:], &v.%s)", t.SrcName(), f.SrcName()) -		c.Putln("") +	case *Union: +		c.Putln("v.%s = %s{}", f.SrcName(), t.SrcName()) +		c.Putln("b += Read%s(buf[b:], &v.%s)", t.SrcName(), f.SrcName())  	default: -		log.Fatalf("Cannot read field '%s' with %T type.", f.XmlName(), f.Type) +		log.Panicf("Cannot read field '%s' with %T type.", f.XmlName(), f.Type)  	}  } @@ -84,6 +96,16 @@ func WriteSimpleSingleField(c *Context, name string, typ Type) {  			c.Putln("put64(buf[b:], uint64(%s))", name)  		}  	case *Base: +		// If this is a bool, stop short and do something special. +		if t.SrcName() == "bool" { +			c.Putln("if %s {", name) +			c.Putln("buf[b] = 1") +			c.Putln("} else {") +			c.Putln("buf[b] = 0") +			c.Putln("}") +			break +		} +  		switch t.Size().Eval() {  		case 1:  			if t.SrcName() != "byte" { @@ -126,11 +148,17 @@ func (f *SingleField) Write(c *Context) {  		ReadSimpleSingleField(c, fmt.Sprintf("v.%s", f.SrcName()), t)  	case *Base:  		ReadSimpleSingleField(c, fmt.Sprintf("v.%s", f.SrcName()), t) +	case *Union: +		c.Putln("{") +		c.Putln("unionBytes := v.%s.Bytes()", f.SrcName()) +		c.Putln("copy(buf[b:], unionBytes)") +		c.Putln("b += pad(len(unionBytes))") +		c.Putln("}")  	case *Struct:  		c.Putln("{")  		c.Putln("structBytes := v.%s.Bytes()", f.SrcName())  		c.Putln("copy(buf[b:], structBytes)") -		c.Putln("b += len(structBytes)") +		c.Putln("b += pad(len(structBytes))")  		c.Putln("}")  	default:  		log.Fatalf("Cannot read field '%s' with %T type.", f.XmlName(), f.Type) diff --git a/nexgb/xgbgen/go_struct.go b/nexgb/xgbgen/go_struct.go index 6925c88..600ebaf 100644 --- a/nexgb/xgbgen/go_struct.go +++ b/nexgb/xgbgen/go_struct.go @@ -13,7 +13,7 @@ func (s *Struct) Define(c *Context) {  	// Write function that reads bytes and produces this struct.  	s.Read(c) -	// Write function that reads a list of this structs. +	// Write function that reads bytes and produces a list of this struct.  	s.ReadList(c)  	// Write function that writes bytes given this struct. @@ -68,7 +68,7 @@ func (s *Struct) ReadList(c *Context) {  func (s *Struct) Write(c *Context) {  	c.Putln("// Struct write %s", s.SrcName())  	c.Putln("func (v %s) Bytes() []byte {", s.SrcName()) -	c.Putln("buf := make([]byte, %s)", s.Size().Reduce("s.", "")) +	c.Putln("buf := make([]byte, %s)", s.Size().Reduce("v.", ""))  	c.Putln("b := 0")  	c.Putln("")  	for _, field := range s.Fields { @@ -88,10 +88,11 @@ func (s *Struct) WriteList(c *Context) {  	c.Putln("for _, item := range list {")  	c.Putln("structBytes = item.Bytes()")  	c.Putln("copy(buf[b:], len(structBytes))") -	c.Putln("b += len(structBytes)") +	c.Putln("b += pad(len(structBytes))")  	c.Putln("}")  	c.Putln("return b")  	c.Putln("}") +	c.Putln("")  }  func (s *Struct) WriteListSize(c *Context) { @@ -101,7 +102,7 @@ func (s *Struct) WriteListSize(c *Context) {  	c.Putln("for _, item := range list {")  	c.Putln("size += %s", s.Size().Reduce("item.", ""))  	c.Putln("}") -	c.Putln("return pad(size)") +	c.Putln("return size")  	c.Putln("}")  	c.Putln("")  } diff --git a/nexgb/xgbgen/go_union.go b/nexgb/xgbgen/go_union.go index 5721c49..3b7365d 100644 --- a/nexgb/xgbgen/go_union.go +++ b/nexgb/xgbgen/go_union.go @@ -3,13 +3,143 @@ package main  // Union types  func (u *Union) Define(c *Context) {  	c.Putln("// Union definition %s", u.SrcName()) +	c.Putln("// Note that to *create* a Union, you should *never* create") +	c.Putln("// this struct directly (unless you know what you're doing).") +	c.Putln("// Instead use one of the following constructors for '%s':", +		u.SrcName()) +	for _, field := range u.Fields { +		c.Putln("//     New%s%s(%s %s) %s", u.SrcName(), field.SrcName(), +			field.SrcName(), field.SrcType(), u.SrcName()) +	} + +	c.Putln("type %s struct {", u.SrcName()) +	for _, field := range u.Fields { +		field.Define(c) +	} +	c.Putln("}") +	c.Putln("") + +	// Write functions for each field that create instances of this +	// union using the corresponding field. +	u.New(c) + +	// Write function that reads bytes and produces this union. +	u.Read(c) + +	// Write function that reads bytes and produces a list of this union. +	u.ReadList(c) + +	// Write function that writes bytes given this union. +	u.Write(c) + +	// Write function that writes a list of this union. +	u.WriteList(c) + +	// Write function that computes the size of a list of these unions. +	u.WriteListSize(c)  } -func (u *Union) Read(c *Context, prefix string) { +func (u *Union) New(c *Context) { +	for _, field := range u.Fields { +		c.Putln("// Union constructor for %s for field %s.", +			u.SrcName(), field.SrcName()) +		c.Putln("func New%s%s(%s %s) %s {", +			u.SrcName(), field.SrcName(), field.SrcName(), +			field.SrcType(), u.SrcName()) +		c.Putln("var b int") +		c.Putln("buf := make([]byte, %s)", u.Size()) +		c.Putln("") +		field.Write(c) +		c.Putln("") +		c.Putln("// Create the Union type") +		c.Putln("v := %s{}", u.SrcName()) +		c.Putln("") +		c.Putln("// Now copy buf into all fields") +		c.Putln("") +		for _, field2 := range u.Fields { +			c.Putln("b = 0 // always read the same bytes") +			field2.Read(c) +			c.Putln("") +		} +		c.Putln("return v") +		c.Putln("}") +		c.Putln("") +	} +} + +func (u *Union) Read(c *Context) {  	c.Putln("// Union read %s", u.SrcName()) +	c.Putln("func Read%s(buf []byte, v *%s) int {", u.SrcName(), u.SrcName()) +	c.Putln("var b int") +	c.Putln("") +	for _, field := range u.Fields { +		c.Putln("b = 0 // re-read the same bytes") +		field.Read(c) +		c.Putln("") +	} +	c.Putln("return %s", u.Size()) +	c.Putln("}") +	c.Putln("") +} + +func (u *Union) ReadList(c *Context) { +	c.Putln("// Union list read %s", u.SrcName()) +	c.Putln("func Read%sList(buf []byte, dest []%s) int {", +		u.SrcName(), u.SrcName()) +	c.Putln("b := 0") +	c.Putln("for i := 0; i < len(dest); i++ {") +	c.Putln("dest[i] = %s{}", u.SrcName()) +	c.Putln("b += Read%s(buf[b:], &dest[i])", u.SrcName()) +	c.Putln("}") +	c.Putln("return pad(b)") +	c.Putln("}") +	c.Putln("")  } -func (u *Union) Write(c *Context, prefix string) { +// This is a bit tricky since writing from a Union implies that only +// the data inside ONE of the elements is actually written. +// However, we only currently support unions where every field has the +// *same* *fixed* size. Thus, we make sure to always read bytes into +// every field which allows us to simply pick the first field and write it. +func (u *Union) Write(c *Context) {  	c.Putln("// Union write %s", u.SrcName()) +	c.Putln("// Each field in a union must contain the same data.") +	c.Putln("// So simply pick the first field and write that to the wire.") +	c.Putln("func (v %s) Bytes() []byte {", u.SrcName()) +	c.Putln("buf := make([]byte, %s)", u.Size().Reduce("v.", "")) +	c.Putln("b := 0") +	c.Putln("") +	u.Fields[0].Write(c) +	c.Putln("return buf") +	c.Putln("}") +	c.Putln("") +} + +func (u *Union) WriteList(c *Context) { +	c.Putln("// Union list write %s", u.SrcName()) +	c.Putln("func %sListBytes(buf []byte, list []%s) int {", +		u.SrcName(), u.SrcName()) +	c.Putln("b := 0") +	c.Putln("var unionBytes []byte") +	c.Putln("for _, item := range list {") +	c.Putln("unionBytes = item.Bytes()") +	c.Putln("copy(buf[b:], len(unionBytes))") +	c.Putln("b += pad(len(unionBytes))") +	c.Putln("}") +	c.Putln("return b") +	c.Putln("}") +	c.Putln("") +} + +func (u *Union) WriteListSize(c *Context) { +	c.Putln("// Union list size %s", u.SrcName()) +	c.Putln("func %sListSize(list []%s) int {", u.SrcName(), u.SrcName()) +	c.Putln("size := 0") +	c.Putln("for _, item := range list {") +	c.Putln("size += %s", u.Size().Reduce("item.", "")) +	c.Putln("}") +	c.Putln("return size") +	c.Putln("}") +	c.Putln("")  } diff --git a/nexgb/xgbgen/type.go b/nexgb/xgbgen/type.go index 9fbef65..1e06bda 100644 --- a/nexgb/xgbgen/type.go +++ b/nexgb/xgbgen/type.go @@ -191,7 +191,7 @@ func (e *Event) XmlName() string {  }  func (e *Event) Size() Size { -	panic("Cannot take size of Event type.") +	return newExpressionSize(&Value{v: 32})  }  func (e *Event) Initialize(p *Protocol) { @@ -358,7 +358,7 @@ func (u *Union) Size() Size {  }  func (u *Union) Initialize(p *Protocol) { -	u.srcName = TypeSrcName(p, u) +	u.srcName = fmt.Sprintf("%sUnion", TypeSrcName(p, u))  	for _, field := range u.Fields {  		field.Initialize(p)  	} | 
