|
1 |
| -import sys |
2 |
| -import os.path |
3 |
| -import glob |
4 |
| -import re |
5 |
| -import json |
6 |
| - |
7 |
| -BEGIN_TEMPLATE = re.compile(r"^/\*template\s*$") |
8 |
| -END_TEMPLATE = re.compile(r"^\*/\s*$") |
9 |
| - |
10 |
| -def expand_template_params(args, param_arg_map): |
11 |
| - '''Given a list of template arguments that may reference template parameters |
12 |
| - of the current template, return a new list of template arguments with each |
13 |
| - parameter use replaced with the appropriate fully-qualified argument for |
14 |
| - that parameter.''' |
15 |
| - result = [] |
16 |
| - for arg in args: |
17 |
| - if arg in param_arg_map: |
18 |
| - result.append(param_arg_map[arg]) |
19 |
| - else: |
20 |
| - result.append(arg) |
21 |
| - |
22 |
| - return result |
23 |
| - |
24 |
| -def find_instantiation(module, args, templates): |
25 |
| - '''Given a template module and a set of template arguments, find the module |
26 |
| - name of the instantiation of that module with those arguments.''' |
27 |
| - template = templates[module] |
28 |
| - for instantiation in template["template_def"]["instantiations"]: |
29 |
| - if instantiation["args"] == args: |
30 |
| - return instantiation["name"] |
31 |
| - return None |
32 |
| - |
33 |
| -def instantiate_template(template, instantiation, root, templates): |
34 |
| - '''Create a single instantiation of a template.''' |
35 |
| - template_def = template["template_def"] |
36 |
| - output_components = instantiation["name"].split(".") |
37 |
| - output_path = root |
38 |
| - for component in output_components: |
39 |
| - output_path = os.path.join(output_path, component) |
40 |
| - output_path = output_path + ".qll" |
41 |
| - with open(output_path, "w") as output: |
42 |
| - output.write( |
43 |
| -""" |
44 |
| -/* |
45 |
| - * THIS FILE IS AUTOMATICALLY GENERATED FROM '%s'. |
46 |
| - * DO NOT EDIT MANUALLY. |
47 |
| - */ |
48 |
| -
|
49 |
| -""" % (template["name"].replace(".", "/") + ".qllt") |
50 |
| - ) |
51 |
| - param_arg_map = {} |
52 |
| - for param_index in range(len(template_def["params"])): |
53 |
| - param = template_def["params"][param_index] |
54 |
| - arg = instantiation["args"][param_index] |
55 |
| - output.write("private import %s as %s // Template parameter\n" % (arg, param)) |
56 |
| - param_arg_map[param] = arg |
57 |
| - for import_record in template_def["imports"]: |
58 |
| - if "access" in import_record: |
59 |
| - output.write(import_record["access"] + " ") |
60 |
| - imported_module = find_instantiation(import_record["module"], |
61 |
| - expand_template_params(import_record["args"], param_arg_map), templates) |
62 |
| - output.write("import %s // %s<%s>\n" % |
63 |
| - ( |
64 |
| - imported_module, |
65 |
| - import_record["module"], |
66 |
| - ", ".join(import_record["args"]) |
67 |
| - ) |
68 |
| - ) |
69 |
| - |
70 |
| - output.writelines(template_def["body_lines"]) |
71 |
| - |
72 |
| -def generate_instantiations(template, root, templates): |
73 |
| - '''Create a .qll source file for each instantiation of the specified template.''' |
74 |
| - template_def = template["template_def"] |
75 |
| - if "instantiations" in template_def: |
76 |
| - for instantiation in template_def["instantiations"]: |
77 |
| - instantiate_template(template, instantiation, root, templates) |
78 |
| - |
79 |
| -def read_template(template_path, module_name): |
80 |
| - '''Read a .qllt template file from template_path, using module_name as the |
81 |
| - fully qualified name of the module.''' |
82 |
| - with open(template_path) as input: |
83 |
| - in_template = False |
84 |
| - template_text = "" |
85 |
| - template_def = None |
86 |
| - body_lines = [] |
87 |
| - for line in iter(input): |
88 |
| - if in_template: |
89 |
| - if END_TEMPLATE.match(line): |
90 |
| - template_def = json.loads(template_text) |
91 |
| - in_template = False |
92 |
| - else: |
93 |
| - template_text += line |
94 |
| - else: |
95 |
| - if BEGIN_TEMPLATE.match(line) and not template_def: |
96 |
| - in_template = True |
97 |
| - else: |
98 |
| - body_lines.append(line) |
99 |
| - |
100 |
| - if template_def: |
101 |
| - template_def["body_lines"] = body_lines |
102 |
| - |
103 |
| - result = { "name": module_name } |
104 |
| - if template_def: |
105 |
| - result["template_def"] = template_def |
106 |
| - return result |
107 |
| - |
108 |
| -def module_name_from_path_impl(path): |
109 |
| - (head, tail) = os.path.split(path) |
110 |
| - if head == "": |
111 |
| - return tail |
112 |
| - else: |
113 |
| - return module_name_from_path(head) + "." + tail |
114 |
| - |
115 |
| -def module_name_from_path(path): |
116 |
| - '''Compute the fully qualified name of a module from the path of its .qll[t] |
117 |
| - file. The path should be relative to the library root.''' |
118 |
| - (module_root, ext) = os.path.splitext(path) |
119 |
| - return module_name_from_path_impl(module_root) |
120 |
| - |
121 |
| -def main(): |
122 |
| - templates = {} |
123 |
| - |
124 |
| - root = sys.argv[1] |
125 |
| - for template_path in glob.glob(os.path.join(root, "**\\*.qllt"), recursive = True): |
126 |
| - print(template_path) |
127 |
| - module_name = module_name_from_path(os.path.relpath(template_path, root)) |
128 |
| - print(module_name) |
129 |
| - template = read_template(template_path, module_name) |
130 |
| - templates[template["name"]] = template |
131 |
| - |
132 |
| - for name, template in templates.items(): |
133 |
| - if "template_def" in template: |
134 |
| - generate_instantiations(template, root, templates) |
135 |
| - |
136 |
| -if __name__ == "__main__": |
137 |
| - main() |
| 1 | +import sys |
| 2 | +import os.path |
| 3 | +import glob |
| 4 | +import re |
| 5 | +import json |
| 6 | + |
| 7 | +BEGIN_TEMPLATE = re.compile(r"^/\*template\s*$") |
| 8 | +END_TEMPLATE = re.compile(r"^\*/\s*$") |
| 9 | + |
| 10 | +def expand_template_params(args, param_arg_map): |
| 11 | + '''Given a list of template arguments that may reference template parameters |
| 12 | + of the current template, return a new list of template arguments with each |
| 13 | + parameter use replaced with the appropriate fully-qualified argument for |
| 14 | + that parameter.''' |
| 15 | + result = [] |
| 16 | + for arg in args: |
| 17 | + if arg in param_arg_map: |
| 18 | + result.append(param_arg_map[arg]) |
| 19 | + else: |
| 20 | + result.append(arg) |
| 21 | + |
| 22 | + return result |
| 23 | + |
| 24 | +def find_instantiation(module, args, templates): |
| 25 | + '''Given a template module and a set of template arguments, find the module |
| 26 | + name of the instantiation of that module with those arguments.''' |
| 27 | + template = templates[module] |
| 28 | + for instantiation in template["template_def"]["instantiations"]: |
| 29 | + if instantiation["args"] == args: |
| 30 | + return instantiation["name"] |
| 31 | + return None |
| 32 | + |
| 33 | +def instantiate_template(template, instantiation, root, templates): |
| 34 | + '''Create a single instantiation of a template.''' |
| 35 | + template_def = template["template_def"] |
| 36 | + output_components = instantiation["name"].split(".") |
| 37 | + output_path = root |
| 38 | + for component in output_components: |
| 39 | + output_path = os.path.join(output_path, component) |
| 40 | + output_path = output_path + ".qll" |
| 41 | + with open(output_path, "w") as output: |
| 42 | + output.write( |
| 43 | +""" |
| 44 | +/* |
| 45 | + * THIS FILE IS AUTOMATICALLY GENERATED FROM '%s'. |
| 46 | + * DO NOT EDIT MANUALLY. |
| 47 | + */ |
| 48 | +
|
| 49 | +""" % (template["name"].replace(".", "/") + ".qllt") |
| 50 | + ) |
| 51 | + param_arg_map = {} |
| 52 | + for param_index in range(len(template_def["params"])): |
| 53 | + param = template_def["params"][param_index] |
| 54 | + arg = instantiation["args"][param_index] |
| 55 | + output.write("private import %s as %s // Template parameter\n" % (arg, param)) |
| 56 | + param_arg_map[param] = arg |
| 57 | + for import_record in template_def["imports"]: |
| 58 | + if "access" in import_record: |
| 59 | + output.write(import_record["access"] + " ") |
| 60 | + imported_module = find_instantiation(import_record["module"], |
| 61 | + expand_template_params(import_record["args"], param_arg_map), templates) |
| 62 | + output.write("import %s // %s<%s>\n" % |
| 63 | + ( |
| 64 | + imported_module, |
| 65 | + import_record["module"], |
| 66 | + ", ".join(import_record["args"]) |
| 67 | + ) |
| 68 | + ) |
| 69 | + |
| 70 | + output.writelines(template_def["body_lines"]) |
| 71 | + |
| 72 | +def generate_instantiations(template, root, templates): |
| 73 | + '''Create a .qll source file for each instantiation of the specified template.''' |
| 74 | + template_def = template["template_def"] |
| 75 | + if "instantiations" in template_def: |
| 76 | + for instantiation in template_def["instantiations"]: |
| 77 | + instantiate_template(template, instantiation, root, templates) |
| 78 | + |
| 79 | +def read_template(template_path, module_name): |
| 80 | + '''Read a .qllt template file from template_path, using module_name as the |
| 81 | + fully qualified name of the module.''' |
| 82 | + with open(template_path) as input: |
| 83 | + in_template = False |
| 84 | + template_text = "" |
| 85 | + template_def = None |
| 86 | + body_lines = [] |
| 87 | + for line in iter(input): |
| 88 | + if in_template: |
| 89 | + if END_TEMPLATE.match(line): |
| 90 | + template_def = json.loads(template_text) |
| 91 | + in_template = False |
| 92 | + else: |
| 93 | + template_text += line |
| 94 | + else: |
| 95 | + if BEGIN_TEMPLATE.match(line) and not template_def: |
| 96 | + in_template = True |
| 97 | + else: |
| 98 | + body_lines.append(line) |
| 99 | + |
| 100 | + if template_def: |
| 101 | + template_def["body_lines"] = body_lines |
| 102 | + |
| 103 | + result = { "name": module_name } |
| 104 | + if template_def: |
| 105 | + result["template_def"] = template_def |
| 106 | + return result |
| 107 | + |
| 108 | +def module_name_from_path_impl(path): |
| 109 | + (head, tail) = os.path.split(path) |
| 110 | + if head == "": |
| 111 | + return tail |
| 112 | + else: |
| 113 | + return module_name_from_path(head) + "." + tail |
| 114 | + |
| 115 | +def module_name_from_path(path): |
| 116 | + '''Compute the fully qualified name of a module from the path of its .qll[t] |
| 117 | + file. The path should be relative to the library root.''' |
| 118 | + (module_root, ext) = os.path.splitext(path) |
| 119 | + return module_name_from_path_impl(module_root) |
| 120 | + |
| 121 | +def main(): |
| 122 | + templates = {} |
| 123 | + |
| 124 | + root = sys.argv[1] |
| 125 | + for template_path in glob.glob(os.path.join(root, "**\\*.qllt"), recursive = True): |
| 126 | + print(template_path) |
| 127 | + module_name = module_name_from_path(os.path.relpath(template_path, root)) |
| 128 | + print(module_name) |
| 129 | + template = read_template(template_path, module_name) |
| 130 | + templates[template["name"]] = template |
| 131 | + |
| 132 | + for name, template in templates.items(): |
| 133 | + if "template_def" in template: |
| 134 | + generate_instantiations(template, root, templates) |
| 135 | + |
| 136 | +if __name__ == "__main__": |
| 137 | + main() |
0 commit comments