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()