Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(483)

Side by Side Diff: content/browser/devtools/protocol/devtools_protocol_handler_generator.py

Issue 508973003: DevTools: Protocol handler generator for content (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 6 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 #!/usr/bin/env python
2 # Copyright 2014 The Chromium Authors. All rights reserved.
3 # Use of this source code is governed by a BSD-style license that can be
4 # found in the LICENSE file.
5
6 import sys
7 import string
8 import json
9
10 input_json_path = sys.argv[1]
11 output_h_path = sys.argv[2]
12 output_cc_path = sys.argv[3]
13
14 header = """\
15 // Copyright 2014 The Chromium Authors. All rights reserved.
16 // Use of this source code is governed by a BSD-style license that can be
17 // found in the LICENSE file.
18
19 // THIS FILE IS AUTOGENERATED. DO NOT EDIT.
20 // Generated by
21 // content/public/browser/devtools_protocol_handler_generator.py from
22 // third_party/WebKit/Source/devtools/protocol.json
23 """
24
25 template_h = string.Template(header + """\
26
27 #ifndef CONTENT_BROWSER_DEVTOOLS_DEVTOOLS_PROTOCOL_HANDLER_H_
28 #define CONTENT_BROWSER_DEVTOOLS_DEVTOOLS_PROTOCOL_HANDLER_H_
29
30 #include "content/browser/devtools/devtools_protocol.h"
31 #include "content/browser/devtools/protocol/devtools_protocol_frontend.h"
32
33 namespace content {
34
35 class RenderViewHostImpl;
36 class DevToolsProtocolHandlerImpl;
37
38 namespace devtools {
39
40 ${types}\
41
42 ${handlers}\
43
44 ${frontends}\
45
46 } // namespace devtools
47
48 class DevToolsProtocolHandlerImpl : public DevToolsProtocol::Handler {
49 public:
50 typedef DevToolsProtocolFrontend::Response Response;
51 typedef DevToolsProtocolFrontend::ResponseStatus ResponseStatus;
52
53 DevToolsProtocolHandlerImpl();
54 virtual ~DevToolsProtocolHandlerImpl();
55 void OnClientDetached();
56 void SetRenderViewHost(RenderViewHostImpl* host);
57
58 private:
59 ${friends}\
60
61 ${callbacks}\
62
63 ${to_value}\
64
65 ${fields}\
66 };
67
68 } // namespace content
69
70 #endif // CONTENT_BROWSER_DEVTOOLS_DEVTOOLS_PROTOCOL_HANDLER_H_
71 """)
72
73 tmpl_typedef = string.Template("""\
74 namespace ${domain} {
75 typedef ${param_type} ${declared_name};
76 }
77 """)
78
79 tmpl_struct = string.Template("""\
80 namespace ${domain} {
81 class ${declared_name} {
82 public:
83 ${declared_name}();
84
85 ${setters}\
86
87 private:
88 friend class ::content::DevToolsProtocolHandlerImpl;
89
90 ${fields}\
91 };
92 } // namespace ${domain}
93 """)
94
95 tmpl_struct_setter = string.Template("""\
96 void set_${param}(${pass_type} ${param});
97 """)
98
99 tmpl_struct_field = string.Template("""\
100 ${param_type} ${param}_;
101 bool has_${param}_;
102 """)
103
104 tmpl_handler = string.Template("""\
105 namespace ${domain} {
106 class Handler;
107 }
108 """)
109
110 tmpl_frontend = string.Template("""\
111 namespace ${domain} {
112 class Frontend : public DevToolsProtocolFrontend {
113 public:
114 Frontend(const EventCallback& event_callback);
115 virtual ~Frontend();
116
117 ${events}\
118 };
119 } // namespace ${domain}
120 """)
121
122 tmpl_event = string.Template("""\
123 void ${Event}($params);
124 """)
125
126 tmpl_event_param = string.Template("${pass_type} ${param}")
127
128 tmpl_friend = string.Template("""\
129 friend class devtools::${domain}::Frontend;
130 """)
131
132 tmpl_to_value = string.Template("""\
133 static base::Value* ToValue(${pass_type} src);
134 """)
135
136 tmpl_callback = string.Template("""\
137 scoped_refptr<DevToolsProtocol::Response> On${Domain}${Command}(
138 scoped_refptr<DevToolsProtocol::Command> command);
139 """)
140
141 tmpl_field = string.Template("""\
142 scoped_ptr<devtools::${domain}::Handler> ${domain}_handler_;
143 """)
144
145 template_cc = string.Template(header + """\
146
147 #include "content/browser/devtools/protocol/devtools_protocol_handler.h"
148
149 #include "base/bind.h"
150 ${includes}\
151
152 namespace content {
153
154 DevToolsProtocolHandlerImpl::DevToolsProtocolHandlerImpl() {
155 ${initializations}\
156 }
157
158 DevToolsProtocolHandlerImpl::~DevToolsProtocolHandlerImpl() {
159 }
160
161 void DevToolsProtocolHandlerImpl::OnClientDetached() {
162 ${client_detached}\
163 }
164
165 void DevToolsProtocolHandlerImpl::SetRenderViewHost(RenderViewHostImpl* host) {
166 ${set_rvh}\
167 }
168
169 ${callbacks}\
170
171 ${to_value}\
172
173 namespace devtools {
174
175 ${types}\
176
177 ${frontends}\
178
179 } // namespace devtools
180
181 } // namespace content
182 """)
183
184 tmpl_include = string.Template("""\
185 #include "content/browser/devtools/protocol/${domain}_domain_handler.h"
186 """)
187
188 tmpl_struct_impl = string.Template("""\
189 namespace ${domain} {
190
191 ${declared_name}::${declared_name}()
192 : ${fields} {
193 }
194
195 ${setters}\
196
197 } // namespace ${domain}
198 """)
199
200 tmpl_struct_field_init = string.Template("has_${param}_(false)")
201
202
203 tmpl_struct_setter_impl = string.Template("""\
204 void ${declared_name}::set_${param}(${pass_type} ${param}) {
205 ${param}_ = ${param};
206 has_${param}_ = true;
207 }
208 """)
209
210
211 tmpl_frontend_impl = string.Template("""\
212 namespace ${domain} {
213
214 Frontend::Frontend(const EventCallback& event_callback)
215 : DevToolsProtocolFrontend(event_callback) {
216 }
217
218 Frontend::~Frontend() {
219 }
220
221 ${events}\
222
223 }
224 """)
225
226 tmpl_event_impl = string.Template("""\
227 void Frontend::${Event}(${params}) {
228 base::DictionaryValue* dict = new base::DictionaryValue();
229 ${wrap}\
230 SendNotification("${Domain}.${event}", dict);
231 }
232 """)
233
234 tmpl_register = string.Template("""\
235 RegisterCommandHandler(
236 "${Domain}.${command}",
237 base::Bind(&DevToolsProtocolHandlerImpl::On${Domain}${Command},
238 base::Unretained(this)));
239 """)
240
241 tmpl_init_handler = string.Template("""\
242 ${domain}_handler_.reset(new devtools::${domain}::Handler());
243 """)
244
245 tmpl_init_frontend = string.Template("""\
246 ${domain}_handler_->SetFrontend(make_scoped_ptr(
247 new devtools::${domain}::Frontend(
248 base::Bind(&DevToolsProtocolHandlerImpl::SendNotification,
249 base::Unretained(this)))));
250 """)
251
252 tmpl_client_detached = string.Template("""\
253 ${domain}_handler_->OnClientDetached();
254 """)
255
256 tmpl_set_rvh = string.Template("""\
257 ${domain}_handler_->SetRenderViewHost(host);
258 """)
259
260 tmpl_to_value_impl = string.Template("""\
261 // static
262 base::Value* DevToolsProtocolHandlerImpl::ToValue(${pass_type} src) {
263 base::DictionaryValue* dict = new base::DictionaryValue();
264 ${dchecks}\
265 ${wrap}\
266 return dict;
267 }
268 """)
269
270 tmpl_dcheck = string.Template("""\
271 DCHECK(src.has_${param}_);
272 """)
273
274 tmpl_callback_impl = string.Template("""\
275 scoped_refptr<DevToolsProtocol::Response>
276 DevToolsProtocolHandlerImpl::On${Domain}${Command}(
277 scoped_refptr<DevToolsProtocol::Command> command) {
278 ${prep}\
279 Response response = ${domain}_handler_->${Command}(${args});
280 switch (response.status_) {
281 case ResponseStatus::RESPONSE_STATUS_FALLTHROUGH:
282 return NULL;
283 case ResponseStatus::RESPONSE_STATUS_OK:
284 break;
285 case ResponseStatus::RESPONSE_STATUS_INVALID_PARAMS:
286 return command->InvalidParamResponse(response.message_);
287 case ResponseStatus::RESPONSE_STATUS_INTERNAL_ERROR:
288 return command->InternalErrorResponse(response.message_);
289 case ResponseStatus::RESPONSE_STATUS_SERVER_ERROR:
290 return command->ServerErrorResponse(response.message_);
291 }
292 base::DictionaryValue* dict = new base::DictionaryValue();
293 ${wrap}\
294 return command->SuccessResponse(dict);
295 }
296 """)
297
298 params_prep = """\
299 base::DictionaryValue* params = command->params();
300 if (!params)
301 return command->NoSuchMethodErrorResponse();
302 """
303
304 tmpl_prep_req = string.Template("""\
305 ${param_type} in_${param}${init};
306 if (!params->Get${Type}("${proto_param}", &in_${param}))
307 return command->InvalidParamResponse("${proto_param}");
308 """)
309
310 tmpl_prep_req_list = string.Template("""\
311 base::ListValue* list_${param} = NULL;
312 if (!params->GetList("${proto_param}", &list_${param}))
313 return command->InvalidParamResponse("${proto_param}");
314 ${param_type} in_${param};
315 for (base::ListValue::const_iterator it = list_${param}->begin();
316 it != list_${param}->end(); ++it) {
317 ${item_type} item${item_init};
318 if (!(*it)->GetAs${ItemType}(&item))
319 return command->InvalidParamResponse("${proto_param}");
320 in_${param}.push_back(item);
321 }
322 """)
323
324 tmpl_prep_opt = string.Template("""\
325 ${param_type} in_${param}${init};
326 bool ${param}_found = params->Get${Type}("${proto_param}", &in_${param});
327 """)
328
329 tmpl_prep_output = string.Template("""\
330 ${param_type} out_${param}${init};
331 """)
332
333 tmpl_arg_req = string.Template("in_${param}")
334
335 tmpl_arg_opt = string.Template("${param}_found ? &in_${param} : NULL")
336
337 tmpl_arg_output = string.Template("&out_${param}")
338
339 tmpl_wrap = string.Template("""\
340 dict->Set${Type}("${proto_param}", ${var_name});
341 """)
342
343 tmpl_wrap_dict = string.Template("""\
344 dict->Set("${proto_param}",
345 DevToolsProtocolHandlerImpl::ToValue(${var_name}));
346 """)
347
348 tmpl_wrap_obj = string.Template("""\
349 dict->Set("${proto_param}", ${var_name});
350 """)
351
352 tmpl_wrap_list = string.Template("""\
353 base::ListValue* list_${param} = new base::ListValue();
354 for (${param_type}::const_iterator it = ${var_name}.begin();
355 it != ${var_name}.end(); ++it) {
356 ${append}\
357 }
358 dict->Set("${proto_param}", list_${param});
359 """)
360
361 tmpl_append = string.Template("""\
362 list_${param}->Append${Type}(*it);
363 """)
364
365 tmpl_append_dict = string.Template("""\
366 list_${param}->Append(DevToolsProtocolHandlerImpl::ToValue(*it));
367 """)
368
369 tmpl_append_obj = string.Template("""\
370 list_${param}->Append(*it);
371 """)
372
373 tmpl_wrap_opt = string.Template("""\
374 if (${cond_name})
375 dict->Set${Type}("${proto_param}", ${var_name});
376 """)
377
378 tmpl_typename = string.Template("devtools::${domain}::${declared_name}")
379
380 def Capitalize(s):
381 return s[:1].upper() + s[1:]
382
383 def Decapitalize(s):
384 return s.lower()
385
386 def Uncamelcase(s):
387 result = ""
388 for i, c in enumerate(s):
389 if c.isupper():
390 if (i < len(s)-1) and s[i+1].islower() or (i > 0) and s[i-1].islower():
391 result += "_"
392 result += c.lower()
393 else:
394 result += c
395 return result
396
397 types = {}
398 json_api = json.loads(open(input_json_path, "r").read())
399 type_decls = []
400 type_impls = []
401 to_value = []
402 to_value_impls = []
403
404 for json_domain in json_api["domains"]:
405 if "types" in json_domain:
406 for json_type in json_domain["types"]:
407 types["%s.%s" % (json_domain["domain"], json_type["id"])] = json_type
408
409 def DeclareStruct(json, mapping):
410 setters = []
411 fields = []
412 fields_init = []
413 setter_impls = []
414 dchecks = []
415 wrap = []
416 if "properties" in json:
417 for json_prop in json["properties"]:
418 prop_map = mapping.copy()
419 prop_map.pop("append", None)
420 prop_map.pop("wrap", None)
421 prop_map.pop("prep_req", None)
422 prop_map.pop("pass_type", None)
423 prop_map["proto_param"] = json_prop["name"]
424 prop_map["param"] = Uncamelcase(json_prop["name"])
425 prop_map["var_name"] = "src.%s_" % prop_map["param"]
426 ResolveType(json_prop, prop_map)
427 prop_map["declared_name"] = mapping["declared_name"]
428 setters.append(tmpl_struct_setter.substitute(prop_map))
429 fields.append(tmpl_struct_field.substitute(prop_map))
430 fields_init.append(tmpl_struct_field_init.substitute(prop_map))
431 setter_impls.append(tmpl_struct_setter_impl.substitute(prop_map))
432 if json_prop.get("optional"):
433 wrap.append(tmpl_wrap_opt.substitute(prop_map,
434 cond_name = "src.has_%s_" % prop_map["param"]))
435 else:
436 dchecks.append(tmpl_dcheck.substitute(prop_map));
437 wrap.append(prop_map["wrap"])
438 type_decls.append(tmpl_struct.substitute(mapping,
439 setters = "".join(setters),
440 fields = "".join(fields)))
441 type_impls.append(tmpl_struct_impl.substitute(mapping,
442 fields = ",\n ".join(fields_init),
443 setters = "\n".join(setter_impls)))
444 to_value.append(tmpl_to_value.substitute(mapping))
445 to_value_impls.append(tmpl_to_value_impl.substitute(mapping,
446 dchecks = "".join(dchecks),
447 wrap = "".join(wrap)))
448
449 def ResolveType(json, mapping):
450 mapping["init"] = ""
451 if "$ref" in json:
452 dot_pos = json["$ref"].find(".")
453 if dot_pos == -1:
454 domain_name = mapping["Domain"]
455 type_name = json["$ref"]
456 else:
457 domain_name = json["$ref"][:dot_pos]
458 type_name = json["$ref"][dot_pos + 1:]
459 json_type = types["%s.%s" % (domain_name, type_name)]
460 mapping["declared_name"] = Capitalize(type_name)
461 mapping["param_type"] = tmpl_typename.substitute(mapping)
462 ResolveType(json_type, mapping)
463 if not "___mark" in json_type:
464 json_type["___mark"] = True;
465 if (json_type.get("type") == "object") and ("properties" in json_type):
466 DeclareStruct(json_type, mapping)
467 else:
468 type_decls.append(tmpl_typedef.substitute(mapping))
469 mapping["param_type"] = tmpl_typename.substitute(mapping)
470 elif "type" in json:
471 json_type = json["type"]
472 if json_type == "array":
473 items_map = mapping.copy()
474 ResolveType(json["items"], items_map)
475 mapping["param_type"] = "std::vector<%s>" % items_map["param_type"]
476 mapping["Type"] = "List"
477 mapping["wrap"] = tmpl_wrap_list.substitute(mapping,
478 append = items_map["append"])
479 mapping["prep_req"] = tmpl_prep_req_list.substitute(mapping,
480 item_type = items_map["param_type"],
481 item_init = items_map["init"],
482 ItemType = items_map["Type"])
483 elif json_type == "boolean":
484 mapping["param_type"] = "bool"
485 mapping["Type"] = "Boolean"
486 mapping["init"] = " = false"
487 elif json_type == "integer":
488 mapping["param_type"] = "int"
489 mapping["Type"] = "Integer"
490 mapping["init"] = " = 0"
491 elif json_type == "number":
492 mapping["param_type"] = "double"
493 mapping["Type"] = "Double"
494 mapping["init"] = " = 0.0"
495 elif json_type == "object":
496 mapping["Type"] = "Dictionary"
497 if "properties" in json:
498 if not "declared_name" in mapping:
499 if "Command" in mapping:
500 subdomain = mapping["Command"]
501 elif "Event" in mapping:
502 subdomain = mapping["Event"]
503 else:
504 raise Exception("Unrecognized subdomain")
505 mapping["declared_name"] = ("%s%s" %
506 (subdomain, Capitalize(mapping["proto_param"])))
507 mapping["param_type"] = tmpl_typename.substitute(mapping)
508 DeclareStruct(json_type, mapping)
509 mapping["append"] = tmpl_append_dict.substitute(mapping)
510 mapping["wrap"] = tmpl_wrap_dict.substitute(mapping)
511 mapping["pass_type"] = "const %s&" % mapping["param_type"]
512 else:
513 mapping["param_type"] = "base::DictionaryValue*"
514 mapping["append"] = tmpl_append_obj.substitute(mapping)
515 mapping["wrap"] = tmpl_wrap_obj.substitute(mapping)
516 elif json_type == "string":
517 mapping["param_type"] = "std::string"
518 mapping["pass_type"] = "const std::string&"
519 mapping["Type"] = "String"
520 else:
521 raise Exception("Unknown type: %s" % json_type)
522 else:
523 raise Exception("Unknown type at %s.%s %s" %
524 (mapping["Domain"], mapping["command"], mapping["proto_param"]))
525 if not ("wrap" in mapping):
526 mapping["wrap"] = tmpl_wrap.substitute(mapping)
527 if not ("append" in mapping):
528 mapping["append"] = tmpl_append.substitute(mapping)
529 if not ("prep_req" in mapping):
530 mapping["prep_req"] = tmpl_prep_req.substitute(mapping)
531 if not ("pass_type" in mapping):
532 mapping["pass_type"] = mapping["param_type"]
533
534 handlers = []
535 frontends = []
536 friends = []
537 callbacks = []
538 fields = []
539
540 includes = []
541 initializations = []
542 client_detached = []
543 set_rvh = []
544 callback_impls = []
545 frontend_impls = []
546
547 for json_domain in json_api["domains"]:
548 domain_map = {}
549 domain_map["Domain"] = json_domain["domain"]
550 domain_map["domain"] = Decapitalize(json_domain["domain"])
551
552 events = []
553 event_impls = []
554 domain_has_commands = False
555 domain_has_events = False
556
557 if "commands" in json_domain:
558 for json_command in json_domain["commands"]:
559 if (not ("handlers" in json_command) or
560 not ("browser" in json_command["handlers"])):
561 continue
562 domain_has_commands = True
563
564 command_map = domain_map.copy()
565 command_map["command"] = json_command["name"]
566 command_map["Command"] = Capitalize(json_command["name"])
567
568 prep = []
569 args = []
570 wrap = []
571
572 if "parameters" in json_command:
573 for json_param in json_command["parameters"]:
574 param_map = command_map.copy()
575 param_map["proto_param"] = json_param["name"]
576 param_map["param"] = Uncamelcase(json_param["name"])
577 param_map["var_name"] = "in_%s" % param_map["param"]
578
579 ResolveType(json_param, param_map)
580 if len(prep) == 0:
581 prep.append(params_prep)
582 if json_param.get("optional"):
583 if param_map["Type"] in ["List", "Dictionary"]:
584 raise Exception(
585 "Optional array and object parameters are not implemented")
586 prep.append(tmpl_prep_opt.substitute(param_map))
587 args.append(tmpl_arg_opt.substitute(param_map))
588 else:
589 prep.append(param_map["prep_req"])
590 args.append(tmpl_arg_req.substitute(param_map))
591
592 if "returns" in json_command:
593 for json_param in json_command["returns"]:
594 param_map = command_map.copy()
595 param_map["proto_param"] = json_param["name"]
596 param_map["param"] = Uncamelcase(json_param["name"])
597 param_map["var_name"] = "out_%s" % param_map["param"]
598
599 if json_param.get("optional"):
dgozman 2014/09/10 13:01:20 I think we should have support for this before lan
vkuzkokov 2014/09/11 12:53:03 They are not used in protocol. Even if I implement
600 raise Exception("Optional return values are not implemented")
601 ResolveType(json_param, param_map)
602 prep.append(tmpl_prep_output.substitute(param_map))
603 args.append(tmpl_arg_output.substitute(param_map))
604 wrap.append(param_map["wrap"])
605
606 initializations.append(tmpl_register.substitute(command_map))
607 callbacks.append(tmpl_callback.substitute(command_map))
608 callback_impls.append(tmpl_callback_impl.substitute(command_map,
609 prep = "".join(prep),
610 args = ", ".join(args),
611 wrap = "".join(wrap)))
612
613 if "events" in json_domain:
614 for json_event in json_domain["events"]:
615 if (not ("handlers" in json_event) or
616 not ("browser" in json_event["handlers"])):
617 continue
618 domain_has_events = True
619
620 event_map = domain_map.copy()
621 event_map["event"] = json_event["name"]
622 event_map["Event"] = Capitalize(json_event["name"])
623
624 params = []
625 wrap = []
626
627 if "parameters" in json_event:
628 for json_param in json_event["parameters"]:
629 param_map = event_map.copy()
630 param_map["proto_param"] = json_param["name"]
631 param_map["param"] = Uncamelcase(json_param["name"])
632 param_map["var_name"] = param_map["param"]
633
634 if json_param.get("optional"):
dgozman 2014/09/10 13:01:20 ditto
vkuzkokov 2014/09/11 12:53:03 ditto
635 raise Exception("Optional event params are not implemented")
636 ResolveType(json_param, param_map)
637 params.append(tmpl_event_param.substitute(param_map))
638 wrap.append(param_map["wrap"])
639
640 event_map["params"] = ", ".join(params)
641 events.append(tmpl_event.substitute(event_map))
642 event_impls.append(tmpl_event_impl.substitute(event_map,
643 wrap = "".join(wrap)))
644
645 if not (domain_has_commands or domain_has_events):
646 continue
647 handlers.append(tmpl_handler.substitute(domain_map))
648 fields.append(tmpl_field.substitute(domain_map))
649 includes.append(tmpl_include.substitute(domain_map))
650 initializations.append(tmpl_init_handler.substitute(domain_map))
651 client_detached.append(tmpl_client_detached.substitute(domain_map))
652 set_rvh.append(tmpl_set_rvh.substitute(domain_map))
653 if domain_has_events:
654 frontends.append(tmpl_frontend.substitute(domain_map,
655 events = "".join(events)))
656 friends.append(tmpl_friend.substitute(domain_map))
657 initializations.append(tmpl_init_frontend.substitute(domain_map))
658 frontend_impls.append(tmpl_frontend_impl.substitute(domain_map,
659 events = "\n".join(event_impls)))
660
661 output_h_file = open(output_h_path, "w")
662 output_cc_file = open(output_cc_path, "w")
663
664 output_h_file.write(template_h.substitute({},
665 types = "\n".join(type_decls),
666 handlers = "".join(handlers),
667 friends = "".join(friends),
668 callbacks = "".join(callbacks),
669 to_value = "".join(to_value),
670 fields = "".join(fields),
671 frontends = "\n".join(frontends)))
672
673 output_cc_file.write(template_cc.substitute({},
674 includes = "".join(includes),
675 initializations = "".join(initializations),
676 client_detached = "".join(client_detached),
677 set_rvh = "".join(set_rvh),
678 callbacks = "\n".join(callback_impls),
679 to_value = "\n".join(to_value_impls),
680 types = "\n".join(type_impls),
681 frontends = "\n".join(frontend_impls)))
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698