github.com/BurntSushi/xgb@v0.0.0-20210121224620-deaf085860bc/xgbgen/go_error.go (about) 1 package main 2 3 import ( 4 "fmt" 5 ) 6 7 // Error types 8 func (e *Error) Define(c *Context) { 9 c.Putln("// %s is the error number for a %s.", e.ErrConst(), e.ErrConst()) 10 c.Putln("const %s = %d", e.ErrConst(), e.Number) 11 c.Putln("") 12 c.Putln("type %s struct {", e.ErrType()) 13 c.Putln("Sequence uint16") 14 c.Putln("NiceName string") 15 for _, field := range e.Fields { 16 field.Define(c) 17 } 18 c.Putln("}") 19 c.Putln("") 20 21 // Read defines a function that transforms a byte slice into this 22 // error struct. 23 e.Read(c) 24 25 // Makes sure this error type implements the xgb.Error interface. 26 e.ImplementsError(c) 27 28 // Let's the XGB event loop read this error. 29 c.Putln("func init() {") 30 if c.protocol.isExt() { 31 c.Putln("xgb.NewExtErrorFuncs[\"%s\"][%d] = %sNew", 32 c.protocol.ExtXName, e.Number, e.ErrType()) 33 } else { 34 c.Putln("xgb.NewErrorFuncs[%d] = %sNew", e.Number, e.ErrType()) 35 } 36 c.Putln("}") 37 c.Putln("") 38 } 39 40 func (e *Error) Read(c *Context) { 41 c.Putln("// %sNew constructs a %s value that implements xgb.Error from "+ 42 "a byte slice.", e.ErrType(), e.ErrType()) 43 c.Putln("func %sNew(buf []byte) xgb.Error {", e.ErrType()) 44 c.Putln("v := %s{}", e.ErrType()) 45 c.Putln("v.NiceName = \"%s\"", e.SrcName()) 46 c.Putln("") 47 c.Putln("b := 1 // skip error determinant") 48 c.Putln("b += 1 // don't read error number") 49 c.Putln("") 50 c.Putln("v.Sequence = xgb.Get16(buf[b:])") 51 c.Putln("b += 2") 52 c.Putln("") 53 for _, field := range e.Fields { 54 field.Read(c, "v.") 55 c.Putln("") 56 } 57 c.Putln("return v") 58 c.Putln("}") 59 c.Putln("") 60 } 61 62 // ImplementsError writes functions to implement the XGB Error interface. 63 func (e *Error) ImplementsError(c *Context) { 64 c.Putln("// SequenceId returns the sequence id attached to the %s error.", 65 e.ErrConst()) 66 c.Putln("// This is mostly used internally.") 67 c.Putln("func (err %s) SequenceId() uint16 {", e.ErrType()) 68 c.Putln("return err.Sequence") 69 c.Putln("}") 70 c.Putln("") 71 c.Putln("// BadId returns the 'BadValue' number if one exists for the "+ 72 "%s error. If no bad value exists, 0 is returned.", e.ErrConst()) 73 c.Putln("func (err %s) BadId() uint32 {", e.ErrType()) 74 if !c.protocol.isExt() { 75 c.Putln("return err.BadValue") 76 } else { 77 c.Putln("return 0") 78 } 79 c.Putln("}") 80 c.Putln("// Error returns a rudimentary string representation of the %s "+ 81 "error.", e.ErrConst()) 82 c.Putln("") 83 c.Putln("func (err %s) Error() string {", e.ErrType()) 84 ErrorFieldString(c, e.Fields, e.ErrConst()) 85 c.Putln("}") 86 c.Putln("") 87 } 88 89 // ErrorCopy types 90 func (e *ErrorCopy) Define(c *Context) { 91 c.Putln("// %s is the error number for a %s.", e.ErrConst(), e.ErrConst()) 92 c.Putln("const %s = %d", e.ErrConst(), e.Number) 93 c.Putln("") 94 c.Putln("type %s %s", e.ErrType(), e.Old.(*Error).ErrType()) 95 c.Putln("") 96 97 // Read defines a function that transforms a byte slice into this 98 // error struct. 99 e.Read(c) 100 101 // Makes sure this error type implements the xgb.Error interface. 102 e.ImplementsError(c) 103 104 // Let's the XGB know how to read this error. 105 c.Putln("func init() {") 106 if c.protocol.isExt() { 107 c.Putln("xgb.NewExtErrorFuncs[\"%s\"][%d] = %sNew", 108 c.protocol.ExtXName, e.Number, e.ErrType()) 109 } else { 110 c.Putln("xgb.NewErrorFuncs[%d] = %sNew", e.Number, e.ErrType()) 111 } 112 c.Putln("}") 113 c.Putln("") 114 } 115 116 func (e *ErrorCopy) Read(c *Context) { 117 c.Putln("// %sNew constructs a %s value that implements xgb.Error from "+ 118 "a byte slice.", e.ErrType(), e.ErrType()) 119 c.Putln("func %sNew(buf []byte) xgb.Error {", e.ErrType()) 120 c.Putln("v := %s(%sNew(buf).(%s))", 121 e.ErrType(), e.Old.(*Error).ErrType(), e.Old.(*Error).ErrType()) 122 c.Putln("v.NiceName = \"%s\"", e.SrcName()) 123 c.Putln("return v") 124 c.Putln("}") 125 c.Putln("") 126 } 127 128 // ImplementsError writes functions to implement the XGB Error interface. 129 func (e *ErrorCopy) ImplementsError(c *Context) { 130 c.Putln("// SequenceId returns the sequence id attached to the %s error.", 131 e.ErrConst()) 132 c.Putln("// This is mostly used internally.") 133 c.Putln("func (err %s) SequenceId() uint16 {", e.ErrType()) 134 c.Putln("return err.Sequence") 135 c.Putln("}") 136 c.Putln("") 137 c.Putln("// BadId returns the 'BadValue' number if one exists for the "+ 138 "%s error. If no bad value exists, 0 is returned.", e.ErrConst()) 139 c.Putln("func (err %s) BadId() uint32 {", e.ErrType()) 140 if !c.protocol.isExt() { 141 c.Putln("return err.BadValue") 142 } else { 143 c.Putln("return 0") 144 } 145 c.Putln("}") 146 c.Putln("") 147 c.Putln("// Error returns a rudimentary string representation of the %s "+ 148 "error.", e.ErrConst()) 149 c.Putln("func (err %s) Error() string {", e.ErrType()) 150 ErrorFieldString(c, e.Old.(*Error).Fields, e.ErrConst()) 151 c.Putln("}") 152 c.Putln("") 153 } 154 155 // ErrorFieldString works for both Error and ErrorCopy. It assembles all of the 156 // fields in an error and formats them into a single string. 157 func ErrorFieldString(c *Context, fields []Field, errName string) { 158 c.Putln("fieldVals := make([]string, 0, %d)", len(fields)) 159 c.Putln("fieldVals = append(fieldVals, \"NiceName: \" + err.NiceName)") 160 c.Putln("fieldVals = append(fieldVals, "+ 161 "xgb.Sprintf(\"Sequence: %s\", err.Sequence))", "%d") 162 for _, field := range fields { 163 switch field.(type) { 164 case *PadField: 165 continue 166 default: 167 if field.SrcType() == "string" { 168 c.Putln("fieldVals = append(fieldVals, \"%s: \" + err.%s)", 169 field.SrcName(), field.SrcName()) 170 } else { 171 format := fmt.Sprintf("xgb.Sprintf(\"%s: %s\", err.%s)", 172 field.SrcName(), "%d", field.SrcName()) 173 c.Putln("fieldVals = append(fieldVals, %s)", format) 174 } 175 } 176 } 177 c.Putln("return \"%s {\" + xgb.StringsJoin(fieldVals, \", \") + \"}\"", 178 errName) 179 }