#! /usr/bin/env python
#
# Autogenerates infrastructure code for visitor handling from a list of classes. Outputs:
#
#   <dst-dir>/visitor-interface.h
#   <dst-dir>/visitor-types.h
#   <dst-dir>/visitor-rtti.c
#
# TODO: Do we still need these?
#   <dst-dir>/visitor-template.h    # Template methods decls for c&p use in a visitor.
#   <dst-dir>/visitor-template.cc   # Template methods implementations for c&p use in a visitor.

import os.path
import sys

if len(sys.argv) != 4:
    print >>sys.stderr, "usage: %s <namespace> <decl-file> <dst-dir>\n" % sys.argv[0]
    sys.exit(1)

namespace = sys.argv[1]
decls     = sys.argv[2]
dst       = sys.argv[3]

includes = []
classes = []
parents = {}

current = None

lnr = 0

for line in open(decls):
    lnr += 1

    line = line.strip()

    if line.startswith("#include "):
        includes.append(line)
        continue

    if not line or line.startswith("#"):
        continue

    if line.startswith(":"):
        d = parents.setdefault(current, set())
        d.add(line.split(":", 1)[1].strip())
        continue

    if line.startswith("-"):
        visitor = False
        cls = line[1:]
    else:
        visitor = True
        cls = line

    classes += [(visitor, cls, lnr, decls)]
    current = cls

classes.sort()

interface = open(os.path.join(dst, "visitor-interface.h"), "w")
types     = open(os.path.join(dst, "visitor-types.h"), "w")
tmpl_h    = open(os.path.join(dst, "visitor-template.h"), "w")
tmpl_cc   = open(os.path.join(dst, "visitor-template.cc"), "w")
rtti_cc   = open(os.path.join(dst, "visitor-rtti.cc"), "w")

print >>types, "namespace %s" % namespace, "{"
print >>types, ""

print >>rtti_cc, "#include <ast/rtti.h>"

for include in includes:
    print >>rtti_cc, include

print >>rtti_cc, ""
#print >>rtti_cc, "#define __RTTI_NAMESPACE %s" % namespace
#print >>rtti_cc, "namespace %s" % namespace, "{"
print >>rtti_cc, ""

for (visitor, cls, line, file) in classes:
    m = cls.split("::")

    id = ("%s_%s" % (namespace, cls)).replace("::", "_")
    print >>rtti_cc, "#line %d \"%s\"" % (line, file)
    print >>rtti_cc, "AST_RTTI_BEGIN(%s::%s, %s)" % (namespace, cls, id)

    for p in parents.get(cls, set()):
        print >>rtti_cc, "#line %d \"%s\"" % (line, file)
        print >>rtti_cc, "  AST_RTTI_PARENT(%s::%s)" %  (namespace, p)

    print >>rtti_cc, "#line %d \"%s\"" % (line, file)
    print >>rtti_cc, "AST_RTTI_END(%s)\n" % id

    print >>rtti_cc, "#line %d \"%s\"" % (line, file)
    print >>rtti_cc, "AST_RTTI_CAST_BEGIN(%s::%s)" % (namespace, cls)

    for p in parents.get(cls, set()):
        print >>rtti_cc, "#line %d \"%s\"" % (line, file)
        print >>rtti_cc, "  AST_RTTI_CAST_PARENT(%s::%s)" % (namespace, p)

    print >>rtti_cc, "#line %d \"%s\"" % (line, file)
    print >>rtti_cc, "AST_RTTI_CAST_END()\n"

    if not visitor:
        continue

    for ns in m[:-1]:
        print >>types, "namespace %s {" % ns,

    print >>types, "class %s;" % m[-1],

    for ns in m[:-1]:
        print >>types, "}",

    print >>types, ""

    print >>interface, "virtual void visit(%s* n) {}" % cls

    first = m[-1].lower()[0]

    print >>tmpl_h, "    void visit(%s* %s) override;" % (cls, first)
    print >>tmpl_cc, "void XXX::visit(%s* %s)\n{\n}\n" % (cls, first)

print >>types, ""
print >>types, "}",

#print >>rtti_cc, ""
#print >>rtti_cc, "}",

