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