| #!/usr/bin/env python |
| |
| from collections import OrderedDict |
| from sets import Set |
| from shutil import copyfile |
| import argparse |
| import json |
| import os |
| import pprint |
| import re |
| import subprocess |
| |
| def normalize(dict_var): |
| for k, v in dict_var.items(): |
| if isinstance(v, OrderedDict): |
| normalize(v) |
| elif isinstance(v, list): |
| for e in v: |
| if isinstance(e, OrderedDict): |
| normalize(e) |
| elif type(v) is unicode: |
| st = v.encode('utf-8') |
| if v != "0x0" and re.match(r"0x[0-9A-Fa-f]+", v): |
| dict_var[k] = u'0x{{.*}}' |
| elif os.path.isfile(v): |
| dict_var[k] = u'{{.*}}' |
| else: |
| splits = (v.split(u' ')) |
| out_splits = [] |
| for split in splits: |
| inner_splits = split.rsplit(u':',2) |
| if os.path.isfile(inner_splits[0]): |
| out_splits.append( |
| u'{{.*}}:%s:%s' |
| %(inner_splits[1], |
| inner_splits[2])) |
| continue |
| out_splits.append(split) |
| |
| dict_var[k] = ' '.join(out_splits) |
| |
| def filter_json(dict_var, filters, out): |
| for k, v in dict_var.items(): |
| if type(v) is unicode: |
| st = v.encode('utf-8') |
| if st in filters: |
| out.append(dict_var) |
| break |
| elif isinstance(v, OrderedDict): |
| filter_json(v, filters, out) |
| elif isinstance(v, list): |
| for e in v: |
| if isinstance(e, OrderedDict): |
| filter_json(e, filters, out) |
| |
| def main(): |
| parser = argparse.ArgumentParser() |
| parser.add_argument("--clang", help="The clang binary (could be a relative or absolute path)", |
| action="store", required=True) |
| parser.add_argument("--opts", help="other options", |
| action="store", default='', type=str) |
| parser.add_argument("--source", help="the source file. Command used to generate the json will be of the format <clang> -cc1 -ast-dump=json <opts> <source>", |
| action="store", required=True) |
| parser.add_argument("--filters", help="comma separated list of AST filters. Ex: --filters=TypedefDecl,BuiltinType", |
| action="store", default='') |
| |
| args = parser.parse_args() |
| |
| if not args.source: |
| print("Specify the source file to give to clang.") |
| return -1 |
| |
| clang_binary = os.path.abspath(args.clang) |
| if not os.path.isfile(clang_binary): |
| print("clang binary specified not present.") |
| return -1 |
| |
| options = args.opts.split(' ') |
| filters = Set(args.filters.split(',')) if args.filters else Set([]) |
| |
| note = "// NOTE: CHECK lines have been autogenerated by " \ |
| "gen_ast_dump_json_test.py" |
| |
| if (args.filters): |
| note += "\n// using --filters=" + args.filters |
| |
| cmd = [clang_binary, "-cc1"] |
| cmd.extend(options) |
| |
| using_ast_dump_filter = 'ast-dump-filter' in args.opts |
| |
| cmd.extend(["-ast-dump=json", args.source]) |
| |
| try: |
| json_str = subprocess.check_output(cmd) |
| except Exception as ex: |
| print("The clang command failed with %s" % ex) |
| return -1 |
| |
| out_asts = [] |
| if using_ast_dump_filter: |
| splits = re.split('Dumping .*:\n', json_str) |
| if len(splits) > 1: |
| for split in splits[1:]: |
| j = json.loads(split.decode('utf-8'), object_pairs_hook=OrderedDict) |
| normalize(j) |
| out_asts.append(j) |
| else: |
| j = json.loads(json_str.decode('utf-8'), object_pairs_hook=OrderedDict) |
| normalize(j) |
| |
| if len(filters) == 0: |
| out_asts.append(j) |
| else: |
| #assert using_ast_dump_filter is False,\ |
| # "Does not support using compiler's ast-dump-filter "\ |
| # "and the tool's filter option at the same time yet." |
| |
| filter_json(j, filters, out_asts) |
| |
| partition = args.source.rpartition('.') |
| dest_path = '%s-json%s%s' % (partition[0], partition[1], partition[2]) |
| |
| print("Writing json appended source file to %s." %(dest_path)) |
| copyfile(args.source, dest_path) |
| with open(dest_path, "a") as f: |
| f.write("\n" + note + "\n") |
| for out_ast in out_asts: |
| append_str = json.dumps(out_ast, indent=1, ensure_ascii=False) |
| out_str = '\n\n' |
| index = 0 |
| for append_line in append_str.splitlines()[2:]: |
| if index == 0: |
| out_str += '// CHECK: %s\n' %(append_line.rstrip()) |
| index += 1 |
| else: |
| out_str += '// CHECK-NEXT: %s\n' %(append_line.rstrip()) |
| |
| f.write(out_str) |
| |
| return 0 |
| |
| if __name__ == '__main__': |
| main() |