github.com/hugelgupf/u-root@v0.0.0-20191023214958-4807c632154c/cmds/core/elvish/parse/boilerplate.py (about)

     1  #!/usr/bin/python2.7
     2  """
     3  Generate helper functions for node types.
     4  
     5  For every node type T, it generates the following:
     6  
     7  * A IsT func that determines whether a Node is actually of type *T.
     8  
     9  * A GetT func that takes Node and returns *T. It examines whether the Node is
    10    actually of type *T, and if it is, returns it; otherwise it returns nil.
    11  
    12  * For each field F of type *[]U, it generates a addToF method that appends a
    13    node to this field and adds it to the children list.
    14  
    15  * For each field F of type *U where U is not a slice, it generates a setF
    16    method that sets this field and adds it to the children list.
    17  
    18  * If the type has a parse method that takes a *paser, it genertes a parseT
    19    func that takes a *Parser and returns *T. The func creates a new instance of
    20    *T, sets its begin field, calls its parse method, and set its end and
    21    sourceText fields.
    22  
    23  For example, for the following type:
    24  
    25  type X struct {
    26      node
    27      F *Y
    28      G *[]Z
    29  }
    30  
    31  The following boilerplate is generated:
    32  
    33  func IsX(n Node) bool {
    34      _, ok := n.(*X)
    35      return ok
    36  }
    37  
    38  func GetX(n Node) *X {
    39      if nn, ok := n.(*X); ok {
    40          return nn
    41      }
    42      return nil
    43  }
    44  
    45  func (n *X) setF(ch *Y) {
    46      n.F = ch
    47      addChild(n, ch)
    48  }
    49  
    50  func (n *X) addToG(ch *Z) {
    51      n.G = append(n.G, ch)
    52      addChild(n, ch)
    53  }
    54  
    55  func ParseX(ps *Parser) *X {
    56      n := &X{node: node{begin: ps.pos}}
    57      n.parse(ps)
    58      n.end = ps.pos
    59      n.sourceText = ps.src[n.begin:n.end]
    60      return n
    61  }
    62  """
    63  import re
    64  import os
    65  
    66  
    67  def put_is(out, typename):
    68      print >>out, '''
    69  func Is{typename}(n Node) bool {{
    70      _, ok := n.(*{typename})
    71      return ok
    72  }}
    73  '''.format(typename=typename)
    74  
    75  
    76  def put_get(out, typename):
    77      print >>out, '''
    78  func Get{typename}(n Node) *{typename} {{
    79      if nn, ok := n.(*{typename}); ok {{
    80          return nn
    81      }}
    82      return nil
    83  }}
    84  '''.format(typename=typename)
    85  
    86  
    87  def put_set(out, parent, field, child):
    88      print >>out, '''
    89  func (n *{parent}) set{field}(ch *{child}) {{
    90      n.{field} = ch
    91      addChild(n, ch)
    92  }}'''.format(parent=parent, field=field, child=child)
    93  
    94  
    95  def put_addto(out, parent, field, child):
    96      print >>out, '''
    97  func (n *{parent}) addTo{field}(ch *{child}) {{
    98      n.{field} = append(n.{field}, ch)
    99      addChild(n, ch)
   100  }}'''.format(parent=parent, field=field, child=child)
   101  
   102  
   103  def put_parse(out, typename, extraargs):
   104      extranames = ', '.join(a.split(' ')[0] for a in extraargs.split(', ')) if extraargs else ''
   105      print >>out, '''
   106  func Parse{typename}(ps *Parser{extraargs}) *{typename} {{
   107      n := &{typename}{{node: node{{begin: ps.pos}}}}
   108      n.parse(ps{extranames})
   109      n.end = ps.pos
   110      n.sourceText = ps.src[n.begin:n.end]
   111      return n
   112  }}'''.format(typename=typename, extraargs=extraargs, extranames=extranames)
   113  
   114  
   115  def main():
   116      types = []
   117      in_type = ''
   118      out = open('boilerplate.go', 'w')
   119      print >>out, 'package parse'
   120      for line in file('parse.go'):
   121          if in_type:
   122              if line == '}\n':
   123                  in_type = ''
   124                  continue
   125              m = re.match(r'^\t(\w+(?:, \w+)*) +(\S+)', line)
   126              if m:
   127                  fields = m.group(1).split(', ')
   128                  typename = m.group(2)
   129                  if typename.startswith('*'):
   130                      # Single child
   131                      [put_set(out, in_type, f, typename[1:]) for f in fields]
   132                  elif typename.startswith('[]*'):
   133                      # Children list
   134                      [put_addto(out, in_type, f, typename[3:]) for f in fields]
   135              continue
   136          m = re.match(r'^type (.*) struct', line)
   137          if m:
   138              in_type = m.group(1)
   139              put_is(out, in_type)
   140              put_get(out, in_type)
   141              continue
   142          m = re.match(
   143              r'^func \(.* \*(.*)\) parse\(ps \*Parser(.*?)\) {$', line)
   144          if m:
   145              typename, extraargs = m.groups()
   146              put_parse(out, typename, extraargs)
   147      out.close()
   148      os.system('gofmt -w boilerplate.go')
   149  
   150  
   151  if __name__ == '__main__':
   152      main()