github.com/osrg/gobgp@v2.0.0+incompatible/tools/pyang_plugins/bgpyang2golang.py (about)

     1  # Copyright (C) 2014,2015 Nippon Telegraph and Telephone Corporation.
     2  #
     3  # Licensed under the Apache License, Version 2.0 (the "License");
     4  # you may not use this file except in compliance with the License.
     5  # You may obtain a copy of the License at
     6  #
     7  #    http://www.apache.org/licenses/LICENSE-2.0
     8  #
     9  # Unless required by applicable law or agreed to in writing, software
    10  # distributed under the License is distributed on an "AS IS" BASIS,
    11  # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
    12  # implied.
    13  # See the License for the specific language governing permissions and
    14  # limitations under the License.
    15  
    16  from __future__ import print_function
    17  
    18  import sys
    19  from collections import namedtuple
    20  
    21  from pyang import plugin
    22  
    23  _COPYRIGHT_NOTICE = """
    24  // DO NOT EDIT
    25  // generated by pyang using OpenConfig https://github.com/openconfig/public
    26  //
    27  // Copyright (C) 2014-2016 Nippon Telegraph and Telephone Corporation.
    28  //
    29  // Licensed under the Apache License, Version 2.0 (the "License");
    30  // you may not use this file except in compliance with the License.
    31  // You may obtain a copy of the License at
    32  //
    33  //    http://www.apache.org/licenses/LICENSE-2.0
    34  //
    35  // Unless required by applicable law or agreed to in writing, software
    36  // distributed under the License is distributed on an "AS IS" BASIS,
    37  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
    38  // implied.
    39  // See the License for the specific language governing permissions and
    40  // limitations under the License.
    41  
    42  """
    43  
    44  EQUAL_TYPE_LEAF = 0
    45  EQUAL_TYPE_ARRAY = 1
    46  EQUAL_TYPE_MAP = 2
    47  EQUAL_TYPE_CONTAINER = 3
    48  
    49  
    50  def pyang_plugin_init():
    51      plugin.register_plugin(GolangPlugin())
    52  
    53  
    54  class GolangPlugin(plugin.PyangPlugin):
    55  
    56      def __init__(self, name=None):
    57          super(GolangPlugin, self).__init__(name=name)
    58          self.multiple_modules = True
    59  
    60      def add_output_format(self, fmts):
    61          fmts['golang'] = self
    62  
    63      def emit(self, ctx, modules, fd):
    64          ctx.golang_identity_map = {}
    65          ctx.golang_typedef_map = {}
    66          ctx.golang_struct_def = []
    67          ctx.golang_struct_names = {}
    68  
    69          ctx.emitted_type_names = {}
    70  
    71          ctx.prefix_rel = {}
    72          ctx.module_deps = []
    73          for m in modules:
    74              check_module_deps(ctx, m)
    75  
    76          # visit yang statements
    77          visit_modules(ctx)
    78  
    79          # emit bgp_configs
    80          emit_go(ctx, fd)
    81  
    82  
    83  def visit_modules(ctx):
    84      # visit typedef and identity
    85      for mod in ctx.module_deps:
    86          visit_typedef(ctx, mod)
    87          visit_identity(ctx, mod)
    88  
    89      # visit container
    90      for mod in ctx.module_deps:
    91          visit_children(ctx, mod, mod.i_children)
    92  
    93  
    94  def emit_go(ctx, fd):
    95      ctx.golang_struct_def.reverse()
    96      done = set()
    97  
    98      # emit
    99      generate_header(fd)
   100      generate_common_functions(fd)
   101  
   102      for mod in ctx.module_deps:
   103          if mod not in _module_excluded:
   104              emit_typedef(ctx, mod, fd)
   105              emit_identity(ctx, mod, fd)
   106  
   107      for struct in ctx.golang_struct_def:
   108          struct_name = struct.uniq_name
   109          if struct_name in done:
   110              continue
   111          emit_class_def(ctx, struct, struct_name, struct.module_prefix, fd)
   112          done.add(struct_name)
   113  
   114  
   115  def check_module_deps(ctx, mod):
   116      own_prefix = mod.i_prefix
   117      for k, v in mod.i_prefixes.items():
   118          mod = ctx.get_module(v[0])
   119          if mod is None:
   120              continue
   121  
   122          if mod.i_prefix != own_prefix:
   123              check_module_deps(ctx, mod)
   124  
   125          ctx.prefix_rel[mod.i_prefix] = k
   126          if (mod not in ctx.module_deps
   127                  and mod.i_modulename not in _module_excluded):
   128              ctx.module_deps.append(mod)
   129  
   130  
   131  def dig_leafref(type_obj):
   132      reftype = type_obj.i_type_spec.i_target_node.search_one('type')
   133      if is_leafref(reftype):
   134          return dig_leafref(reftype)
   135      else:
   136          return reftype
   137  
   138  
   139  def emit_class_def(ctx, stmt, struct_name, prefix, fd):
   140      if len(stmt.i_children) == 1 and is_list(stmt.i_children[0]):
   141          return
   142  
   143      print('// struct for container %s:%s.' % (prefix, stmt.arg), file=fd)
   144      emit_description(stmt, fd)
   145      print('type %s struct {' % convert_to_golang(struct_name), file=fd)
   146  
   147      equal_elems = []
   148  
   149      for child in stmt.i_children:
   150  
   151          if child.path in _path_exclude:
   152              continue
   153  
   154          container_or_list_name = child.uniq_name
   155          val_name_go = convert_to_golang(child.arg)
   156          child_prefix = get_orig_prefix(child.i_orig_module)
   157          tag_name = child.uniq_name.lower()
   158          equal_type = EQUAL_TYPE_LEAF
   159          equal_data = None
   160          print('// original -> %s:%s' % (child_prefix, container_or_list_name), file=fd)
   161  
   162          # case leaf
   163          if is_leaf(child):
   164              type_obj = child.search_one('type')
   165              type_name = type_obj.arg
   166  
   167              # case identityref
   168              if is_identityref(type_obj):
   169                  emit_type_name = convert_to_golang(type_obj.search_one('base').arg.split(':')[-1])
   170  
   171              # case leafref
   172              elif is_leafref(type_obj):
   173                  if type_obj.search_one('path').arg.startswith('../config'):
   174                      continue
   175                  t = dig_leafref(type_obj)
   176                  if is_translation_required(t):
   177                      print('// %s:%s\'s original type is %s.' % (child_prefix, container_or_list_name, t.arg), file=fd)
   178                      emit_type_name = translate_type(t.arg)
   179                  elif is_identityref(t):
   180                      emit_type_name = convert_to_golang(t.search_one('base').arg.split(':')[-1])
   181                  else:
   182                      emit_type_name = t.arg
   183  
   184              # case embeded enumeration
   185              elif is_enum(type_obj):
   186                  emit_type_name = val_name_go
   187  
   188              # case translation required
   189              elif is_translation_required(type_obj):
   190                  print('// %s:%s\'s original type is %s.' % (child_prefix, container_or_list_name, type_name), file=fd)
   191                  emit_type_name = translate_type(type_name)
   192  
   193              # case other primitives
   194              elif is_builtin_type(type_obj):
   195                  emit_type_name = type_name
   196  
   197              # default
   198              else:
   199                  base_module = type_obj.i_orig_module.i_prefix
   200                  t = lookup_typedef(ctx, base_module, type_name)
   201                  # print(t.golang_name, file=sys.stderr)
   202                  emit_type_name = t.golang_name
   203  
   204          # case 'case'
   205          if is_case(child):
   206              continue
   207  
   208          if is_choice(child) and is_enum_choice(child):
   209              emit_type_name = val_name_go
   210  
   211          # case leaflist
   212          if is_leaflist(child):
   213              type_obj = child.search_one('type')
   214              type_name = type_obj.arg
   215              val_name_go = val_name_go + 'List'
   216              tag_name += '-list'
   217              equal_type = EQUAL_TYPE_ARRAY
   218  
   219              # case leafref
   220              if is_leafref(type_obj):
   221                  t = dig_leafref(type_obj)
   222                  emit_type_name = '[]' + t.arg
   223  
   224              # case identityref
   225              elif is_identityref(type_obj):
   226                  emit_type_name = '[]' + convert_to_golang(type_obj.search_one('base').arg.split(':')[-1])
   227  
   228              # case translation required
   229              elif is_translation_required(type_obj):
   230                  print('// original type is list of %s' % type_obj.arg, file=fd)
   231                  emit_type_name = '[]' + translate_type(type_name)
   232  
   233              # case other primitives
   234              elif is_builtin_type(type_obj):
   235                  emit_type_name = '[]' + type_name
   236  
   237              # default
   238              else:
   239                  base_module = type_obj.i_orig_module.i_prefix
   240                  t = lookup_typedef(ctx, base_module, type_name)
   241                  emit_type_name = '[]' + t.golang_name
   242  
   243          # case container
   244          elif is_container(child) or (is_choice(child) and not is_enum_choice(child)):
   245              key = child_prefix + ':' + container_or_list_name
   246              t = ctx.golang_struct_names[key]
   247              val_name_go = t.golang_name
   248              if len(t.i_children) == 1 and is_list(t.i_children[0]):
   249                  c = t.i_children[0]
   250                  emit_type_name = '[]' + c.golang_name
   251                  equal_type = EQUAL_TYPE_MAP
   252                  equal_data = c.search_one('key').arg
   253                  leaf = c.search_one('leaf').search_one('type')
   254                  if leaf.arg == 'leafref' and leaf.search_one('path').arg.startswith('../config'):
   255                      equal_data = 'config.' + equal_data
   256              else:
   257                  emit_type_name = t.golang_name
   258                  equal_type = EQUAL_TYPE_CONTAINER
   259  
   260          # case list
   261          elif is_list(child):
   262              key = child_prefix + ':' + container_or_list_name
   263              t = ctx.golang_struct_names[key]
   264              val_name_go = val_name_go + 'List'
   265              tag_name += '-list'
   266              emit_type_name = '[]' + t.golang_name
   267              equal_type = EQUAL_TYPE_MAP
   268              equal_data = child.search_one('key').arg
   269  
   270          if is_container(child):
   271              name = emit_type_name
   272              if name.startswith(convert_to_golang(struct_name)) and name.endswith("Config"):
   273                  tag_name = 'config'
   274                  val_name_go = 'Config'
   275              elif name.startswith(convert_to_golang(struct_name)) and name.endswith("State"):
   276                  tag_name = 'state'
   277                  val_name_go = 'State'
   278  
   279          emit_description(child, fd=fd)
   280          print('  {0}\t{1} `mapstructure:"{2}" json:"{2},omitempty"`'.format(val_name_go, emit_type_name, tag_name), file=fd)
   281  
   282          equal_elems.append((val_name_go, emit_type_name, equal_type, equal_data))
   283  
   284      print('}', file=fd)
   285  
   286      if not struct_name.endswith('state'):
   287          print('func (lhs *{0}) Equal(rhs *{0}) bool {{'.format(convert_to_golang(struct_name)), file=fd)
   288          print('if lhs == nil || rhs == nil {', file=fd)
   289          print('return false', file=fd)
   290          print('}', file=fd)
   291  
   292          for val_name, type_name, typ, elem in equal_elems:
   293              if val_name == 'State':
   294                  continue
   295              if typ == EQUAL_TYPE_LEAF:
   296                  if type_name == '[]byte':
   297                      print('if bytes.Compare(lhs.{0}, rhs.{0}) != 0 {{'.format(val_name), file=fd)
   298                  else:
   299                      print('if lhs.{0} != rhs.{0} {{'.format(val_name), file=fd)
   300                  print('return false', file=fd)
   301                  print('}', file=fd)
   302              elif typ == EQUAL_TYPE_CONTAINER:
   303                  print('if !lhs.{0}.Equal(&(rhs.{0})) {{'.format(val_name), file=fd)
   304                  print('return false', file=fd)
   305                  print('}', file=fd)
   306              elif typ == EQUAL_TYPE_ARRAY:
   307                  print('if len(lhs.{0}) != len(rhs.{0}) {{'.format(val_name), file=fd)
   308                  print('return false', file=fd)
   309                  print('}', file=fd)
   310                  print('for idx, l := range lhs.{0} {{'.format(val_name), file=fd)
   311                  if type_name == '[][]byte':
   312                      print('if bytes.Compare(l, rhs.{0}[idx]) != 0 {{'.format(val_name), file=fd)
   313                  else:
   314                      print('if l != rhs.{0}[idx] {{'.format(val_name), file=fd)
   315                  print('return false', file=fd)
   316                  print('}', file=fd)
   317                  print('}', file=fd)
   318              elif typ == EQUAL_TYPE_MAP:
   319                  print('if len(lhs.{0}) != len(rhs.{0}) {{'.format(val_name), file=fd)
   320                  print('return false', file=fd)
   321                  print('}', file=fd)
   322                  print('{', file=fd)
   323                  print('lmap := make(map[string]*{0})'.format(type_name[2:]), file=fd)
   324                  print('for i, l := range lhs.{0} {{'.format(val_name), file=fd)
   325                  print('lmap[mapkey(i, string({0}))] = &lhs.{1}[i]'.format(' + '.join('l.{0}'.format(convert_to_golang(v)) for v in elem.split(' ')), val_name), file=fd)
   326                  print('}', file=fd)
   327                  print('for i, r := range rhs.{0} {{'.format(val_name), file=fd)
   328                  print('if l, y := lmap[mapkey(i, string({0}))]; !y {{'.format('+'.join('r.{0}'.format(convert_to_golang(v)) for v in elem.split(' '))), file=fd)
   329                  print('return false', file=fd)
   330                  print('} else if !r.Equal(l) {', file=fd)
   331                  print('return false', file=fd)
   332                  print('}', file=fd)
   333                  print('}', file=fd)
   334                  print('}', file=fd)
   335              else:
   336                  sys.stderr.write("invalid equal type %s", typ)
   337  
   338          print('return true', file=fd)
   339          print('}', file=fd)
   340  
   341  
   342  def get_orig_prefix(mod):
   343      orig = mod.i_orig_module
   344      if orig:
   345          get_orig_prefix(orig)
   346      else:
   347          return mod.i_prefix
   348  
   349  
   350  def get_path(c):
   351      path = ''
   352      if c.parent is not None:
   353          p = ''
   354          if hasattr(c, 'i_module'):
   355              mod = c.i_module
   356              prefix = mod.search_one('prefix')
   357              if prefix:
   358                  p = prefix.arg + ":"
   359  
   360          path = get_path(c.parent) + "/" + p + c.arg
   361      return path
   362  
   363  
   364  # define container embedded enums
   365  def define_enum(ctx, mod, c):
   366      prefix = mod.i_prefix
   367      c.path = get_path(c)
   368      c.golang_name = convert_to_golang(c.arg)
   369      if prefix in ctx.golang_typedef_map:
   370          ctx.golang_typedef_map[prefix][c.arg] = c
   371      else:
   372          ctx.golang_typedef_map[prefix] = {c.arg: c}
   373  
   374  
   375  def visit_children(ctx, mod, children):
   376      for c in children:
   377          if is_case(c):
   378              prefix = get_orig_prefix(c.parent.i_orig_module)
   379              c.i_orig_module = c.parent.i_orig_module
   380          else:
   381              prefix = get_orig_prefix(c.i_orig_module)
   382  
   383          c.uniq_name = c.arg
   384          if c.arg == 'config':
   385              c.uniq_name = c.parent.uniq_name + '-config'
   386  
   387          elif c.arg == 'state':
   388              c.uniq_name = c.parent.uniq_name + '-state'
   389  
   390          elif c.arg == 'graceful-restart' and prefix == 'bgp-mp':
   391              c.uniq_name = 'mp-graceful-restart'
   392  
   393          if is_leaf(c) and is_enum(c.search_one('type')):
   394              define_enum(ctx, mod, c)
   395  
   396          elif is_list(c) or is_container(c) or is_choice(c):
   397              c.golang_name = convert_to_golang(c.uniq_name)
   398  
   399              if is_choice(c):
   400                  picks = pickup_choice(c)
   401                  c.i_children = picks
   402                  if is_enum_choice(c):
   403                      define_enum(ctx, mod, c)
   404                      continue
   405  
   406              prefix_name = prefix + ':' + c.uniq_name
   407              if prefix_name in ctx.golang_struct_names:
   408                  ext_c = ctx.golang_struct_names.get(prefix_name)
   409                  ext_c_child_count = len(getattr(ext_c, "i_children"))
   410                  current_c_child_count = len(getattr(c, "i_children"))
   411                  if ext_c_child_count < current_c_child_count:
   412                      c.module_prefix = prefix
   413                      ctx.golang_struct_names[prefix_name] = c
   414                      idx = ctx.golang_struct_def.index(ext_c)
   415                      ctx.golang_struct_def[idx] = c
   416              else:
   417                  c.module_prefix = prefix
   418                  ctx.golang_struct_names[prefix_name] = c
   419                  ctx.golang_struct_def.append(c)
   420  
   421          c.path = get_path(c)
   422          # print(c.path, file=sys.stderr)
   423          if hasattr(c, 'i_children'):
   424              visit_children(ctx, mod, c.i_children)
   425  
   426  
   427  def pickup_choice(c):
   428      element = []
   429      for child in c.i_children:
   430          if is_case(child):
   431              element = element + child.i_children
   432  
   433      return element
   434  
   435  
   436  def get_type_spec(stmt):
   437      for s in stmt.substmts:
   438          if hasattr(s, 'i_type_spec'):
   439              return s.i_type_spec.name
   440  
   441      return None
   442  
   443  
   444  def visit_typedef(ctx, mod):
   445      prefix = mod.i_prefix
   446      child_map = {}
   447      for stmt in mod.substmts:
   448          if is_typedef(stmt):
   449              stmt.path = get_path(stmt)
   450              # print('stmt.path = "%s"' % stmt.path, file=sys.stderr)
   451              name = stmt.arg
   452              stmt.golang_name = convert_to_golang(name)
   453              # print('stmt.golang_name = "%s"' % stmt.golang_name, file=sys.stderr)
   454              child_map[name] = stmt
   455  
   456      ctx.golang_typedef_map[prefix] = child_map
   457      # print('ctx.golang_typedef_map["%s"] = %s' % (prefix, child_map), file=sys.stderr)
   458      prefix_rel = ctx.prefix_rel[prefix]
   459      ctx.golang_typedef_map[prefix_rel] = child_map
   460      # print('ctx.golang_typedef_map["%s"] = %s' % (prefix_rel, child_map)), file=sys.stderr)
   461  
   462  
   463  def visit_identity(ctx, mod):
   464      prefix = mod.i_prefix
   465      child_map = {}
   466      for stmt in mod.substmts:
   467          if is_identity(stmt):
   468              name = stmt.arg
   469              stmt.golang_name = convert_to_golang(name)
   470              # print('stmt.golang_name = "%s"' % stmt.golang_name, file=sys.stderr)
   471              child_map[name] = stmt
   472  
   473              base = stmt.search_one('base')
   474              if base:
   475                  base_name = base.arg
   476                  if ':' in base_name:
   477                      base_prefix, base_name = base_name.split(':', 1)
   478                      if base_prefix in ctx.golang_identity_map:
   479                          ctx.golang_identity_map[base_prefix][base_name].substmts.append(stmt)
   480                  else:
   481                      child_map[base_name].substmts.append(stmt)
   482  
   483      ctx.golang_identity_map[prefix] = child_map
   484      # print('ctx.golang_identity_map["%s"] = %s\n' % (prefix, child_map), file=sys.stderr)
   485      prefix_rel = ctx.prefix_rel[prefix]
   486      ctx.golang_identity_map[prefix_rel] = child_map
   487      # print('ctx.golang_identity_map["%s"] = %s\n' % (prefix_rel, child_map), file=sys.stderr)
   488  
   489  
   490  def lookup_identity(ctx, default_prefix, identity_name):
   491      result = lookup(ctx.golang_identity_map, default_prefix, identity_name)
   492      return result
   493  
   494  
   495  def lookup_typedef(ctx, default_prefix, type_name):
   496      result = lookup(ctx.golang_typedef_map, default_prefix, type_name)
   497      return result
   498  
   499  
   500  def lookup(basemap, default_prefix, key):
   501      if ':' in key:
   502          pref, name = key.split(':')
   503      else:
   504          pref = default_prefix
   505          name = key
   506  
   507      if pref in basemap:
   508          return basemap[pref].get(name, None)
   509      else:
   510          return key
   511  
   512  
   513  def emit_description(stmt, fd):
   514      desc = stmt.search_one('description')
   515      if desc is None:
   516          return None
   517      desc_words = desc.arg if desc.arg.endswith('.') else desc.arg + '.'
   518      print('// %s' % desc_words.replace('\n', '\n// '), file=fd)
   519  
   520  
   521  def emit_enum(prefix, name, stmt, substmts, fd):
   522      type_name_org = name
   523      type_name = stmt.golang_name
   524      print('// typedef for identity %s:%s.' % (prefix, type_name_org), file=fd)
   525      emit_description(stmt, fd)
   526      print('type %s string' % type_name, file=fd)
   527  
   528      const_prefix = convert_const_prefix(type_name_org)
   529      print('const (', file=fd)
   530      m = {}
   531  
   532      if is_choice(stmt) and is_enum_choice(stmt):
   533          n = namedtuple('Statement', ['arg'])
   534          n.arg = 'none'
   535          substmts = [n] + substmts
   536  
   537      for sub in substmts:
   538          enum_name = '%s_%s' % (const_prefix, convert_const_prefix(sub.arg))
   539          m[sub.arg.lower()] = enum_name
   540          print(' %s %s = "%s"' % (enum_name, type_name, sub.arg.lower()), file=fd)
   541      print(')\n', file=fd)
   542  
   543      print('var %sToIntMap = map[%s]int {' % (type_name, type_name), file=fd)
   544      for i, sub in enumerate(substmts):
   545          enum_name = '%s_%s' % (const_prefix, convert_const_prefix(sub.arg))
   546          print(' %s: %d,' % (enum_name, i), file=fd)
   547      print('}\n', file=fd)
   548  
   549      print('var IntTo%sMap = map[int]%s {' % (type_name, type_name), file=fd)
   550      for i, sub in enumerate(substmts):
   551          enum_name = '%s_%s' % (const_prefix, convert_const_prefix(sub.arg))
   552          print(' %d: %s,' % (i, enum_name), file=fd)
   553      print('}\n', file=fd)
   554  
   555      print('func (v %s) Validate() error {' % type_name, file=fd)
   556      print('if _, ok := %sToIntMap[v]; !ok {' % type_name, file=fd)
   557      print('return fmt.Errorf("invalid %s: %%s", v)' % type_name, file=fd)
   558      print('}', file=fd)
   559      print('return nil', file=fd)
   560      print('}\n', file=fd)
   561  
   562      if stmt.search_one('default'):
   563          default = stmt.search_one('default')
   564          print('func (v %s) Default() %s {' % (type_name, type_name), file=fd)
   565          print('return %s' % m[default.arg.lower()], file=fd)
   566          print('}\n', file=fd)
   567  
   568          print('func (v %s) DefaultAsNeeded() %s {' % (type_name, type_name), file=fd)
   569          print(' if string(v) == "" {', file=fd)
   570          print(' return v.Default()', file=fd)
   571          print('}', file=fd)
   572          print(' return v', file=fd)
   573          print('}', file=fd)
   574  
   575          print('func (v %s) ToInt() int {' % type_name, file=fd)
   576          print('_v := v.DefaultAsNeeded()')
   577          print('i, ok := %sToIntMap[_v]' % type_name, file=fd)
   578  
   579      else:
   580          print('func (v %s) ToInt() int {' % type_name, file=fd)
   581          print('i, ok := %sToIntMap[v]' % type_name, file=fd)
   582      print('if !ok {', file=fd)
   583      print('return -1', file=fd)
   584      print('}', file=fd)
   585      print('return i', file=fd)
   586      print('}', file=fd)
   587  
   588  
   589  def emit_typedef(ctx, mod, fd):
   590      prefix = mod.i_prefix
   591      t_map = ctx.golang_typedef_map[prefix]
   592      for name, stmt in t_map.items():
   593          if stmt.path in _typedef_exclude:
   594              continue
   595  
   596          # skip identityref type because currently skip identity
   597          if get_type_spec(stmt) == 'identityref':
   598              continue
   599  
   600          type_name_org = name
   601          type_name = stmt.golang_name
   602          if type_name in ctx.emitted_type_names:
   603              print("warning %s: %s has already been emitted from %s."
   604                    % (prefix + ":" + type_name_org, type_name_org, ctx.emitted_type_names[type_name]),
   605                    file=sys.stderr)
   606              continue
   607  
   608          ctx.emitted_type_names[type_name] = prefix + ":" + type_name_org
   609  
   610          t = stmt.search_one('type')
   611          if not t and is_choice(stmt):
   612              emit_enum(prefix, type_name_org, stmt, stmt.i_children, fd)
   613          elif is_enum(t):
   614              emit_enum(prefix, type_name_org, stmt, t.substmts, fd)
   615          elif is_union(t):
   616              print('// typedef for typedef %s:%s.' % (prefix, type_name_org), file=fd)
   617              emit_description(t, fd)
   618              print('type %s string' % type_name, file=fd)
   619          else:
   620              if is_leafref(t):
   621                  t = dig_leafref(t)
   622  
   623              print('// typedef for typedef %s:%s.' % (prefix, type_name_org), file=fd)
   624              if is_builtin_type(t):
   625                  emit_description(t, fd)
   626                  print('type %s %s' % (type_name, t.arg), file=fd)
   627              elif is_translation_required(t):
   628                  print('// %s:%s\'s original type is %s.' % (prefix, name, t.arg), file=fd)
   629                  emit_description(t, fd)
   630                  print('type %s %s' % (type_name, translate_type(t.arg)), file=fd)
   631              else:
   632                  m = ctx.golang_typedef_map
   633                  for k in t.arg.split(':'):
   634                      m = m[k]
   635                  emit_description(t, fd)
   636                  print('type %s %s' % (type_name, m.golang_name), file=fd)
   637  
   638  
   639  def emit_identity(ctx, mod, fd):
   640      prefix = mod.i_prefix
   641      i_map = ctx.golang_identity_map[prefix]
   642      for name, stmt in i_map.items():
   643          enums = stmt.search('identity')
   644          if len(enums) > 0:
   645              emit_enum(prefix, name, stmt, enums, fd)
   646  
   647  
   648  def is_reference(s):
   649      return s.arg in ['leafref', 'identityref']
   650  
   651  
   652  def is_leafref(s):
   653      return s.arg in ['leafref']
   654  
   655  
   656  def is_identityref(s):
   657      return s.arg in ['identityref']
   658  
   659  
   660  def is_enum(s):
   661      return s.arg in ['enumeration']
   662  
   663  
   664  def is_union(s):
   665      return s.arg in ['union']
   666  
   667  
   668  def is_typedef(s):
   669      return s.keyword in ['typedef']
   670  
   671  
   672  def is_identity(s):
   673      return s.keyword in ['identity']
   674  
   675  
   676  def is_leaf(s):
   677      return s.keyword in ['leaf']
   678  
   679  
   680  def is_leaflist(s):
   681      return s.keyword in ['leaf-list']
   682  
   683  
   684  def is_list(s):
   685      return s.keyword in ['list']
   686  
   687  
   688  def is_container(s):
   689      return s.keyword in ['container']
   690  
   691  
   692  def is_case(s):
   693      return s.keyword in ['case']
   694  
   695  
   696  def is_choice(s):
   697      return s.keyword in ['choice']
   698  
   699  
   700  def is_enum_choice(s):
   701      return all(e.search_one('type').arg in _type_enum_case for e in s.i_children)
   702  
   703  
   704  _type_enum_case = [
   705      'empty',
   706  ]
   707  
   708  
   709  def is_builtin_type(t):
   710      return t.arg in _type_builtin
   711  
   712  
   713  def is_translation_required(t):
   714      return t.arg in list(_type_translation_map.keys())
   715  
   716  
   717  _type_translation_map = {
   718      'union': 'string',
   719      'decimal64': 'float64',
   720      'boolean': 'bool',
   721      'empty': 'bool',
   722      'inet:ip-address': 'string',
   723      'inet:ip-prefix': 'string',
   724      'inet:ipv4-address': 'string',
   725      'inet:as-number': 'uint32',
   726      'bgp-set-community-option-type': 'string',
   727      'inet:port-number': 'uint16',
   728      'yang:timeticks': 'int64',
   729      'ptypes:install-protocol-type': 'string',
   730      'binary': '[]byte',
   731      'route-family': 'bgp.RouteFamily',
   732      'bgp-capability': 'bgp.ParameterCapabilityInterface',
   733      'bgp-open-message': '*bgp.BGPMessage',
   734  }
   735  
   736  
   737  _type_builtin = [
   738      "union",
   739      "int8",
   740      "int16",
   741      "int32",
   742      "int64",
   743      "string",
   744      "uint8",
   745      "uint16",
   746      "uint32",
   747      "uint64",
   748  ]
   749  
   750  
   751  _module_excluded = [
   752      "ietf-inet-types",
   753      "ietf-yang-types",
   754  ]
   755  
   756  _path_exclude = [
   757      "/rpol:routing-policy/rpol:defined-sets/rpol:neighbor-sets/rpol:neighbor-set/rpol:neighbor",
   758      "/rpol:routing-policy/rpol:defined-sets/bgp-pol:bgp-defined-sets/bgp-pol:community-sets/bgp-pol:community-set/bgp-pol:community-member",
   759      "/rpol:routing-policy/rpol:defined-sets/bgp-pol:bgp-defined-sets/bgp-pol:ext-community-sets/bgp-pol:ext-community-set/bgp-pol:ext-community-member",
   760      "/rpol:routing-policy/rpol:defined-sets/bgp-pol:bgp-defined-sets/bgp-pol:as-path-sets/bgp-pol:as-path-set/bgp-pol:as-path-set-member",
   761  ]
   762  
   763  _typedef_exclude = [
   764      "/gobgp:bgp-capability",
   765      "/gobgp:bgp-open-message",
   766  ]
   767  
   768  
   769  def generate_header(fd):
   770      print(_COPYRIGHT_NOTICE, file=fd)
   771      print('package config', file=fd)
   772      print('', file=fd)
   773      print('import (', file=fd)
   774      print('"fmt"', file=fd)
   775      print('', file=fd)
   776      print('"github.com/osrg/gobgp/pkg/packet/bgp"', file=fd)
   777      print(')', file=fd)
   778      print('', file=fd)
   779  
   780  
   781  def generate_common_functions(fd):
   782      print('func mapkey(index int, name string) string {', file=fd)
   783      print('if name != "" {', file=fd)
   784      print('return name', file=fd)
   785      print('}', file=fd)
   786      print('return fmt.Sprintf("%v", index)', file=fd)
   787      print('}', file=fd)
   788  
   789  
   790  def translate_type(key):
   791      if key in _type_translation_map.keys():
   792          return _type_translation_map[key]
   793      else:
   794          return key
   795  
   796  
   797  # 'hoge-hoge' -> 'HogeHoge'
   798  def convert_to_golang(type_string):
   799      a = type_string.split('.')
   800      return '.'.join(''.join(t.capitalize() for t in x.split('-')) for x in a)
   801  
   802  
   803  # 'hoge-hoge' -> 'HOGE_HOGE'
   804  def convert_const_prefix(type_string):
   805      return type_string.replace('-', '_').upper()
   806  
   807  
   808  def chop_suf(s, suf):
   809      if not s.endswith(suf):
   810          return s
   811      return s[:-len(suf)]