github.com/robotn/xgb@v0.0.0-20190912153532-2cb92d044934/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  }