OLD | NEW |
---|---|
(Empty) | |
1 #!/usr/bin/env python | |
2 # | |
3 # Copyright 2013 The Chromium Authors. All rights reserved. | |
Yaron
2014/08/20 05:52:02
2014
mkosiba (inactive)
2014/09/02 16:00:57
Done.
| |
4 # Use of this source code is governed by a BSD-style license that can be | |
Yaron
2014/08/20 05:52:02
Please add tests.
mkosiba (inactive)
2014/09/02 16:00:57
Done.
| |
5 # found in the LICENSE file. | |
6 | |
7 import collections | |
8 import re | |
9 import optparse | |
10 import os | |
11 from string import Template | |
12 import sys | |
13 | |
14 from util import build_utils | |
15 | |
16 def GetScriptName(): | |
17 script_components = os.path.abspath(sys.argv[0]).split(os.path.sep) | |
18 build_index = script_components.index('build') | |
19 return os.sep.join(script_components[build_index:]) | |
20 | |
21 def DoGenerate(options, path): | |
22 enum_entries = DoParseHeaderFile(path) | |
23 build_utils.MakeDirectory(os.path.dirname(options.output)) | |
24 DoWriteOutput(options, enum_entries) | |
25 | |
26 def DoParseHeaderFile(path): | |
27 with open(path) as f: | |
28 lines = f.readlines() | |
29 | |
30 single_line_comment_re = re.compile(r'\s*//') | |
31 multi_line_comment_start_re = re.compile(r'\s*/\*') | |
32 enum_start_re = re.compile(r'^\s*enum\s+(\w+)\s+{\s*$') | |
33 enum_line_re = re.compile(r'^\s*(\w+)(\s*\=\s*([^,]+))?,\s*$') | |
34 enum_end_re = re.compile(r'^\s*}\s*;\s*$') | |
35 | |
36 in_enum = False | |
37 enum_name = None | |
38 enum_entries = collections.OrderedDict() | |
39 | |
40 for line in lines: | |
41 if not in_enum: | |
42 enum_start = enum_start_re.match(line) | |
43 if enum_start: | |
44 if enum_name: | |
45 raise Exception('Only one enum per header file is supported.') | |
Yaron
2014/08/20 05:52:02
Are there really no examples of this?
mkosiba (inactive)
2014/09/02 16:00:57
Done.
| |
46 enum_name = enum_start.groups()[0] | |
47 in_enum = True | |
48 else: | |
49 | |
50 if single_line_comment_re.match(line): | |
51 continue | |
52 if multi_line_comment_start_re.match(line): | |
53 raise Exception('Multi-line comments are not supported.') | |
54 enum_end = enum_end_re.match(line) | |
55 enum_entry = enum_line_re.match(line) | |
56 if enum_end: | |
57 in_enum = False | |
58 if enum_entry: | |
59 enum_key = enum_entry.groups()[0] | |
60 enum_value = enum_entry.groups()[2] | |
61 if enum_key in enum_entries: | |
62 raise Exception('Multiple definitions of key %s found.' % enum_key) | |
63 enum_entries[enum_key] = enum_value | |
64 | |
65 all_entries_assigned = all(enum_entries.values()) | |
66 any_entries_assigned = any(enum_entries.values()) | |
67 if any_entries_assigned and not all_entries_assigned: | |
68 raise Exception('You either need to assign a value to all or none of the ' | |
69 'enum values.') | |
70 | |
71 if not any_entries_assigned: | |
72 index = 0 | |
73 for key in enum_entries.iterkeys(): | |
74 enum_entries[key] = index | |
75 index = index + 1 | |
76 | |
77 return enum_entries | |
78 | |
79 | |
80 def DoWriteOutput(options, enum_entries): | |
81 template = Template(""" | |
82 // Copyright 2014 The Chromium Authors. All rights reserved. | |
83 // Use of this source code is governed by a BSD-style license that can be | |
84 // found in the LICENSE file. | |
85 | |
86 // This file is autogenerated by | |
87 // ${SCRIPT_NAME} | |
88 // For | |
89 // ${PACKAGE}.${CLASS_NAME} | |
90 | |
91 package ${PACKAGE}; | |
92 | |
93 public class ${CLASS_NAME} { | |
94 ${ENUM_ENTRIES} | |
95 } | |
96 """) | |
97 | |
98 enum_template = Template(" public final int ${NAME} = ${VALUE},") | |
99 enum_entries_string = [] | |
100 for enum_name, enum_value in enum_entries.iteritems(): | |
101 values = { | |
102 'NAME': enum_name, | |
103 'VALUE': enum_value, | |
104 } | |
105 enum_entries_string.append(enum_template.substitute(values)) | |
106 enum_entries_string = "\n".join(enum_entries_string) | |
107 | |
108 values = { | |
109 'SCRIPT_NAME': GetScriptName(), | |
110 'PACKAGE': options.package.replace('/', '.'), | |
111 'CLASS_NAME': options.class_name, | |
112 'ENUM_ENTRIES': enum_entries_string, | |
113 } | |
114 | |
115 with open(options.output, "w") as out_file: | |
116 out_file.write(template.substitute(values)) | |
117 | |
118 | |
119 def main(): | |
120 parser = optparse.OptionParser() | |
121 build_utils.AddDepfileOption(parser) | |
122 | |
123 parser.add_option('--output', help='Path for generated file.') | |
124 parser.add_option('--package', help='Package name.') | |
125 parser.add_option('--class_name', help='Class name.') | |
126 parser.add_option('--stamp', help='Path to touch on success.') | |
127 parser.add_option('--defines', help='Pre-defines macros', action='append') | |
128 | |
129 options, args = parser.parse_args() | |
130 | |
131 DoGenerate(options, args[0]) | |
132 | |
133 if options.depfile: | |
134 build_utils.WriteDepfile( | |
135 options.depfile, | |
136 build_utils.GetPythonDependencies()) | |
137 | |
138 if options.stamp: | |
Yaron
2014/08/20 05:52:02
We have a definite output file. Why is a stamp nec
mkosiba (inactive)
2014/09/02 16:00:57
Done.
| |
139 build_utils.Touch(options.stamp) | |
140 | |
141 | |
142 if __name__ == '__main__': | |
143 sys.exit(main()) | |
OLD | NEW |