<reponame>zhsj/elvish
#!/usr/bin/python2.7
import re
import os


def put_set(out, parent, field, child):
    print >>out, '''
func (n *{parent}) set{field}(ch *{child}) {{
    n.{field} = ch
    addChild(n, ch)
}}'''.format(parent=parent, field=field, child=child)


def put_addto(out, parent, field, child):
    print >>out, '''
func (n *{parent}) addTo{field}(ch *{child}) {{
    n.{field} = append(n.{field}, ch)
    addChild(n, ch)
}}'''.format(parent=parent, field=field, child=child)


def put_parse(out, typename, extraargs):
    extranames = ', '.join(a.split(' ')[0] for a in extraargs.split(', ')) if extraargs else ''
    print >>out, '''
func parse{typename}(ps *parser{extraargs}) *{typename} {{
    n := &{typename}{{node: node{{begin: ps.pos}}}}
    n.parse(ps{extranames})
    n.end = ps.pos
    n.sourceText = ps.src[n.begin:n.end]
    return n
}}'''.format(typename=typename, extraargs=extraargs, extranames=extranames)


def main():
    types = []
    in_type = ''
    out = open('boilerplate.go', 'w')
    print >>out, 'package parse'
    for line in file('parse.go'):
        if in_type:
            if line == '}\n':
                in_type = ''
                continue
            m = re.match(r'^\t(\w+(?:, \w+)*) +(\S+)', line)
            if m:
                fields = m.group(1).split(', ')
                typename = m.group(2)
                if typename.startswith('*'):
                    # Single child
                    [put_set(out, in_type, f, typename[1:]) for f in fields]
                elif typename.startswith('[]*'):
                    # Children list
                    [put_addto(out, in_type, f, typename[3:]) for f in fields]
            continue
        m = re.match(r'^type (.*) struct', line)
        if m:
            in_type = m.group(1)
            continue
        m = re.match(
            r'^func \(.* \*(.*)\) parse\(ps \*parser(.*?)\) {$', line)
        if m:
            typename, extraargs = m.groups()
            put_parse(out, typename, extraargs)
    out.close()
    os.system('gofmt -w boilerplate.go')


if __name__ == '__main__':
    main()
