'''Tool for generating the dbscheme from the relation tree described in 'master.py' and the part scheme in dbscheme.template''' from semmle.util import fprintf from semmle import util from semmle.python import master import sys import os.path def write(nodes, out): nodes = set(nodes) #Emit in sorted order to reduce diffs. sorted_nodes = sorted(nodes, key = lambda n: n.__name__) fprintf(out, '\n') for n in sorted_nodes: if n.layout: fprintf(out, '\n') for name, f_t, offset, _, _, _ in n.layout: fprintf(out, '/* %s.%s = %s, %s */\n', n.ql_name(), name, offset, f_t.__name__) if n.parents: fprintf(out, '/* %s = %s */\n', n.ql_name(), n.parents.ql_name()) parents = set() for n in sorted_nodes: if n.is_sub_type() or n.is_union_type(): continue fprintf(out, u'%s(', n.relation_name()) if n.__name__ == "bool": fields = [] else: fields = [ n.db_key('id') ] if n.is_case_type(): fields.append('int kind: int ref') if n.parents: parents.add(n.parents) if n.unique_parent: fields.append('unique int parent : %s ref' % n.parents.db_name()) else: fields.append('int parent : %s ref' % n.parents.db_name()) fields.append('int idx : int ref') fprintf(out, ',\n '.join(fields)) fprintf(out, ');\n\n') nodes = nodes | parents sorted_nodes = sorted(nodes, key = lambda n: n.__name__) for n in sorted_nodes: if n.is_case_type(): fprintf(out, 'case %s.kind of\n ', n.db_name()) subtypes = sorted(n.subclasses, key = lambda x : x.index) body = '\n| '.join(['%s = %s' % (s.index, s.db_name()) for s in subtypes]) fprintf(out, '%s;\n\n' % body) for n in sorted_nodes: if n.is_union_type(): fprintf(out, '%s = ', n.db_name()) body = ' | '.join(sorted([item.db_name() for item in n.types])) fprintf(out, '%s;\n\n' % body) HEADER = '''/* * This dbscheme is auto-generated by '%s'. * WARNING: Any modifications to this file will be lost. * Relations can be changed by modifying master.py or * by adding rules to dbscheme.template */ ''' AUTO_GEN_END = ''' /* * End of auto-generated part */ ''' def main(): run(master) def run(nodes_module): use_file = len(sys.argv) > 1 if use_file: out = open(sys.argv[1], 'w', encoding='utf-8') else: out = sys.stdout try: nodes = nodes_module.all_nodes() this_dir, _ = os.path.split(sys.argv[0]) with open(os.path.join(this_dir, 'dbscheme.template')) as template_file: t0, t1 = template_file.read().split('$AST_SCHEME$') out.write(HEADER % '/'.join(__file__.split(os.path.sep)[-2:])) out.write(t0) out.write(util.AUTO_GEN_STRING) write(nodes.values(), out) out.write(AUTO_GEN_END) out.write(t1) finally: if use_file: out.close() if __name__ == '__main__': main()