OLD | NEW |
(Empty) | |
| 1 #!/usr/bin/env python |
| 2 |
| 3 import getopt |
| 4 import os |
| 5 import sys |
| 6 |
| 7 from Cheetah.Template import Template |
| 8 from datetime import datetime |
| 9 from idl_option import ParseOptions |
| 10 from idl_parser import IDLParser |
| 11 |
| 12 class APIArgument: |
| 13 def __init__(self, name, type): |
| 14 self.name = name |
| 15 self.type = type |
| 16 |
| 17 def __str__(self): |
| 18 return "%s: %s" % (self.type, self.name) |
| 19 |
| 20 def mapped_type(self): |
| 21 if self.type == "long": |
| 22 return "int" |
| 23 if self.type == "DOMString": |
| 24 return "std::string" |
| 25 if self.type.endswith("Options"): |
| 26 return "ListValue" |
| 27 return self.type |
| 28 |
| 29 def mapped_arg_type(self): |
| 30 if self.type == "long": |
| 31 return "int" |
| 32 if self.type == "DOMString": |
| 33 return "const std::string&" |
| 34 if self.type.endswith("Options"): |
| 35 return "const ListValue&" |
| 36 return self.type |
| 37 |
| 38 class APIFunction: |
| 39 def __init__(self, name, arguments, return_values, family=None, |
| 40 is_experimental=False): |
| 41 self.family = family |
| 42 self.name = name |
| 43 self.arguments = arguments |
| 44 self.return_values = return_values |
| 45 self.is_experimental = is_experimental |
| 46 |
| 47 def class_name(self): |
| 48 return self.family.name + self.name |
| 49 |
| 50 def dotted_name(self): |
| 51 dotted_name = self.family.name.lower() + '.' + self.name.lower() |
| 52 if self.is_experimental: |
| 53 return 'experimental.' + dotted_name |
| 54 else: |
| 55 return dotted_name |
| 56 |
| 57 def __str__(self): |
| 58 s = self.name + ": " |
| 59 for argument in self.arguments: |
| 60 s += str(argument) + ", " |
| 61 s += " <- " |
| 62 for return_value in self.return_values: |
| 63 s += str(return_value) + ", " |
| 64 return s |
| 65 |
| 66 class APIFamily: |
| 67 def __init__(self, name, functions): |
| 68 self.name = name |
| 69 self.functions = functions |
| 70 for f in functions: |
| 71 f.family = self |
| 72 |
| 73 def __str__(self): |
| 74 s = self.name + ": " |
| 75 for function in self.functions: |
| 76 s += str(function) + "; " |
| 77 return s |
| 78 |
| 79 def header_path(self): |
| 80 return "chrome/browser/extensions/api/%(ln)s/%(ln)s_api.h" % { |
| 81 'ln': self.name.lower() } |
| 82 |
| 83 class TemplateHelper: |
| 84 def __init__(self, template, families, input_dir, |
| 85 output_filename, output_dir): |
| 86 self.template = template |
| 87 self.families = families |
| 88 self.dirname = output_dir |
| 89 self.basename = output_filename |
| 90 self.pathname = os.path.join(output_dir, output_filename) |
| 91 |
| 92 self.template.families = self.families |
| 93 self.template.basename = self.basename |
| 94 self.template.dirname = self.dirname |
| 95 self.template.output_file = self.output_file |
| 96 self.template.pathname = self.pathname |
| 97 self.template.year = datetime.today().year |
| 98 |
| 99 if self.basename.endswith(".cc"): |
| 100 self.template.header_pathname = "chrome/%s" % ( |
| 101 self.basename.replace(".cc", ".h")) |
| 102 |
| 103 path_parts = os.path.join(input_dir, |
| 104 output_filename).replace('.', '/').split('/') |
| 105 path_parts_upper = ['CHROME'] |
| 106 for part in path_parts: |
| 107 if len(part.strip()) != 0: |
| 108 path_parts_upper.append(part.upper()) |
| 109 self.template.guard = '_'.join(path_parts_upper) + '_' |
| 110 |
| 111 def output_file(self): |
| 112 self.make_path(self.dirname) |
| 113 f = open(self.pathname, 'w+') |
| 114 f.write(str(self.template)) |
| 115 f.close() |
| 116 |
| 117 def make_path(self, path): |
| 118 try: |
| 119 os.makedirs(path) |
| 120 except OSError, e: |
| 121 if e.errno == 17: |
| 122 pass |
| 123 else: |
| 124 raise e |
| 125 |
| 126 def generate_file(template_filename, families, input_dir, output_dir): |
| 127 output_filename = template_filename.replace(".tmpl", "") |
| 128 template_pathname = os.path.join(input_dir, template_filename) |
| 129 th = TemplateHelper(Template(file=template_pathname), families, |
| 130 input_dir, output_filename, output_dir) |
| 131 th.output_file() |
| 132 |
| 133 def read_idl(idl_filename): |
| 134 f = open(idl_filename, 'r') |
| 135 contents = f.read() |
| 136 f.close() |
| 137 |
| 138 parser = IDLParser() |
| 139 return parser.ParseData(contents, idl_filename) |
| 140 |
| 141 def member_to_function(member): |
| 142 if member.cls != "Member": |
| 143 return None |
| 144 |
| 145 name = member.GetProperty("NAME") |
| 146 arguments = [] |
| 147 for member_part in member.children: |
| 148 if member_part.cls != "Callspec": |
| 149 continue |
| 150 for child in member_part.children: |
| 151 if child.cls == "Param": |
| 152 # The last param is usually a callback, which is implied. |
| 153 if child.GetProperty("NAME") == "callBack": |
| 154 continue |
| 155 arguments.append(APIArgument(child.GetProperty("NAME"), |
| 156 child.GetProperty("TYPEREF"))) |
| 157 return APIFunction(name.capitalize(), arguments, []) |
| 158 |
| 159 def nodes_to_families(nodes): |
| 160 families = [] |
| 161 for node in nodes: |
| 162 namespace = node.GetProperty("NAME") |
| 163 if namespace.startswith("experimental."): |
| 164 is_experimental = True |
| 165 namespace = namespace.replace("experimental.", "") |
| 166 else: |
| 167 is_experimental = False |
| 168 namespace = namespace.capitalize() |
| 169 functions = [] |
| 170 for child in node.children: |
| 171 if child.cls == "Interface": |
| 172 if child.GetProperty("NAME") == "Functions": |
| 173 for member in child.children: |
| 174 function = member_to_function(member) |
| 175 if function is not None: |
| 176 function.is_experimental = is_experimental |
| 177 functions.append(function) |
| 178 families.append(APIFamily(namespace, functions)) |
| 179 return families |
| 180 |
| 181 def main(): |
| 182 try: |
| 183 opts, args = getopt.getopt(sys.argv[1:], "hi:o:d:", |
| 184 ["help", "input=", "output=", "idl="]) |
| 185 except getopt.GetoptError, err: |
| 186 print str(err) |
| 187 usage() |
| 188 sys.exit(2) |
| 189 |
| 190 input_dir = None |
| 191 output_dir = None |
| 192 idl_filename = None |
| 193 |
| 194 verbose = False |
| 195 for o, a in opts: |
| 196 if o in ("-h", "--help"): |
| 197 usage() |
| 198 sys.exit(0) |
| 199 elif o in ("-i", "--input"): |
| 200 input_dir = a |
| 201 elif o in ("-o", "--output"): |
| 202 output_dir = a |
| 203 elif o in ("-d", "--idl"): |
| 204 idl_filename = a |
| 205 else: |
| 206 assert False, "unhandled option: %s" % o |
| 207 |
| 208 if (input_dir is None): |
| 209 print "ERROR: Must specify input_dir." |
| 210 usage() |
| 211 sys.exit(2) |
| 212 |
| 213 if (output_dir is None): |
| 214 print "ERROR: Must specify output_dir." |
| 215 usage() |
| 216 sys.exit(2) |
| 217 |
| 218 if (idl_filename is None): |
| 219 print "ERROR: Must specify idl." |
| 220 usage() |
| 221 sys.exit(2) |
| 222 |
| 223 nodes = read_idl(idl_filename) |
| 224 families = nodes_to_families(nodes) |
| 225 |
| 226 for arg in args: |
| 227 generate_file(arg, families, input_dir, output_dir) |
| 228 |
| 229 sys.exit(0) |
| 230 |
| 231 def usage(): |
| 232 print """ |
| 233 Takes an input directory, an output directory, an IDL, and one or more names of |
| 234 template files in the input directory, and generates files from those templates |
| 235 in the output directory. |
| 236 |
| 237 Usage: apiidlc -i input_directory -o output_directory -d idl_filename |
| 238 [file1.tmpl] [file2.tmpl] ... |
| 239 """ |
| 240 |
| 241 if __name__ == "__main__": |
| 242 main() |
OLD | NEW |