github.com/BurntSushi/xgb@v0.0.0-20210121224620-deaf085860bc/xgbgen/translation.go (about) 1 package main 2 3 /* 4 translation.go provides a 'Translate' method on every XML type that converts 5 the XML type into our "better" representation. 6 7 i.e., the representation of Fields and Expressions is just too general. 8 We end up losing a lot of the advantages of static typing if we keep 9 the types that encoding/xml forces us into. 10 11 Please see 'representation.go' for the type definitions that we're 12 translating to. 13 */ 14 15 import ( 16 "log" 17 "strconv" 18 "strings" 19 ) 20 21 func (xml *XML) Translate(parent *Protocol) *Protocol { 22 protocol := &Protocol{ 23 Parent: parent, 24 Name: xml.Header, 25 ExtXName: xml.ExtensionXName, 26 ExtName: xml.ExtensionName, 27 MajorVersion: xml.MajorVersion, 28 MinorVersion: xml.MinorVersion, 29 30 Imports: make([]*Protocol, 0), 31 Types: make([]Type, 0), 32 Requests: make([]*Request, len(xml.Requests)), 33 } 34 35 for _, imp := range xml.Imports { 36 if imp.xml != nil { 37 protocol.Imports = append(protocol.Imports, 38 imp.xml.Translate(protocol)) 39 } 40 } 41 42 for xmlName, srcName := range BaseTypeMap { 43 newBaseType := &Base{ 44 srcName: srcName, 45 xmlName: xmlName, 46 size: newFixedSize(BaseTypeSizes[xmlName], true), 47 } 48 protocol.Types = append(protocol.Types, newBaseType) 49 } 50 for _, enum := range xml.Enums { 51 protocol.Types = append(protocol.Types, enum.Translate()) 52 } 53 for _, xid := range xml.Xids { 54 protocol.Types = append(protocol.Types, xid.Translate()) 55 } 56 for _, xidunion := range xml.XidUnions { 57 protocol.Types = append(protocol.Types, xidunion.Translate()) 58 } 59 for _, typedef := range xml.TypeDefs { 60 protocol.Types = append(protocol.Types, typedef.Translate()) 61 } 62 for _, s := range xml.Structs { 63 protocol.Types = append(protocol.Types, s.Translate()) 64 } 65 for _, union := range xml.Unions { 66 protocol.Types = append(protocol.Types, union.Translate()) 67 } 68 for _, ev := range xml.Events { 69 protocol.Types = append(protocol.Types, ev.Translate()) 70 } 71 for _, evcopy := range xml.EventCopies { 72 protocol.Types = append(protocol.Types, evcopy.Translate()) 73 } 74 for _, err := range xml.Errors { 75 protocol.Types = append(protocol.Types, err.Translate()) 76 } 77 for _, errcopy := range xml.ErrorCopies { 78 protocol.Types = append(protocol.Types, errcopy.Translate()) 79 } 80 81 for i, request := range xml.Requests { 82 protocol.Requests[i] = request.Translate() 83 } 84 85 // Now load all of the type and source name information. 86 protocol.Initialize() 87 88 // Make sure all enums have concrete values. 89 for _, typ := range protocol.Types { 90 enum, ok := typ.(*Enum) 91 if !ok { 92 continue 93 } 94 nextValue := 0 95 for _, item := range enum.Items { 96 if item.Expr == nil { 97 item.Expr = &Value{v: nextValue} 98 nextValue++ 99 } else { 100 nextValue = item.Expr.Eval() + 1 101 } 102 } 103 } 104 105 return protocol 106 } 107 108 func (x *XMLEnum) Translate() *Enum { 109 enum := &Enum{ 110 xmlName: x.Name, 111 Items: make([]*EnumItem, len(x.Items)), 112 } 113 for i, item := range x.Items { 114 enum.Items[i] = &EnumItem{ 115 xmlName: item.Name, 116 Expr: item.Expr.Translate(), 117 } 118 } 119 return enum 120 } 121 122 func (x *XMLXid) Translate() *Resource { 123 return &Resource{ 124 xmlName: x.Name, 125 } 126 } 127 128 func (x *XMLTypeDef) Translate() *TypeDef { 129 return &TypeDef{ 130 xmlName: x.New, 131 Old: newTranslation(x.Old), 132 } 133 } 134 135 func (x *XMLEvent) Translate() *Event { 136 ev := &Event{ 137 xmlName: x.Name, 138 Number: x.Number, 139 NoSequence: x.NoSequence, 140 Fields: make([]Field, 0, len(x.Fields)), 141 } 142 for _, field := range x.Fields { 143 if field.XMLName.Local == "doc" { 144 continue 145 } 146 ev.Fields = append(ev.Fields, field.Translate(ev)) 147 } 148 return ev 149 } 150 151 func (x *XMLEventCopy) Translate() *EventCopy { 152 return &EventCopy{ 153 xmlName: x.Name, 154 Number: x.Number, 155 Old: newTranslation(x.Ref), 156 } 157 } 158 159 func (x *XMLError) Translate() *Error { 160 err := &Error{ 161 xmlName: x.Name, 162 Number: x.Number, 163 Fields: make([]Field, len(x.Fields)), 164 } 165 for i, field := range x.Fields { 166 err.Fields[i] = field.Translate(err) 167 } 168 return err 169 } 170 171 func (x *XMLErrorCopy) Translate() *ErrorCopy { 172 return &ErrorCopy{ 173 xmlName: x.Name, 174 Number: x.Number, 175 Old: newTranslation(x.Ref), 176 } 177 } 178 179 func (x *XMLStruct) Translate() *Struct { 180 s := &Struct{ 181 xmlName: x.Name, 182 Fields: make([]Field, len(x.Fields)), 183 } 184 for i, field := range x.Fields { 185 s.Fields[i] = field.Translate(s) 186 } 187 return s 188 } 189 190 func (x *XMLUnion) Translate() *Union { 191 u := &Union{ 192 xmlName: x.Name, 193 Fields: make([]Field, len(x.Fields)), 194 } 195 for i, field := range x.Fields { 196 u.Fields[i] = field.Translate(u) 197 } 198 return u 199 } 200 201 func (x *XMLRequest) Translate() *Request { 202 r := &Request{ 203 xmlName: x.Name, 204 Opcode: x.Opcode, 205 Combine: x.Combine, 206 Fields: make([]Field, 0, len(x.Fields)), 207 Reply: x.Reply.Translate(), 208 } 209 for _, field := range x.Fields { 210 if field.XMLName.Local == "doc" || field.XMLName.Local == "fd" { 211 continue 212 } 213 r.Fields = append(r.Fields, field.Translate(r)) 214 } 215 216 // Address bug (or legacy code) in QueryTextExtents. 217 // The XML protocol description references 'string_len' in the 218 // computation of the 'odd_length' field. However, 'string_len' is not 219 // defined. Therefore, let's forcefully add it as a 'local field'. 220 // (i.e., a parameter in the caller but does not get sent over the wire.) 221 if x.Name == "QueryTextExtents" { 222 stringLenLocal := &LocalField{&SingleField{ 223 xmlName: "string_len", 224 Type: newTranslation("CARD16"), 225 }} 226 r.Fields = append(r.Fields, stringLenLocal) 227 } 228 229 return r 230 } 231 232 func (x *XMLReply) Translate() *Reply { 233 if x == nil { 234 return nil 235 } 236 237 r := &Reply{ 238 Fields: make([]Field, 0, len(x.Fields)), 239 } 240 for _, field := range x.Fields { 241 if field.XMLName.Local == "doc" || field.XMLName.Local == "fd" { 242 continue 243 } 244 r.Fields = append(r.Fields, field.Translate(r)) 245 } 246 return r 247 } 248 249 func (x *XMLExpression) Translate() Expression { 250 if x == nil { 251 return nil 252 } 253 254 switch x.XMLName.Local { 255 case "op": 256 if len(x.Exprs) != 2 { 257 log.Panicf("'op' found %d expressions; expected 2.", len(x.Exprs)) 258 } 259 return &BinaryOp{ 260 Op: x.Op, 261 Expr1: x.Exprs[0].Translate(), 262 Expr2: x.Exprs[1].Translate(), 263 } 264 case "unop": 265 if len(x.Exprs) != 1 { 266 log.Panicf("'unop' found %d expressions; expected 1.", len(x.Exprs)) 267 } 268 return &UnaryOp{ 269 Op: x.Op, 270 Expr: x.Exprs[0].Translate(), 271 } 272 case "popcount": 273 if len(x.Exprs) != 1 { 274 log.Panicf("'popcount' found %d expressions; expected 1.", 275 len(x.Exprs)) 276 } 277 return &PopCount{ 278 Expr: x.Exprs[0].Translate(), 279 } 280 case "value": 281 val, err := strconv.Atoi(strings.TrimSpace(x.Data)) 282 if err != nil { 283 log.Panicf("Could not convert '%s' in 'value' expression to int.", 284 x.Data) 285 } 286 return &Value{ 287 v: val, 288 } 289 case "bit": 290 bit, err := strconv.Atoi(strings.TrimSpace(x.Data)) 291 if err != nil { 292 log.Panicf("Could not convert '%s' in 'bit' expression to int.", 293 x.Data) 294 } 295 if bit < 0 || bit > 31 { 296 log.Panicf("A 'bit' literal must be in the range [0, 31], but "+ 297 " is %d", bit) 298 } 299 return &Bit{ 300 b: bit, 301 } 302 case "fieldref": 303 return &FieldRef{ 304 Name: x.Data, 305 } 306 case "enumref": 307 return &EnumRef{ 308 EnumKind: newTranslation(x.Ref), 309 EnumItem: x.Data, 310 } 311 case "sumof": 312 return &SumOf{ 313 Name: x.Ref, 314 } 315 } 316 317 log.Panicf("Unrecognized tag '%s' in expression context. Expected one of "+ 318 "op, fieldref, value, bit, enumref, unop, sumof or popcount.", 319 x.XMLName.Local) 320 panic("unreachable") 321 } 322 323 func (x *XMLField) Translate(parent interface{}) Field { 324 switch x.XMLName.Local { 325 case "pad": 326 return &PadField{ 327 Bytes: x.Bytes, 328 } 329 case "field": 330 return &SingleField{ 331 xmlName: x.Name, 332 Type: newTranslation(x.Type), 333 } 334 case "list": 335 return &ListField{ 336 xmlName: x.Name, 337 Type: newTranslation(x.Type), 338 LengthExpr: x.Expr.Translate(), 339 } 340 case "localfield": 341 return &LocalField{&SingleField{ 342 xmlName: x.Name, 343 Type: newTranslation(x.Type), 344 }} 345 case "exprfield": 346 return &ExprField{ 347 xmlName: x.Name, 348 Type: newTranslation(x.Type), 349 Expr: x.Expr.Translate(), 350 } 351 case "valueparam": 352 return &ValueField{ 353 Parent: parent, 354 MaskType: newTranslation(x.ValueMaskType), 355 MaskName: x.ValueMaskName, 356 ListName: x.ValueListName, 357 } 358 case "switch": 359 swtch := &SwitchField{ 360 Name: x.Name, 361 Expr: x.Expr.Translate(), 362 Bitcases: make([]*Bitcase, len(x.Bitcases)), 363 } 364 for i, bitcase := range x.Bitcases { 365 swtch.Bitcases[i] = bitcase.Translate() 366 } 367 return swtch 368 } 369 370 log.Panicf("Unrecognized field element: %s", x.XMLName.Local) 371 panic("unreachable") 372 } 373 374 func (x *XMLBitcase) Translate() *Bitcase { 375 b := &Bitcase{ 376 Expr: x.Expr().Translate(), 377 Fields: make([]Field, len(x.Fields)), 378 } 379 for i, field := range x.Fields { 380 b.Fields[i] = field.Translate(b) 381 } 382 return b 383 } 384 385 // SrcName is used to translate any identifier into a Go name. 386 // Mostly used for fields, but used in a couple other places too (enum items). 387 func SrcName(p *Protocol, name string) string { 388 // If it's in the name map, use that translation. 389 if newn, ok := NameMap[name]; ok { 390 return newn 391 } 392 return splitAndTitle(name) 393 } 394 395 func TypeSrcName(p *Protocol, typ Type) string { 396 t := typ.XmlName() 397 398 // If this is a base type, then write the raw Go type. 399 if baseType, ok := typ.(*Base); ok { 400 return baseType.SrcName() 401 } 402 403 // If it's in the type map, use that translation. 404 if newt, ok := TypeMap[t]; ok { 405 return newt 406 } 407 408 // If there's a namespace to this type, just use it and be done. 409 if colon := strings.Index(t, ":"); colon > -1 { 410 namespace := t[:colon] 411 rest := t[colon+1:] 412 return p.ProtocolFind(namespace).PkgName() + "." + splitAndTitle(rest) 413 } 414 415 // Since there's no namespace, we're left with the raw type name. 416 // If the type is part of the source we're generating (i.e., there is 417 // no parent protocol), then just return that type name. 418 // Otherwise, we must qualify it with a package name. 419 if p.Parent == nil { 420 return splitAndTitle(t) 421 } 422 return p.PkgName() + "." + splitAndTitle(t) 423 }