DevTools: migrate remote debugging protocol generators to jinja2.

BUG=580337

Review URL: https://codereview.chromium.org/1702673002

Cr-Original-Commit-Position: refs/heads/master@{#376929}
Cr-Mirrored-From: https://chromium.googlesource.com/chromium/src
Cr-Mirrored-Commit: 10924eea919977e800165ab7e10adaa7b495a65f
diff --git a/CodeGenerator.py b/CodeGenerator.py
old mode 100755
new mode 100644
index c8fbfb3..e85a96d
--- a/CodeGenerator.py
+++ b/CodeGenerator.py
@@ -1,32 +1,6 @@
-#!/usr/bin/env python
-# Copyright (c) 2011 Google Inc. All rights reserved.
-# Copyright (c) 2012 Intel Corporation. All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-#     * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-#     * Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-#     * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# Copyright 2016 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
 
 import os.path
 import sys
@@ -38,20 +12,28 @@
 except ImportError:
     import simplejson as json
 
-import CodeGeneratorStrings
+# Path handling for libraries and templates
+# Paths have to be normalized because Jinja uses the exact template path to
+# determine the hash used in the cache filename, and we need a pre-caching step
+# to be concurrency-safe. Use absolute path because __file__ is absolute if
+# module is imported, and relative if executed directly.
+# If paths differ between pre-caching and individual file compilation, the cache
+# is regenerated, which causes a race condition and breaks concurrent build,
+# since some compile processes will try to read the partially written cache.
+module_path, module_filename = os.path.split(os.path.realpath(__file__))
+templates_dir = module_path
+third_party_dir = os.path.normpath(os.path.join(
+    module_path, os.pardir, os.pardir, os.pardir, os.pardir))
 
-# Manually-filled map of type name replacements.
-TYPE_NAME_FIX_MAP = {
-    "RGBA": "Rgba",  # RGBA is reported to be conflicting with a define name in Windows CE.
-    "": "Empty",
-}
-
-
-TYPES_WITH_RUNTIME_CAST_SET = frozenset(["Runtime.RemoteObject", "Runtime.PropertyDescriptor", "Runtime.InternalPropertyDescriptor",
-                                         "Debugger.FunctionDetails", "Debugger.GeneratorObjectDetails", "Debugger.CollectionEntry", "Debugger.CallFrame", "Debugger.Location"])
+# jinja2 is in chromium's third_party directory.
+# Insert at 1 so at front to override system libraries, and
+# after path[0] == invoking script dir
+sys.path.insert(1, third_party_dir)
+import jinja2
 
 cmdline_parser = optparse.OptionParser()
 cmdline_parser.add_option("--output_dir")
+cmdline_parser.add_option("--template_dir")
 
 try:
     arg_options, arg_values = cmdline_parser.parse_args()
@@ -68,1999 +50,227 @@
     sys.stderr.write("Usage: <script> --output_dir <output_dir> protocol.json\n")
     exit(1)
 
-
-# FIXME: move this methods under Capitalizer class below and remove duplications.
-def dash_to_camelcase(word):
-    return ''.join(x.capitalize() or '-' for x in word.split('-'))
-
-
-def fix_camel_case(name):
-    refined = re.sub(r'-(\w)', lambda pat: pat.group(1).upper(), name)
-    refined = to_title_case(refined)
-    return re.sub(r'(?i)HTML|XML|WML|API', lambda pat: pat.group(0).upper(), refined)
+input_file = open(input_json_filename, "r")
+json_string = input_file.read()
+json_api = json.loads(json_string)
 
 
 def to_title_case(name):
     return name[:1].upper() + name[1:]
 
 
-class Capitalizer:
-    @staticmethod
-    def lower_camel_case_to_upper(str):
-        if len(str) > 0 and str[0].islower():
-            str = str[0].upper() + str[1:]
-        return str
+def dash_to_camelcase(word):
+    return ''.join(to_title_case(x) or '-' for x in word.split('-'))
 
-    @staticmethod
-    def upper_camel_case_to_lower(str):
-        pos = 0
-        while pos < len(str) and str[pos].isupper():
-            pos += 1
-        if pos == 0:
-            return str
-        if pos == 1:
-            return str[0].lower() + str[1:]
-        if pos < len(str):
-            pos -= 1
-        possible_abbreviation = str[0:pos]
-        if possible_abbreviation not in Capitalizer.ABBREVIATION:
-            raise Exception("Unknown abbreviation %s" % possible_abbreviation)
-        str = possible_abbreviation.lower() + str[pos:]
-        return str
 
-    ABBREVIATION = frozenset(["XHR", "DOM", "CSS", "IO"])
-
-VALIDATOR_IFDEF_NAME = "ENABLE(ASSERT)"
-
-
-class DomainNameFixes:
-    @staticmethod
-    def get_fixed_data(domain_name):
-        return Capitalizer.upper_camel_case_to_lower(domain_name) + "Agent"
-
-class RawTypes(object):
-    @staticmethod
-    def get(json_type):
-        if json_type == "boolean":
-            return RawTypes.Bool
-        elif json_type == "string":
-            return RawTypes.String
-        elif json_type == "array":
-            return RawTypes.Array
-        elif json_type == "object":
-            return RawTypes.Object
-        elif json_type == "integer":
-            return RawTypes.Int
-        elif json_type == "number":
-            return RawTypes.Number
-        elif json_type == "any":
-            return RawTypes.Any
-        else:
-            raise Exception("Unknown type: %s" % json_type)
-
-    class BaseType(object):
-        @classmethod
-        def get_raw_validator_call_text(cls):
-            return "RuntimeCastHelper::assertType<JSONValue::Type%s>" % cls.get_getter_name()
-
-        @staticmethod
-        def get_getter_name():
-            raise Exception("Unsupported")
-
-    class String(BaseType):
-        @staticmethod
-        def get_getter_name():
-            return "String"
-
-        get_setter_name = get_getter_name
-
-        @staticmethod
-        def get_constructor_pattern():
-            return "InspectorString::create(%s)"
-
-        @staticmethod
-        def is_heavy_value():
-            return True
-
-        @staticmethod
-        def get_array_item_raw_c_type_text():
-            return "String"
-
-        @staticmethod
-        def get_raw_type_model():
-            return TypeModel.String
-
-    class Int(BaseType):
-        @staticmethod
-        def get_getter_name():
-            return "Int"
-
-        @staticmethod
-        def get_setter_name():
-            return "Number"
-
-        @staticmethod
-        def get_constructor_pattern():
-            return "InspectorBasicValue::create(%s)"
-
-        @classmethod
-        def get_raw_validator_call_text(cls):
-            return "RuntimeCastHelper::assertInt"
-
-        @staticmethod
-        def is_heavy_value():
-            return False
-
-        @staticmethod
-        def get_array_item_raw_c_type_text():
-            return "int"
-
-        @staticmethod
-        def get_raw_type_model():
-            return TypeModel.Int
-
-    class Number(BaseType):
-        @staticmethod
-        def get_getter_name():
-            return "Double"
-
-        @staticmethod
-        def get_setter_name():
-            return "Number"
-
-        @staticmethod
-        def get_constructor_pattern():
-            return "InspectorBasicValue::create(%s)"
-
-        @staticmethod
-        def get_raw_validator_call_text():
-            return "RuntimeCastHelper::assertType<JSONValue::TypeNumber>"
-
-        @staticmethod
-        def is_heavy_value():
-            return False
-
-        @staticmethod
-        def get_array_item_raw_c_type_text():
-            return "double"
-
-        @staticmethod
-        def get_raw_type_model():
-            return TypeModel.Number
-
-    class Bool(BaseType):
-        @staticmethod
-        def get_getter_name():
-            return "Boolean"
-
-        get_setter_name = get_getter_name
-
-        @staticmethod
-        def get_constructor_pattern():
-            return "InspectorBasicValue::create(%s)"
-
-        @staticmethod
-        def is_heavy_value():
-            return False
-
-        @staticmethod
-        def get_array_item_raw_c_type_text():
-            return "bool"
-
-        @staticmethod
-        def get_raw_type_model():
-            return TypeModel.Bool
-
-    class Object(BaseType):
-        @staticmethod
-        def get_getter_name():
-            return "Object"
-
-        @staticmethod
-        def get_setter_name():
-            return "Value"
-
-        @staticmethod
-        def get_constructor_pattern():
-            return "%s"
-
-        @staticmethod
-        def get_output_argument_prefix():
-            return ""
-
-        @staticmethod
-        def is_heavy_value():
-            return True
-
-        @staticmethod
-        def get_array_item_raw_c_type_text():
-            return "JSONObject"
-
-        @staticmethod
-        def get_raw_type_model():
-            return TypeModel.Object
-
-    class Any(BaseType):
-        @staticmethod
-        def get_getter_name():
-            return "Value"
-
-        get_setter_name = get_getter_name
-
-        @staticmethod
-        def get_constructor_pattern():
-            raise Exception("Unsupported")
-
-        @staticmethod
-        def get_raw_validator_call_text():
-            return "RuntimeCastHelper::assertAny"
-
-        @staticmethod
-        def is_heavy_value():
-            return True
-
-        @staticmethod
-        def get_array_item_raw_c_type_text():
-            return "JSONValue"
-
-        @staticmethod
-        def get_raw_type_model():
-            return TypeModel.Any
-
-    class Array(BaseType):
-        @staticmethod
-        def get_getter_name():
-            return "Array"
-
-        @staticmethod
-        def get_setter_name():
-            return "Value"
-
-        @staticmethod
-        def get_constructor_pattern():
-            return "%s"
-
-        @staticmethod
-        def get_output_argument_prefix():
-            return ""
-
-        @staticmethod
-        def is_heavy_value():
-            return True
-
-        @staticmethod
-        def get_array_item_raw_c_type_text():
-            return "JSONArray"
-
-        @staticmethod
-        def get_raw_type_model():
-            return TypeModel.Array
-
-
-class CommandReturnPassModel:
-    class ByReference:
-        def __init__(self, var_type, set_condition):
-            self.var_type = var_type
-            self.set_condition = set_condition
-
-        def get_return_var_type(self):
-            return self.var_type
-
-        @staticmethod
-        def get_output_argument_prefix():
-            return ""
-
-        @staticmethod
-        def get_output_to_raw_expression():
-            return "%s"
-
-        def get_output_parameter_type(self):
-            return self.var_type + "&"
-
-        def get_set_return_condition(self):
-            return self.set_condition
-
-    class ByPointer:
-        def __init__(self, var_type):
-            self.var_type = var_type
-
-        def get_return_var_type(self):
-            return self.var_type
-
-        @staticmethod
-        def get_output_argument_prefix():
-            return "&"
-
-        @staticmethod
-        def get_output_to_raw_expression():
-            return "%s"
-
-        def get_output_parameter_type(self):
-            return self.var_type + "*"
-
-        @staticmethod
-        def get_set_return_condition():
-            return None
-
-    class OptOutput:
-        def __init__(self, var_type):
-            self.var_type = var_type
-
-        def get_return_var_type(self):
-            return "TypeBuilder::OptOutput<%s>" % self.var_type
-
-        @staticmethod
-        def get_output_argument_prefix():
-            return "&"
-
-        @staticmethod
-        def get_output_to_raw_expression():
-            return "%s.getValue()"
-
-        def get_output_parameter_type(self):
-            return "TypeBuilder::OptOutput<%s>*" % self.var_type
-
-        @staticmethod
-        def get_set_return_condition():
-            return "%s.isAssigned()"
-
-
-class TypeModel:
-    class RefPtrBased(object):
-        def __init__(self, class_name):
-            self.class_name = class_name
-            self.optional = False
-
-        def get_optional(self):
-            result = TypeModel.RefPtrBased(self.class_name)
-            result.optional = True
-            return result
-
-        def get_command_return_pass_model(self):
-            if self.optional:
-                set_condition = "%s"
-            else:
-                set_condition = None
-            return CommandReturnPassModel.ByReference("RefPtr<%s>" % self.class_name, set_condition)
-
-        def get_input_param_type_text(self):
-            return "PassRefPtr<%s>" % self.class_name
-
-        @staticmethod
-        def get_event_setter_expression_pattern():
-            return "%s"
-
-    class Enum(object):
-        def __init__(self, base_type_name):
-            self.type_name = base_type_name + "::Enum"
-
-        def get_optional(base_self):
-            class EnumOptional:
-                @classmethod
-                def get_optional(cls):
-                    return cls
-
-                @staticmethod
-                def get_command_return_pass_model():
-                    return CommandReturnPassModel.OptOutput(base_self.type_name)
-
-                @staticmethod
-                def get_input_param_type_text():
-                    return base_self.type_name + "*"
-
-                @staticmethod
-                def get_event_setter_expression_pattern():
-                    raise Exception("TODO")
-            return EnumOptional
-
-        def get_command_return_pass_model(self):
-            return CommandReturnPassModel.ByPointer(self.type_name)
-
-        def get_input_param_type_text(self):
-            return self.type_name
-
-        @staticmethod
-        def get_event_setter_expression_pattern():
-            return "%s"
-
-    class ValueType(object):
-        def __init__(self, type_name, is_heavy):
-            self.type_name = type_name
-            self.is_heavy = is_heavy
-
-        def get_optional(self):
-            return self.ValueOptional(self)
-
-        def get_command_return_pass_model(self):
-            return CommandReturnPassModel.ByPointer(self.type_name)
-
-        def get_input_param_type_text(self):
-            if self.is_heavy:
-                return "const %s&" % self.type_name
-            else:
-                return self.type_name
-
-        def get_opt_output_type_(self):
-            return self.type_name
-
-        @staticmethod
-        def get_event_setter_expression_pattern():
-            return "%s"
-
-        class ValueOptional:
-            def __init__(self, base):
-                self.base = base
-
-            def get_optional(self):
-                return self
-
-            def get_command_return_pass_model(self):
-                return CommandReturnPassModel.OptOutput(self.base.get_opt_output_type_())
-
-            def get_input_param_type_text(self):
-                return "const %s* const" % self.base.type_name
-
-            @staticmethod
-            def get_event_setter_expression_pattern():
-                return "*%s"
-
-    @classmethod
-    def init_class(cls):
-        cls.Bool = cls.ValueType("bool", False)
-        cls.Int = cls.ValueType("int", False)
-        cls.Number = cls.ValueType("double", False)
-        cls.String = cls.ValueType("String", True,)
-        cls.Object = cls.RefPtrBased("JSONObject")
-        cls.Array = cls.RefPtrBased("JSONArray")
-        cls.Any = cls.RefPtrBased("JSONValue")
-
-TypeModel.init_class()
-
-
-# Collection of JSONObject class methods that are likely to be overloaded in generated class.
-# We must explicitly import all overloaded methods or they won't be available to user.
-INSPECTOR_OBJECT_SETTER_NAMES = frozenset(["setValue", "setBoolean", "setNumber", "setString", "setValue", "setObject", "setArray"])
-
-
-def fix_type_name(json_name):
-    if json_name in TYPE_NAME_FIX_MAP:
-        fixed = TYPE_NAME_FIX_MAP[json_name]
-
-        class Result(object):
-            class_name = fixed
-
-            @staticmethod
-            def output_comment(writer):
-                writer.newline("// Type originally was named '%s'.\n" % json_name)
-    else:
-
-        class Result(object):
-            class_name = json_name
-
-            @staticmethod
-            def output_comment(writer):
-                pass
-
-    return Result
-
-
-class Writer:
-    def __init__(self, output, indent):
-        self.output = output
-        self.indent = indent
-
-    def newline(self, str):
-        if (self.indent):
-            self.output.append(self.indent)
-        self.output.append(str)
-
-    def append(self, str):
-        self.output.append(str)
-
-    def newline_multiline(self, str):
-        parts = str.split('\n')
-        self.newline(parts[0])
-        for p in parts[1:]:
-            self.output.append('\n')
-            if p:
-                self.newline(p)
-
-    def append_multiline(self, str):
-        parts = str.split('\n')
-        self.append(parts[0])
-        for p in parts[1:]:
-            self.output.append('\n')
-            if p:
-                self.newline(p)
-
-    def get_indent(self):
-        return self.indent
-
-    def insert_writer(self, additional_indent):
-        new_output = []
-        self.output.append(new_output)
-        return Writer(new_output, self.indent + additional_indent)
-
-
-class EnumConstants:
-    map_ = {}
-    constants_ = []
-
-    @classmethod
-    def add_constant(cls, value):
-        if value in cls.map_:
-            return cls.map_[value]
-        else:
-            pos = len(cls.map_)
-            cls.map_[value] = pos
-            cls.constants_.append(value)
-            return pos
-
-    @classmethod
-    def get_enum_constant_code(cls):
-        output = []
-        for item in cls.constants_:
-            output.append("    \"" + item + "\"")
-        return ",\n".join(output) + "\n"
-
-
-# Typebuilder code is generated in several passes: first typedefs, then other classes.
-# Manual pass management is needed because we cannot have forward declarations for typedefs.
-class TypeBuilderPass:
-    TYPEDEF = "typedef"
-    MAIN = "main"
-
-
-class TypeBindings:
-    @staticmethod
-    def create_named_type_declaration(json_typable, context_domain_name, type_data):
-        json_type = type_data.get_json_type()
-
-        class Helper:
-            is_ad_hoc = False
-            full_name_prefix_for_use = "TypeBuilder::" + context_domain_name + "::"
-            full_name_prefix_for_impl = "TypeBuilder::" + context_domain_name + "::"
-
-            @staticmethod
-            def write_doc(writer):
-                if "description" in json_type:
-                    writer.newline("/* ")
-                    writer.append(json_type["description"])
-                    writer.append(" */\n")
-
-            @staticmethod
-            def add_to_forward_listener(forward_listener):
-                forward_listener.add_type_data(type_data)
-
-
-        fixed_type_name = fix_type_name(json_type["id"])
-        return TypeBindings.create_type_declaration_(json_typable, context_domain_name, fixed_type_name, Helper)
-
-    @staticmethod
-    def create_ad_hoc_type_declaration(json_typable, context_domain_name, ad_hoc_type_context):
-        class Helper:
-            is_ad_hoc = True
-            full_name_prefix_for_use = ad_hoc_type_context.container_relative_name_prefix
-            full_name_prefix_for_impl = ad_hoc_type_context.container_full_name_prefix
-
-            @staticmethod
-            def write_doc(writer):
-                pass
-
-            @staticmethod
-            def add_to_forward_listener(forward_listener):
-                pass
-        fixed_type_name = ad_hoc_type_context.get_type_name_fix()
-        return TypeBindings.create_type_declaration_(json_typable, context_domain_name, fixed_type_name, Helper)
-
-    @staticmethod
-    def create_type_declaration_(json_typable, context_domain_name, fixed_type_name, helper):
-        if json_typable["type"] == "string":
-            if "enum" in json_typable:
-
-                class EnumBinding:
-                    need_user_runtime_cast_ = False
-                    need_internal_runtime_cast_ = False
-
-                    @classmethod
-                    def resolve_inner(cls, resolve_context):
-                        pass
-
-                    @classmethod
-                    def request_user_runtime_cast(cls, request):
-                        if request:
-                            cls.need_user_runtime_cast_ = True
-                            request.acknowledge()
-
-                    @classmethod
-                    def request_internal_runtime_cast(cls):
-                        cls.need_internal_runtime_cast_ = True
-
-                    @classmethod
-                    def get_code_generator(enum_binding_cls):
-
-                        class CodeGenerator:
-                            @staticmethod
-                            def generate_type_builder(writer, generate_context):
-                                enum = json_typable["enum"]
-                                helper.write_doc(writer)
-                                enum_name = fixed_type_name.class_name
-                                fixed_type_name.output_comment(writer)
-                                writer.newline("struct ")
-                                writer.append(enum_name)
-                                writer.append(" {\n")
-                                writer.newline("    enum Enum {\n")
-                                for enum_item in enum:
-                                    enum_pos = EnumConstants.add_constant(enum_item)
-
-                                    item_c_name = enum_item.replace('-', '_')
-                                    item_c_name = Capitalizer.lower_camel_case_to_upper(item_c_name)
-                                    if item_c_name in TYPE_NAME_FIX_MAP:
-                                        item_c_name = TYPE_NAME_FIX_MAP[item_c_name]
-                                    writer.newline("        ")
-                                    writer.append(item_c_name)
-                                    writer.append(" = ")
-                                    writer.append("%s" % enum_pos)
-                                    writer.append(",\n")
-                                writer.newline("    };\n")
-                                if enum_binding_cls.need_user_runtime_cast_:
-                                    raise Exception("Not yet implemented")
-
-                                if enum_binding_cls.need_internal_runtime_cast_:
-                                    writer.append("#if %s\n" % VALIDATOR_IFDEF_NAME)
-                                    writer.newline("    static void assertCorrectValue(JSONValue* value);\n")
-                                    writer.append("#endif  // %s\n" % VALIDATOR_IFDEF_NAME)
-
-                                    validator_writer = generate_context.validator_writer
-
-                                    validator_writer.newline("void %s%s::assertCorrectValue(JSONValue* value)\n" % (helper.full_name_prefix_for_impl, enum_name))
-                                    validator_writer.newline("{\n")
-                                    validator_writer.newline("    WTF::String s;\n")
-                                    validator_writer.newline("    bool cast_res = value->asString(&s);\n")
-                                    validator_writer.newline("    ASSERT(cast_res);\n")
-                                    if len(enum) > 0:
-                                        condition_list = []
-                                        for enum_item in enum:
-                                            enum_pos = EnumConstants.add_constant(enum_item)
-                                            condition_list.append("s == \"%s\"" % enum_item)
-                                        validator_writer.newline("    ASSERT(%s);\n" % " || ".join(condition_list))
-                                    validator_writer.newline("}\n")
-
-                                    validator_writer.newline("\n\n")
-
-                                writer.newline("}; // struct ")
-                                writer.append(enum_name)
-                                writer.append("\n\n")
-
-                            @staticmethod
-                            def register_use(forward_listener):
-                                pass
-
-                            @staticmethod
-                            def get_generate_pass_id():
-                                return TypeBuilderPass.MAIN
-
-                        return CodeGenerator
-
-                    @classmethod
-                    def get_validator_call_text(cls):
-                        return helper.full_name_prefix_for_use + fixed_type_name.class_name + "::assertCorrectValue"
-
-                    @classmethod
-                    def get_array_item_c_type_text(cls):
-                        return helper.full_name_prefix_for_use + fixed_type_name.class_name + "::Enum"
-
-                    @staticmethod
-                    def get_setter_value_expression_pattern():
-                        return "TypeBuilder::getEnumConstantValue(%s)"
-
-                    @staticmethod
-                    def reduce_to_raw_type():
-                        return RawTypes.String
-
-                    @staticmethod
-                    def get_type_model():
-                        return TypeModel.Enum(helper.full_name_prefix_for_use + fixed_type_name.class_name)
-
-                return EnumBinding
-            else:
-                if helper.is_ad_hoc:
-
-                    class PlainString:
-                        @classmethod
-                        def resolve_inner(cls, resolve_context):
-                            pass
-
-                        @staticmethod
-                        def request_user_runtime_cast(request):
-                            raise Exception("Unsupported")
-
-                        @staticmethod
-                        def request_internal_runtime_cast():
-                            pass
-
-                        @staticmethod
-                        def get_code_generator():
-                            return None
-
-                        @classmethod
-                        def get_validator_call_text(cls):
-                            return RawTypes.String.get_raw_validator_call_text()
-
-                        @staticmethod
-                        def reduce_to_raw_type():
-                            return RawTypes.String
-
-                        @staticmethod
-                        def get_type_model():
-                            return TypeModel.String
-
-                        @staticmethod
-                        def get_setter_value_expression_pattern():
-                            return None
-
-                        @classmethod
-                        def get_array_item_c_type_text(cls):
-                            return cls.reduce_to_raw_type().get_array_item_raw_c_type_text()
-
-                    return PlainString
-
-                else:
-
-                    class TypedefString:
-                        @classmethod
-                        def resolve_inner(cls, resolve_context):
-                            pass
-
-                        @staticmethod
-                        def request_user_runtime_cast(request):
-                            raise Exception("Unsupported")
-
-                        @staticmethod
-                        def request_internal_runtime_cast():
-                            pass
-
-                        @staticmethod
-                        def get_code_generator():
-                            class CodeGenerator:
-                                @staticmethod
-                                def generate_type_builder(writer, generate_context):
-                                    helper.write_doc(writer)
-                                    fixed_type_name.output_comment(writer)
-                                    writer.newline("typedef String ")
-                                    writer.append(fixed_type_name.class_name)
-                                    writer.append(";\n\n")
-
-                                @staticmethod
-                                def register_use(forward_listener):
-                                    pass
-
-                                @staticmethod
-                                def get_generate_pass_id():
-                                    return TypeBuilderPass.TYPEDEF
-
-                            return CodeGenerator
-
-                        @classmethod
-                        def get_validator_call_text(cls):
-                            return RawTypes.String.get_raw_validator_call_text()
-
-                        @staticmethod
-                        def reduce_to_raw_type():
-                            return RawTypes.String
-
-                        @staticmethod
-                        def get_type_model():
-                            return TypeModel.ValueType("%s%s" % (helper.full_name_prefix_for_use, fixed_type_name.class_name), True)
-
-                        @staticmethod
-                        def get_setter_value_expression_pattern():
-                            return None
-
-                        @classmethod
-                        def get_array_item_c_type_text(cls):
-                            return "%s%s" % (helper.full_name_prefix_for_use, fixed_type_name.class_name)
-
-                    return TypedefString
-
-        elif json_typable["type"] == "object":
-            if "properties" in json_typable:
-
-                class ClassBinding:
-                    resolve_data_ = None
-                    need_user_runtime_cast_ = False
-                    need_internal_runtime_cast_ = False
-
-                    @classmethod
-                    def resolve_inner(cls, resolve_context):
-                        if cls.resolve_data_:
-                            return
-
-                        properties = json_typable["properties"]
-                        main = []
-                        optional = []
-
-                        ad_hoc_type_list = []
-
-                        for prop in properties:
-                            prop_name = prop["name"]
-                            ad_hoc_type_context = cls.AdHocTypeContextImpl(prop_name, fixed_type_name.class_name, resolve_context, ad_hoc_type_list, helper.full_name_prefix_for_impl)
-                            binding = resolve_param_type(prop, context_domain_name, ad_hoc_type_context)
-
-                            code_generator = binding.get_code_generator()
-                            if code_generator:
-                                code_generator.register_use(resolve_context.forward_listener)
-
-                            class PropertyData:
-                                param_type_binding = binding
-                                p = prop
-
-                            if prop.get("optional"):
-                                optional.append(PropertyData)
-                            else:
-                                main.append(PropertyData)
-
-                        class ResolveData:
-                            main_properties = main
-                            optional_properties = optional
-                            ad_hoc_types = ad_hoc_type_list
-
-                        cls.resolve_data_ = ResolveData
-
-                        for ad_hoc in ad_hoc_type_list:
-                            ad_hoc.resolve_inner(resolve_context)
-
-                    @classmethod
-                    def request_user_runtime_cast(cls, request):
-                        if not request:
-                            return
-                        cls.need_user_runtime_cast_ = True
-                        request.acknowledge()
-                        cls.request_internal_runtime_cast()
-
-                    @classmethod
-                    def request_internal_runtime_cast(cls):
-                        if cls.need_internal_runtime_cast_:
-                            return
-                        cls.need_internal_runtime_cast_ = True
-                        for p in cls.resolve_data_.main_properties:
-                            p.param_type_binding.request_internal_runtime_cast()
-                        for p in cls.resolve_data_.optional_properties:
-                            p.param_type_binding.request_internal_runtime_cast()
-
-                    @classmethod
-                    def get_code_generator(class_binding_cls):
-                        class CodeGenerator:
-                            @classmethod
-                            def generate_type_builder(cls, writer, generate_context):
-                                resolve_data = class_binding_cls.resolve_data_
-                                helper.write_doc(writer)
-                                class_name = fixed_type_name.class_name
-
-                                fixed_type_name.output_comment(writer)
-                                writer.newline("class PLATFORM_EXPORT %s : public JSONObjectBase {\n" % class_name)
-                                writer.newline("public:\n")
-                                ad_hoc_type_writer = writer.insert_writer("    ")
-
-                                for ad_hoc_type in resolve_data.ad_hoc_types:
-                                    code_generator = ad_hoc_type.get_code_generator()
-                                    if code_generator:
-                                        code_generator.generate_type_builder(ad_hoc_type_writer, generate_context)
-
-                                writer.newline_multiline(
-"""    enum {
-        NoFieldsSet = 0,
-""")
-
-                                state_enum_items = []
-                                if len(resolve_data.main_properties) > 0:
-                                    pos = 0
-                                    for prop_data in resolve_data.main_properties:
-                                        item_name = Capitalizer.lower_camel_case_to_upper(prop_data.p["name"]) + "Set"
-                                        state_enum_items.append(item_name)
-                                        writer.newline("        %s = 1 << %s,\n" % (item_name, pos))
-                                        pos += 1
-                                    all_fields_set_value = "(" + (" | ".join(state_enum_items)) + ")"
-                                else:
-                                    all_fields_set_value = "0"
-
-                                writer.newline_multiline(CodeGeneratorStrings.class_binding_builder_part_1
-                                                         % (all_fields_set_value, class_name, class_name))
-
-                                pos = 0
-                                for prop_data in resolve_data.main_properties:
-                                    prop_name = prop_data.p["name"]
-
-                                    param_type_binding = prop_data.param_type_binding
-                                    param_raw_type = param_type_binding.reduce_to_raw_type()
-
-                                    writer.newline_multiline(CodeGeneratorStrings.class_binding_builder_part_2
-                                        % (state_enum_items[pos],
-                                           Capitalizer.lower_camel_case_to_upper(prop_name),
-                                           param_type_binding.get_type_model().get_input_param_type_text(),
-                                           state_enum_items[pos], prop_name,
-                                           param_raw_type.get_setter_name(), prop_name,
-                                           format_setter_value_expression(param_type_binding, "value"),
-                                           state_enum_items[pos]))
-
-                                    pos += 1
-
-                                writer.newline_multiline(CodeGeneratorStrings.class_binding_builder_part_3
-                                                         % (class_name, class_name, class_name, class_name, class_name, class_name))
-
-                                writer.newline("    /*\n")
-                                writer.newline("     * Synthetic constructor:\n")
-                                writer.newline("     * RefPtr<%s> result = %s::create()" % (class_name, class_name))
-                                for prop_data in resolve_data.main_properties:
-                                    writer.append_multiline("\n     *     .set%s(...)" % Capitalizer.lower_camel_case_to_upper(prop_data.p["name"]))
-                                writer.append_multiline(";\n     */\n")
-
-                                writer.newline_multiline(CodeGeneratorStrings.class_binding_builder_part_4)
-
-                                writer.newline("    typedef TypeBuilder::StructItemTraits ItemTraits;\n")
-
-                                for prop_data in resolve_data.main_properties:
-                                    prop_name = prop_data.p["name"]
-                                    param_type_binding = prop_data.param_type_binding
-                                    if isinstance(param_type_binding.get_type_model(), TypeModel.ValueType):
-                                        writer.append_multiline("\n    void %s" % prop_name)
-                                        writer.append("(%s value)\n" % param_type_binding.get_type_model().get_command_return_pass_model().get_output_parameter_type())
-                                        writer.newline("    {\n")
-                                        writer.newline("        JSONObjectBase::get%s(\"%s\", value);\n"
-                                            % (param_type_binding.reduce_to_raw_type().get_setter_name(), prop_data.p["name"]))
-                                        writer.newline("    }\n")
-
-                                for prop_data in resolve_data.optional_properties:
-                                    prop_name = prop_data.p["name"]
-                                    param_type_binding = prop_data.param_type_binding
-                                    setter_name = "set%s" % Capitalizer.lower_camel_case_to_upper(prop_name)
-
-                                    writer.append_multiline("\n    void %s" % setter_name)
-                                    writer.append("(%s value)\n" % param_type_binding.get_type_model().get_input_param_type_text())
-                                    writer.newline("    {\n")
-                                    writer.newline("        this->set%s(\"%s\", %s);\n"
-                                        % (param_type_binding.reduce_to_raw_type().get_setter_name(), prop_data.p["name"],
-                                           format_setter_value_expression(param_type_binding, "value")))
-                                    writer.newline("    }\n")
-
-                                    if setter_name in INSPECTOR_OBJECT_SETTER_NAMES:
-                                        writer.newline("    using JSONObjectBase::%s;\n\n" % setter_name)
-
-                                if class_binding_cls.need_user_runtime_cast_:
-                                    writer.newline("    static PassRefPtr<%s> runtimeCast(PassRefPtr<JSONValue> value)\n" % class_name)
-                                    writer.newline("    {\n")
-                                    writer.newline("        RefPtr<JSONObject> object;\n")
-                                    writer.newline("        bool castRes = value->asObject(&object);\n")
-                                    writer.newline("        ASSERT_UNUSED(castRes, castRes);\n")
-                                    writer.append("#if %s\n" % VALIDATOR_IFDEF_NAME)
-                                    writer.newline("        assertCorrectValue(object.get());\n")
-                                    writer.append("#endif  // %s\n" % VALIDATOR_IFDEF_NAME)
-                                    writer.newline("        static_assert(sizeof(%s) == sizeof(JSONObjectBase), \"%s should be the same size as JSONObjectBase\");\n" % (class_name, class_name))
-                                    writer.newline("        return static_cast<%s*>(static_cast<JSONObjectBase*>(object.get()));\n" % class_name)
-                                    writer.newline("    }\n")
-                                    writer.append("\n")
-
-                                if class_binding_cls.need_internal_runtime_cast_:
-                                    writer.append("#if %s\n" % VALIDATOR_IFDEF_NAME)
-                                    writer.newline("    static void assertCorrectValue(JSONValue* value);\n")
-                                    writer.append("#endif  // %s\n" % VALIDATOR_IFDEF_NAME)
-
-                                    validator_writer = generate_context.validator_writer
-
-                                    validator_writer.newline("void %s%s::assertCorrectValue(JSONValue* value)\n" % (helper.full_name_prefix_for_impl, class_name))
-                                    validator_writer.newline("{\n")
-                                    validator_writer.newline("    RefPtr<JSONObject> object;\n")
-                                    validator_writer.newline("    bool castRes = value->asObject(&object);\n")
-                                    validator_writer.newline("    ASSERT_UNUSED(castRes, castRes);\n")
-                                    for prop_data in resolve_data.main_properties:
-                                        validator_writer.newline("    {\n")
-                                        it_name = "%sPos" % prop_data.p["name"]
-                                        validator_writer.newline("        JSONObject::iterator %s;\n" % it_name)
-                                        validator_writer.newline("        %s = object->find(\"%s\");\n" % (it_name, prop_data.p["name"]))
-                                        validator_writer.newline("        ASSERT(%s != object->end());\n" % it_name)
-                                        validator_writer.newline("        %s(%s->value.get());\n" % (prop_data.param_type_binding.get_validator_call_text(), it_name))
-                                        validator_writer.newline("    }\n")
-
-                                    validator_writer.newline("    int foundPropertiesCount = %s;\n" % len(resolve_data.main_properties))
-
-                                    for prop_data in resolve_data.optional_properties:
-                                        validator_writer.newline("    {\n")
-                                        it_name = "%sPos" % prop_data.p["name"]
-                                        validator_writer.newline("        JSONObject::iterator %s;\n" % it_name)
-                                        validator_writer.newline("        %s = object->find(\"%s\");\n" % (it_name, prop_data.p["name"]))
-                                        validator_writer.newline("        if (%s != object->end()) {\n" % it_name)
-                                        validator_writer.newline("            %s(%s->value.get());\n" % (prop_data.param_type_binding.get_validator_call_text(), it_name))
-                                        validator_writer.newline("            ++foundPropertiesCount;\n")
-                                        validator_writer.newline("        }\n")
-                                        validator_writer.newline("    }\n")
-
-                                    validator_writer.newline("    if (foundPropertiesCount != object->size()) {\n")
-                                    validator_writer.newline("      FATAL(\"Unexpected properties in object: %s\\n\", object->toJSONString().ascii().data());\n")
-                                    validator_writer.newline("    }\n")
-                                    validator_writer.newline("}\n")
-
-                                    validator_writer.newline("\n\n")
-
-                                writer.newline("};\n\n")
-
-                            @staticmethod
-                            def generate_forward_declaration(writer):
-                                class_name = fixed_type_name.class_name
-                                writer.newline("class ")
-                                writer.append(class_name)
-                                writer.append(";\n")
-
-                            @staticmethod
-                            def register_use(forward_listener):
-                                helper.add_to_forward_listener(forward_listener)
-
-                            @staticmethod
-                            def get_generate_pass_id():
-                                return TypeBuilderPass.MAIN
-
-                        return CodeGenerator
-
-                    @staticmethod
-                    def get_validator_call_text():
-                        return helper.full_name_prefix_for_use + fixed_type_name.class_name + "::assertCorrectValue"
-
-                    @classmethod
-                    def get_array_item_c_type_text(cls):
-                        return helper.full_name_prefix_for_use + fixed_type_name.class_name
-
-                    @staticmethod
-                    def get_setter_value_expression_pattern():
-                        return "static_pointer_cast<JSONValue>(%s)"
-
-                    @staticmethod
-                    def reduce_to_raw_type():
-                        return RawTypes.Object
-
-                    @staticmethod
-                    def get_type_model():
-                        return TypeModel.RefPtrBased(helper.full_name_prefix_for_use + fixed_type_name.class_name)
-
-                    class AdHocTypeContextImpl:
-                        def __init__(self, property_name, class_name, resolve_context, ad_hoc_type_list, parent_full_name_prefix):
-                            self.property_name = property_name
-                            self.class_name = class_name
-                            self.resolve_context = resolve_context
-                            self.ad_hoc_type_list = ad_hoc_type_list
-                            self.container_full_name_prefix = parent_full_name_prefix + class_name + "::"
-                            self.container_relative_name_prefix = ""
-
-                        def get_type_name_fix(self):
-                            class NameFix:
-                                class_name = Capitalizer.lower_camel_case_to_upper(self.property_name)
-
-                                @staticmethod
-                                def output_comment(writer):
-                                    writer.newline("// Named after property name '%s' while generating %s.\n" % (self.property_name, self.class_name))
-
-                            return NameFix
-
-                        def add_type(self, binding):
-                            self.ad_hoc_type_list.append(binding)
-
-                return ClassBinding
-            else:
-
-                class PlainObjectBinding:
-                    @classmethod
-                    def resolve_inner(cls, resolve_context):
-                        pass
-
-                    @staticmethod
-                    def request_user_runtime_cast(request):
-                        pass
-
-                    @staticmethod
-                    def request_internal_runtime_cast():
-                        pass
-
-                    @staticmethod
-                    def get_code_generator():
-                        pass
-
-                    @staticmethod
-                    def get_validator_call_text():
-                        return "RuntimeCastHelper::assertType<JSONValue::TypeObject>"
-
-                    @classmethod
-                    def get_array_item_c_type_text(cls):
-                        return cls.reduce_to_raw_type().get_array_item_raw_c_type_text()
-
-                    @staticmethod
-                    def get_setter_value_expression_pattern():
-                        return None
-
-                    @staticmethod
-                    def reduce_to_raw_type():
-                        return RawTypes.Object
-
-                    @staticmethod
-                    def get_type_model():
-                        return TypeModel.Object
-
-                return PlainObjectBinding
-        elif json_typable["type"] == "array":
-            if "items" in json_typable:
-
-                ad_hoc_types = []
-
-                class AdHocTypeContext:
-                    container_full_name_prefix = "<not yet defined>"
-                    container_relative_name_prefix = ""
-
-                    @staticmethod
-                    def get_type_name_fix():
-                        return fixed_type_name
-
-                    @staticmethod
-                    def add_type(binding):
-                        ad_hoc_types.append(binding)
-
-                item_binding = resolve_param_type(json_typable["items"], context_domain_name, AdHocTypeContext)
-
-                class ArrayBinding:
-                    resolve_data_ = None
-                    need_internal_runtime_cast_ = False
-
-                    @classmethod
-                    def resolve_inner(cls, resolve_context):
-                        if cls.resolve_data_:
-                            return
-
-                        class ResolveData:
-                            item_type_binding = item_binding
-                            ad_hoc_type_list = ad_hoc_types
-
-                        cls.resolve_data_ = ResolveData
-
-                        for t in ad_hoc_types:
-                            t.resolve_inner(resolve_context)
-
-                    @classmethod
-                    def request_user_runtime_cast(cls, request):
-                        raise Exception("Not implemented yet")
-
-                    @classmethod
-                    def request_internal_runtime_cast(cls):
-                        if cls.need_internal_runtime_cast_:
-                            return
-                        cls.need_internal_runtime_cast_ = True
-                        cls.resolve_data_.item_type_binding.request_internal_runtime_cast()
-
-                    @classmethod
-                    def get_code_generator(array_binding_cls):
-
-                        class CodeGenerator:
-                            @staticmethod
-                            def generate_type_builder(writer, generate_context):
-                                ad_hoc_type_writer = writer
-
-                                resolve_data = array_binding_cls.resolve_data_
-
-                                for ad_hoc_type in resolve_data.ad_hoc_type_list:
-                                    code_generator = ad_hoc_type.get_code_generator()
-                                    if code_generator:
-                                        code_generator.generate_type_builder(ad_hoc_type_writer, generate_context)
-
-                            @staticmethod
-                            def generate_forward_declaration(writer):
-                                pass
-
-                            @staticmethod
-                            def register_use(forward_listener):
-                                item_code_generator = item_binding.get_code_generator()
-                                if item_code_generator:
-                                    item_code_generator.register_use(forward_listener)
-
-                            @staticmethod
-                            def get_generate_pass_id():
-                                return TypeBuilderPass.MAIN
-
-                        return CodeGenerator
-
-                    @classmethod
-                    def get_validator_call_text(cls):
-                        return cls.get_array_item_c_type_text() + "::assertCorrectValue"
-
-                    @classmethod
-                    def get_array_item_c_type_text(cls):
-                        return "TypeBuilder::Array<%s>" % cls.resolve_data_.item_type_binding.get_array_item_c_type_text()
-
-                    @staticmethod
-                    def get_setter_value_expression_pattern():
-                        return None
-
-                    @staticmethod
-                    def reduce_to_raw_type():
-                        return RawTypes.Array
-
-                    @classmethod
-                    def get_type_model(cls):
-                        return TypeModel.RefPtrBased(cls.get_array_item_c_type_text())
-
-                return ArrayBinding
-            else:
-                # Fall-through to raw type.
-                pass
-
-        raw_type = RawTypes.get(json_typable["type"])
-
-        return RawTypeBinding(raw_type)
-
-
-class RawTypeBinding:
-    def __init__(self, raw_type):
-        self.raw_type_ = raw_type
-
-    def resolve_inner(self, resolve_context):
-        pass
-
-    def request_user_runtime_cast(self, request):
-        raise Exception("Unsupported")
-
-    def request_internal_runtime_cast(self):
-        pass
-
-    def get_code_generator(self):
-        return None
-
-    def get_validator_call_text(self):
-        return self.raw_type_.get_raw_validator_call_text()
-
-    def get_array_item_c_type_text(self):
-        return self.raw_type_.get_array_item_raw_c_type_text()
-
-    def get_setter_value_expression_pattern(self):
-        return None
-
-    def reduce_to_raw_type(self):
-        return self.raw_type_
-
-    def get_type_model(self):
-        return self.raw_type_.get_raw_type_model()
-
-
-class TypeData(object):
-    def __init__(self, json_type, json_domain, domain_data):
-        self.json_type_ = json_type
-        self.json_domain_ = json_domain
-        self.domain_data_ = domain_data
-
-        if "type" not in json_type:
-            raise Exception("Unknown type")
-
-        json_type_name = json_type["type"]
-        raw_type = RawTypes.get(json_type_name)
-        self.raw_type_ = raw_type
-        self.binding_being_resolved_ = False
-        self.binding_ = None
-
-    def get_raw_type(self):
-        return self.raw_type_
-
-    def get_binding(self):
-        if not self.binding_:
-            if self.binding_being_resolved_:
-                raise Error("Type %s is already being resolved" % self.json_type_["type"])
-            # Resolve only lazily, because resolving one named type may require resolving some other named type.
-            self.binding_being_resolved_ = True
-            try:
-                self.binding_ = TypeBindings.create_named_type_declaration(self.json_type_, self.json_domain_["domain"], self)
-            finally:
-                self.binding_being_resolved_ = False
-
-        return self.binding_
-
-    def get_json_type(self):
-        return self.json_type_
-
-    def get_name(self):
-        return self.json_type_["id"]
-
-    def get_domain_name(self):
-        return self.json_domain_["domain"]
-
-
-class DomainData:
-    def __init__(self, json_domain):
-        self.json_domain = json_domain
-        self.types_ = []
-
-    def add_type(self, type_data):
-        self.types_.append(type_data)
-
-    def name(self):
-        return self.json_domain["domain"]
-
-    def types(self):
-        return self.types_
-
-
-class TypeMap:
-    def __init__(self, api):
-        self.map_ = {}
-        self.domains_ = []
-        for json_domain in api["domains"]:
-            domain_name = json_domain["domain"]
-
-            domain_map = {}
-            self.map_[domain_name] = domain_map
-
-            domain_data = DomainData(json_domain)
-            self.domains_.append(domain_data)
-
-            if "types" in json_domain:
-                for json_type in json_domain["types"]:
-                    type_name = json_type["id"]
-                    type_data = TypeData(json_type, json_domain, domain_data)
-                    domain_map[type_name] = type_data
-                    domain_data.add_type(type_data)
-
-    def domains(self):
-        return self.domains_
-
-    def get(self, domain_name, type_name):
-        return self.map_[domain_name][type_name]
-
-
-def resolve_param_type(json_parameter, scope_domain_name, ad_hoc_type_context):
-    if "$ref" in json_parameter:
-        json_ref = json_parameter["$ref"]
-        type_data = get_ref_data(json_ref, scope_domain_name)
-        return type_data.get_binding()
-    elif "type" in json_parameter:
-        result = TypeBindings.create_ad_hoc_type_declaration(json_parameter, scope_domain_name, ad_hoc_type_context)
-        ad_hoc_type_context.add_type(result)
-        return result
-    else:
-        raise Exception("Unknown type")
-
-def resolve_param_raw_type(json_parameter, scope_domain_name):
-    if "$ref" in json_parameter:
-        json_ref = json_parameter["$ref"]
-        type_data = get_ref_data(json_ref, scope_domain_name)
-        return type_data.get_raw_type()
-    elif "type" in json_parameter:
-        json_type = json_parameter["type"]
-        return RawTypes.get(json_type)
-    else:
-        raise Exception("Unknown type")
-
-
-def get_ref_data(json_ref, scope_domain_name):
-    dot_pos = json_ref.find(".")
-    if dot_pos == -1:
-        domain_name = scope_domain_name
-        type_name = json_ref
-    else:
-        domain_name = json_ref[:dot_pos]
-        type_name = json_ref[dot_pos + 1:]
-
-    return type_map.get(domain_name, type_name)
-
-
-input_file = open(input_json_filename, "r")
-json_string = input_file.read()
-json_api = json.loads(json_string)
-
-
-class Templates:
-    def get_this_script_path_(absolute_path):
-        absolute_path = os.path.abspath(absolute_path)
-        components = []
-
-        def fill_recursive(path_part, depth):
-            if depth <= 0 or path_part == '/':
-                return
-            fill_recursive(os.path.dirname(path_part), depth - 1)
-            components.append(os.path.basename(path_part))
-
-        # Typical path is /Source/platform/inspector_protocol/CodeGenerator.py
-        # Let's take 4 components from the real path then.
-        fill_recursive(absolute_path, 4)
-
-        return "/".join(components)
-
-    file_header_ = ("// File is generated by %s\n\n" % get_this_script_path_(sys.argv[0]) +
-"""// Copyright (c) 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-""")
-
-    frontend_domain_class = string.Template(CodeGeneratorStrings.frontend_domain_class)
-    backend_method = string.Template(CodeGeneratorStrings.backend_method)
-    frontend_method = string.Template(CodeGeneratorStrings.frontend_method)
-    callback_main_methods = string.Template(CodeGeneratorStrings.callback_main_methods)
-    frontend_h = string.Template(file_header_ + CodeGeneratorStrings.frontend_h)
-    backend_h = string.Template(file_header_ + CodeGeneratorStrings.backend_h)
-    backend_cpp = string.Template(file_header_ + CodeGeneratorStrings.backend_cpp)
-    frontend_cpp = string.Template(file_header_ + CodeGeneratorStrings.frontend_cpp)
-    typebuilder_h = string.Template(file_header_ + CodeGeneratorStrings.typebuilder_h)
-    typebuilder_cpp = string.Template(file_header_ + CodeGeneratorStrings.typebuilder_cpp)
-    param_container_access_code = CodeGeneratorStrings.param_container_access_code
-
-
-
-
-
-type_map = TypeMap(json_api)
-
-
-class NeedRuntimeCastRequest:
-    def __init__(self):
-        self.ack_ = None
-
-    def acknowledge(self):
-        self.ack_ = True
-
-    def is_acknowledged(self):
-        return self.ack_
-
-
-def resolve_all_types():
-    runtime_cast_generate_requests = {}
-    for type_name in TYPES_WITH_RUNTIME_CAST_SET:
-        runtime_cast_generate_requests[type_name] = NeedRuntimeCastRequest()
-
-    class ForwardListener:
-        type_data_set = set()
-        already_declared_set = set()
-
-        @classmethod
-        def add_type_data(cls, type_data):
-            if type_data not in cls.already_declared_set:
-                cls.type_data_set.add(type_data)
-
-    class ResolveContext:
-        forward_listener = ForwardListener
-
-    for domain_data in type_map.domains():
-        for type_data in domain_data.types():
-            # Do not generate forwards for this type any longer.
-            ForwardListener.already_declared_set.add(type_data)
-
-            binding = type_data.get_binding()
-            binding.resolve_inner(ResolveContext)
-
-    for domain_data in type_map.domains():
-        for type_data in domain_data.types():
-            full_type_name = "%s.%s" % (type_data.get_domain_name(), type_data.get_name())
-            request = runtime_cast_generate_requests.pop(full_type_name, None)
-            binding = type_data.get_binding()
-            if request:
-                binding.request_user_runtime_cast(request)
-
-            if request and not request.is_acknowledged():
-                raise Exception("Failed to generate runtimeCast in " + full_type_name)
-
-    for full_type_name in runtime_cast_generate_requests:
-        raise Exception("Failed to generate runtimeCast. Type " + full_type_name + " not found")
-
-    return ForwardListener
-
-
-global_forward_listener = resolve_all_types()
-
-
-def get_annotated_type_text(raw_type, annotated_type):
-    if annotated_type != raw_type:
-        return "/*%s*/ %s" % (annotated_type, raw_type)
-    else:
-        return raw_type
-
-
-def format_setter_value_expression(param_type_binding, value_ref):
-    pattern = param_type_binding.get_setter_value_expression_pattern()
-    if pattern:
-        return pattern % value_ref
-    else:
-        return value_ref
-
-class Generator:
-    frontend_class_field_lines = []
-    frontend_domain_class_lines = []
-
-    method_name_enum_list = []
-    backend_method_declaration_list = []
-    backend_method_implementation_list = []
-    backend_method_name_declaration_list = []
-    backend_method_name_declaration_index_list = []
-    backend_method_name_declaration_current_index = 0
-    method_handler_list = []
-    frontend_method_list = []
-
-    backend_virtual_setters_list = []
-    backend_agent_interface_list = []
-    backend_setters_list = []
-    backend_constructor_init_list = []
-    backend_field_list = []
-    frontend_constructor_init_list = []
-    type_builder_fragments = []
-    type_builder_forwards = []
-    validator_impl_list = []
-    type_builder_impl_list = []
-
-
-    @staticmethod
-    def go():
-        Generator.process_types(type_map)
-
-        for json_domain in json_api["domains"]:
-            domain_name = json_domain["domain"]
-            domain_name_lower = domain_name.lower()
-
-            agent_field_name = DomainNameFixes.get_fixed_data(domain_name)
-
-            frontend_method_declaration_lines = []
-
-            if "events" in json_domain:
-                for json_event in json_domain["events"]:
-                    Generator.process_event(json_event, domain_name, frontend_method_declaration_lines)
-
-            Generator.frontend_class_field_lines.append("    %s m_%s;\n" % (domain_name, domain_name_lower))
-            if Generator.frontend_constructor_init_list:
-                Generator.frontend_constructor_init_list.append("    , ")
-            Generator.frontend_constructor_init_list.append("m_%s(frontendChannel)\n" % domain_name_lower)
-            Generator.frontend_domain_class_lines.append(Templates.frontend_domain_class.substitute(None,
-                domainClassName=domain_name,
-                domainFieldName=domain_name_lower,
-                frontendDomainMethodDeclarations="".join(flatten_list(frontend_method_declaration_lines))))
-
-            agent_interface_name = Capitalizer.lower_camel_case_to_upper(domain_name) + "CommandHandler"
-            Generator.backend_agent_interface_list.append("    class PLATFORM_EXPORT %s {\n" % agent_interface_name)
-            Generator.backend_agent_interface_list.append("    public:\n")
-            if "commands" in json_domain:
-                for json_command in json_domain["commands"]:
-                    Generator.process_command(json_command, domain_name, agent_field_name, agent_interface_name)
-            Generator.backend_agent_interface_list.append("\n    protected:\n")
-            Generator.backend_agent_interface_list.append("        virtual ~%s() { }\n" % agent_interface_name)
-            Generator.backend_agent_interface_list.append("    };\n\n")
-
-            Generator.backend_constructor_init_list.append("        , m_%s(0)" % agent_field_name)
-            Generator.backend_virtual_setters_list.append("    virtual void registerAgent(%s* %s) = 0;" % (agent_interface_name, agent_field_name))
-            Generator.backend_setters_list.append("    virtual void registerAgent(%s* %s) { ASSERT(!m_%s); m_%s = %s; }" % (agent_interface_name, agent_field_name, agent_field_name, agent_field_name, agent_field_name))
-            Generator.backend_field_list.append("    %s* m_%s;" % (agent_interface_name, agent_field_name))
-
-    @staticmethod
-    def process_event(json_event, domain_name, frontend_method_declaration_lines):
-        if (("handlers" in json_event) and (not ("renderer" in json_event["handlers"]))):
-            return
-
-        event_name = json_event["name"]
-
-        ad_hoc_type_output = []
-        frontend_method_declaration_lines.append(ad_hoc_type_output)
-        ad_hoc_type_writer = Writer(ad_hoc_type_output, "        ")
-
-        decl_parameter_list = []
-
-        json_parameters = json_event.get("parameters")
-        Generator.generate_send_method(json_parameters, event_name, domain_name, ad_hoc_type_writer,
-                                       decl_parameter_list,
-                                       Generator.EventMethodStructTemplate,
-                                       Generator.frontend_method_list, Templates.frontend_method, {"eventName": event_name})
-
-        frontend_method_declaration_lines.append(
-            "        void %s(%s);\n" % (event_name, ", ".join(decl_parameter_list)))
-
-    class EventMethodStructTemplate:
-        @staticmethod
-        def append_prolog(line_list):
-            line_list.append("    RefPtr<JSONObject> paramsObject = JSONObject::create();\n")
-
-        @staticmethod
-        def append_epilog(line_list):
-            line_list.append("    jsonMessage->setObject(\"params\", paramsObject);\n")
-
-        container_name = "paramsObject"
-
-    @staticmethod
-    def process_command(json_command, domain_name, agent_field_name, agent_interface_name):
-        if (("handlers" in json_command) and (not ("renderer" in json_command["handlers"]))):
-            return
-
-        json_command_name = json_command["name"]
-
-        cmd_enum_name = "k%s_%sCmd" % (domain_name, json_command["name"])
-
-        Generator.method_name_enum_list.append("        %s," % cmd_enum_name)
-        Generator.method_handler_list.append("            &DispatcherImpl::%s_%s," % (domain_name, json_command_name))
-        Generator.backend_method_declaration_list.append("    void %s_%s(int sessionId, int callId, JSONObject* requestMessageObject, JSONArray* protocolErrors);" % (domain_name, json_command_name))
-
-        backend_agent_interface_list = [] if "redirect" in json_command else Generator.backend_agent_interface_list
-
-        ad_hoc_type_output = []
-        backend_agent_interface_list.append(ad_hoc_type_output)
-        ad_hoc_type_writer = Writer(ad_hoc_type_output, "        ")
-
-        backend_agent_interface_list.append("        virtual void %s(ErrorString*" % json_command_name)
-
-        method_in_code = ""
-        method_out_code = ""
-        agent_call_param_list = ["&error"]
-        agent_call_params_declaration_list = ["    ErrorString error;"]
-        send_response_call_params_list = ["error"]
-        request_message_param = ""
-        normal_response_cook_text = ""
-
-        if "parameters" in json_command:
-            json_params = json_command["parameters"]
-            request_message_param = " requestMessageObject"
-
-            if json_params:
-                method_in_code += Templates.param_container_access_code
-
-            for json_parameter in json_params:
-                json_param_name = json_parameter["name"]
-                param_raw_type = resolve_param_raw_type(json_parameter, domain_name)
-
-                getter_name = param_raw_type.get_getter_name()
-
-                optional = json_parameter.get("optional")
-
-                non_optional_type_model = param_raw_type.get_raw_type_model()
-
-                if optional:
-                    code = ("    bool %s_valueFound = false;\n"
-                            "    %s in_%s = get%s(paramsContainerPtr, \"%s\", &%s_valueFound, protocolErrors);\n" %
-                           (json_param_name, non_optional_type_model.get_command_return_pass_model().get_return_var_type(), json_param_name, getter_name, json_param_name, json_param_name))
-                    param = "%s_valueFound ? &in_%s : 0" % (json_param_name, json_param_name)
-                    # FIXME: pass optional refptr-values as PassRefPtr
-                    formal_param_type_pattern = "const %s*"
-                else:
-                    code = ("    %s in_%s = get%s(paramsContainerPtr, \"%s\", 0, protocolErrors);\n" %
-                            (non_optional_type_model.get_command_return_pass_model().get_return_var_type(), json_param_name, getter_name, json_param_name))
-                    param = "in_%s" % json_param_name
-                    # FIXME: pass not-optional refptr-values as NonNullPassRefPtr
-                    if param_raw_type.is_heavy_value():
-                        formal_param_type_pattern = "const %s&"
-                    else:
-                        formal_param_type_pattern = "%s"
-
-                method_in_code += code
-                agent_call_param_list.append(param)
-                backend_agent_interface_list.append(", %s in_%s" % (formal_param_type_pattern % non_optional_type_model.get_command_return_pass_model().get_return_var_type(), json_param_name))
-
-        if json_command.get("async") == True:
-            callback_name = Capitalizer.lower_camel_case_to_upper(json_command_name) + "Callback"
-
-            callback_output = []
-            callback_writer = Writer(callback_output, ad_hoc_type_writer.get_indent())
-
-            decl_parameter_list = []
-            Generator.generate_send_method(json_command.get("returns"), json_command_name, domain_name, ad_hoc_type_writer,
-                                           decl_parameter_list,
-                                           Generator.CallbackMethodStructTemplate,
-                                           Generator.backend_method_implementation_list, Templates.callback_main_methods,
-                                           {"callbackName": callback_name, "agentName": agent_interface_name})
-
-            callback_writer.newline("class " + callback_name + " : public CallbackBase {\n")
-            callback_writer.newline("public:\n")
-            callback_writer.newline("    " + callback_name + "(PassRefPtr<DispatcherImpl>, int sessionId, int id);\n")
-            callback_writer.newline("    PLATFORM_EXPORT void sendSuccess(" + ", ".join(decl_parameter_list) + ");\n")
-            callback_writer.newline("};\n")
-
-            ad_hoc_type_output.append(callback_output)
-
-            method_out_code += "    RefPtr<" + agent_interface_name + "::" + callback_name + "> callback = adoptRef(new " + agent_interface_name + "::" + callback_name + "(this, sessionId, callId));\n"
-            agent_call_param_list.append("callback")
-            normal_response_cook_text += "    if (!error.length()) \n"
-            normal_response_cook_text += "        return;\n"
-            normal_response_cook_text += "    callback->disable();\n"
-            backend_agent_interface_list.append(", PassRefPtr<%s> callback" % callback_name)
-        else:
-            if "returns" in json_command:
-                method_out_code += "\n"
-                agent_call_params_declaration_list.append("    RefPtr<JSONObject> result = JSONObject::create();")
-                send_response_call_params_list.append("result")
-                response_cook_list = []
-                for json_return in json_command["returns"]:
-
-                    json_return_name = json_return["name"]
-
-                    optional = bool(json_return.get("optional"))
-
-                    return_type_binding = Generator.resolve_param_type_and_generate_ad_hoc(json_return, json_command_name, domain_name, ad_hoc_type_writer, agent_interface_name + "::")
-
-                    raw_type = return_type_binding.reduce_to_raw_type()
-                    setter_type = raw_type.get_setter_name()
-
-                    type_model = return_type_binding.get_type_model()
-                    if optional:
-                        type_model = type_model.get_optional()
-
-                    code = "    %s out_%s;\n" % (type_model.get_command_return_pass_model().get_return_var_type(), json_return_name)
-                    param = "%sout_%s" % (type_model.get_command_return_pass_model().get_output_argument_prefix(), json_return_name)
-                    var_name = "out_%s" % json_return_name
-                    setter_argument = type_model.get_command_return_pass_model().get_output_to_raw_expression() % var_name
-                    if return_type_binding.get_setter_value_expression_pattern():
-                        setter_argument = return_type_binding.get_setter_value_expression_pattern() % setter_argument
-
-                    cook = "        result->set%s(\"%s\", %s);\n" % (setter_type, json_return_name,
-                                                                         setter_argument)
-
-                    set_condition_pattern = type_model.get_command_return_pass_model().get_set_return_condition()
-                    if set_condition_pattern:
-                        cook = ("        if (%s)\n    " % (set_condition_pattern % var_name)) + cook
-                    annotated_type = type_model.get_command_return_pass_model().get_output_parameter_type()
-
-                    param_name = var_name
-                    if optional:
-                        param_name = "opt_" + param_name
-
-                    backend_agent_interface_list.append(", %s %s" % (annotated_type, param_name))
-                    response_cook_list.append(cook)
-
-                    method_out_code += code
-                    agent_call_param_list.append(param)
-
-                normal_response_cook_text += "".join(response_cook_list)
-
-                if len(normal_response_cook_text) != 0:
-                    normal_response_cook_text = "    if (!error.length()) {\n" + normal_response_cook_text + "    }"
-
-        # Redirect to another agent's implementation.
-        agent_field = "m_" + agent_field_name
-        if "redirect" in json_command:
-            agent_field = "m_" + DomainNameFixes.get_fixed_data(json_command.get("redirect"))
-
-        Generator.backend_method_implementation_list.append(Templates.backend_method.substitute(None,
-            domainName=domain_name, methodName=json_command_name,
-            agentField=agent_field,
-            methodCode="".join([method_in_code, method_out_code]),
-            agentCallParamsDeclaration="\n".join(agent_call_params_declaration_list),
-            agentCallParams=", ".join(agent_call_param_list),
-            requestMessageObject=request_message_param,
-            responseCook=normal_response_cook_text,
-            sendResponseCallParams=", ".join(send_response_call_params_list),
-            commandNameIndex=cmd_enum_name))
-        declaration_command_name = "%s.%s\\0" % (domain_name, json_command_name)
-        Generator.backend_method_name_declaration_list.append("    \"%s\"" % declaration_command_name)
-        assert Generator.backend_method_name_declaration_current_index < 2 ** 16, "Number too large for unsigned short."
-        Generator.backend_method_name_declaration_index_list.append("    %d," % Generator.backend_method_name_declaration_current_index)
-        Generator.backend_method_name_declaration_current_index += len(declaration_command_name) - 1
-
-        backend_agent_interface_list.append(") = 0;\n")
-
-    class CallbackMethodStructTemplate:
-        @staticmethod
-        def append_prolog(line_list):
-            pass
-
-        @staticmethod
-        def append_epilog(line_list):
-            pass
-
-        container_name = "jsonMessage"
-
-    # Generates common code for event sending and callback response data sending.
-    @staticmethod
-    def generate_send_method(parameters, event_name, domain_name, ad_hoc_type_writer, decl_parameter_list,
-                             method_struct_template,
-                             generator_method_list, method_template, template_params):
-        method_line_list = []
-        if parameters:
-            method_struct_template.append_prolog(method_line_list)
-            for json_parameter in parameters:
-                parameter_name = json_parameter["name"]
-
-                param_type_binding = Generator.resolve_param_type_and_generate_ad_hoc(json_parameter, event_name, domain_name, ad_hoc_type_writer, "")
-
-                raw_type = param_type_binding.reduce_to_raw_type()
-                raw_type_binding = RawTypeBinding(raw_type)
-
-                optional = bool(json_parameter.get("optional"))
-
-                setter_type = raw_type.get_setter_name()
-
-                type_model = param_type_binding.get_type_model()
-                raw_type_model = raw_type_binding.get_type_model()
-                if optional:
-                    type_model = type_model.get_optional()
-                    raw_type_model = raw_type_model.get_optional()
-
-                annotated_type = type_model.get_input_param_type_text()
-                mode_type_binding = param_type_binding
-
-                decl_parameter_list.append("%s %s" % (annotated_type, parameter_name))
-
-                setter_argument = raw_type_model.get_event_setter_expression_pattern() % parameter_name
-                if mode_type_binding.get_setter_value_expression_pattern():
-                    setter_argument = mode_type_binding.get_setter_value_expression_pattern() % setter_argument
-
-                setter_code = "    %s->set%s(\"%s\", %s);\n" % (method_struct_template.container_name, setter_type, parameter_name, setter_argument)
-                if optional:
-                    setter_code = ("    if (%s)\n    " % parameter_name) + setter_code
-                method_line_list.append(setter_code)
-
-            method_struct_template.append_epilog(method_line_list)
-
-        generator_method_list.append(method_template.substitute(None,
-            domainName=domain_name,
-            parameters=", ".join(decl_parameter_list),
-            code="".join(method_line_list), **template_params))
-
-    @classmethod
-    def resolve_param_type_and_generate_ad_hoc(cls, json_param, method_name, domain_name, ad_hoc_type_writer, container_relative_name_prefix_param):
-        param_name = json_param["name"]
-        return cls.resolve_type_and_generate_ad_hoc(json_param, param_name, method_name, domain_name, ad_hoc_type_writer, container_relative_name_prefix_param)
-
-    @staticmethod
-    def resolve_type_and_generate_ad_hoc(typable_element, element_name, method_name, domain_name, ad_hoc_type_writer, container_relative_name_prefix_param):
-        ad_hoc_type_list = []
-
-        class AdHocTypeContext:
-            container_full_name_prefix = "<not yet defined>"
-            container_relative_name_prefix = container_relative_name_prefix_param
-
-            @staticmethod
-            def get_type_name_fix():
-                class NameFix:
-                    class_name = Capitalizer.lower_camel_case_to_upper(element_name)
-
-                    @staticmethod
-                    def output_comment(writer):
-                        writer.newline("// Named after parameter '%s' while generating command/event %s.\n" % (element_name, method_name))
-
-                return NameFix
-
-            @staticmethod
-            def add_type(binding):
-                ad_hoc_type_list.append(binding)
-
-        type_binding = resolve_param_type(typable_element, domain_name, AdHocTypeContext)
-
-        class InterfaceForwardListener:
-            @staticmethod
-            def add_type_data(type_data):
-                pass
-
-        class InterfaceResolveContext:
-            forward_listener = InterfaceForwardListener
-
-        for type in ad_hoc_type_list:
-            type.resolve_inner(InterfaceResolveContext)
-
-        class InterfaceGenerateContext:
-            validator_writer = "not supported in InterfaceGenerateContext"
-            cpp_writer = validator_writer
-
-        for type in ad_hoc_type_list:
-            generator = type.get_code_generator()
-            if generator:
-                generator.generate_type_builder(ad_hoc_type_writer, InterfaceGenerateContext)
-
-        return type_binding
-
-    @staticmethod
-    def process_types(type_map):
-        output = Generator.type_builder_fragments
-
-        class GenerateContext:
-            validator_writer = Writer(Generator.validator_impl_list, "")
-            cpp_writer = Writer(Generator.type_builder_impl_list, "")
-
-        def generate_all_domains_code(out, type_data_callback):
-            writer = Writer(out, "")
-            for domain_data in type_map.domains():
-                namespace_declared = []
-
-                def namespace_lazy_generator():
-                    if not namespace_declared:
-                        writer.newline("namespace ")
-                        writer.append(domain_data.name())
-                        writer.append(" {\n")
-                        # What is a better way to change value from outer scope?
-                        namespace_declared.append(True)
-                    return writer
-
-                for type_data in domain_data.types():
-                    type_data_callback(type_data, namespace_lazy_generator)
-
-                if namespace_declared:
-                    writer.append("} // ")
-                    writer.append(domain_data.name())
-                    writer.append("\n\n")
-
-        def create_type_builder_caller(generate_pass_id):
-            def call_type_builder(type_data, writer_getter):
-                code_generator = type_data.get_binding().get_code_generator()
-                if code_generator and generate_pass_id == code_generator.get_generate_pass_id():
-                    writer = writer_getter()
-
-                    code_generator.generate_type_builder(writer, GenerateContext)
-            return call_type_builder
-
-        generate_all_domains_code(output, create_type_builder_caller(TypeBuilderPass.MAIN))
-
-        Generator.type_builder_forwards.append("// Forward declarations.\n")
-
-        def generate_forward_callback(type_data, writer_getter):
-            if type_data in global_forward_listener.type_data_set:
-                binding = type_data.get_binding()
-                binding.get_code_generator().generate_forward_declaration(writer_getter())
-        generate_all_domains_code(Generator.type_builder_forwards, generate_forward_callback)
-
-        Generator.type_builder_forwards.append("// End of forward declarations.\n\n")
-
-        Generator.type_builder_forwards.append("// Typedefs.\n")
-
-        generate_all_domains_code(Generator.type_builder_forwards, create_type_builder_caller(TypeBuilderPass.TYPEDEF))
-
-        Generator.type_builder_forwards.append("// End of typedefs.\n\n")
-
-
-def flatten_list(input):
-    res = []
+def initialize_jinja_env(cache_dir):
+    jinja_env = jinja2.Environment(
+        loader=jinja2.FileSystemLoader(templates_dir),
+        # Bytecode cache is not concurrency-safe unless pre-cached:
+        # if pre-cached this is read-only, but writing creates a race condition.
+        bytecode_cache=jinja2.FileSystemBytecodeCache(cache_dir),
+        keep_trailing_newline=True,  # newline-terminate generated files
+        lstrip_blocks=True,  # so can indent control flow tags
+        trim_blocks=True)
+    jinja_env.filters.update({"to_title_case": to_title_case, "dash_to_camelcase": dash_to_camelcase})
+    jinja_env.add_extension('jinja2.ext.loopcontrols')
+    return jinja_env
 
-    def fill_recursive(l):
-        for item in l:
-            if isinstance(item, list):
-                fill_recursive(item)
-            else:
-                res.append(item)
-    fill_recursive(input)
-    return res
 
 def output_file(file_name):
     return open(file_name, "w")
 
 
-Generator.go()
+def patch_full_qualified_refs():
+    def patch_full_qualified_refs_in_domain(json, domain_name):
+        if isinstance(json, list):
+            for item in json:
+                patch_full_qualified_refs_in_domain(item, domain_name)
 
-backend_h_file = output_file(output_dirname + "/Dispatcher.h")
-backend_cpp_file = output_file(output_dirname + "/Dispatcher.cpp")
+        if not isinstance(json, dict):
+            return
+        for key in json:
+            if key != "$ref":
+                patch_full_qualified_refs_in_domain(json[key], domain_name)
+                continue
+            if json["$ref"].find(".") == -1:
+                json["$ref"] = domain_name + "." + json["$ref"]
 
-frontend_h_file = output_file(output_dirname + "/Frontend.h")
-frontend_cpp_file = output_file(output_dirname + "/Frontend.cpp")
-
-typebuilder_h_file = output_file(output_dirname + "/TypeBuilder.h")
-typebuilder_cpp_file = output_file(output_dirname + "/TypeBuilder.cpp")
+    for domain in json_api["domains"]:
+        patch_full_qualified_refs_in_domain(domain, domain["domain"])
 
 
-backend_h_file.write(Templates.backend_h.substitute(None,
-    virtualSetters="\n".join(Generator.backend_virtual_setters_list),
-    agentInterfaces="".join(flatten_list(Generator.backend_agent_interface_list)),
-    methodNamesEnumContent="\n".join(Generator.method_name_enum_list)))
+def create_user_type_definition(domain_name, type):
+    return {
+        "return_type": "PassOwnPtr<protocol::%s::%s>" % (domain_name, type["id"]),
+        "pass_type": "PassOwnPtr<protocol::%s::%s>" % (domain_name, type["id"]),
+        "to_pass_type": "%s.release()",
+        "type": "OwnPtr<protocol::%s::%s>" % (domain_name, type["id"]),
+        "raw_type": "protocol::%s::%s" % (domain_name, type["id"]),
+        "create_type": "adoptPtr(new protocol::%s::%s())" % (domain_name, type["id"]),
+        "optional_type": "OwnPtr<protocol::%s::%s>" % (domain_name, type["id"]),
+        "optional_pass_type": "PassOwnPtr<protocol::%s::%s>" % (domain_name, type["id"]),
+        "from_optional_out": "%s.release()",
+        "json_getter": "FromValue<protocol::%s::%s>::convert(getObject(%%s))" % (domain_name, type["id"]),
+        "json_type": "TypeObject",
+        "nullable": True,
+    }
 
-backend_cpp_file.write(Templates.backend_cpp.substitute(None,
-    constructorInit="\n".join(Generator.backend_constructor_init_list),
-    setters="\n".join(Generator.backend_setters_list),
-    fieldDeclarations="\n".join(Generator.backend_field_list),
-    methodNameDeclarations="\n".join(Generator.backend_method_name_declaration_list),
-    methodNameDeclarationsIndex="\n".join(Generator.backend_method_name_declaration_index_list),
-    methods="\n".join(Generator.backend_method_implementation_list),
-    methodDeclarations="\n".join(Generator.backend_method_declaration_list),
-    messageHandlers="\n".join(Generator.method_handler_list)))
 
-frontend_h_file.write(Templates.frontend_h.substitute(None,
-    fieldDeclarations="".join(Generator.frontend_class_field_lines),
-    domainClassList="".join(Generator.frontend_domain_class_lines)))
+def create_object_type_definition():
+    return {
+        "return_type": "PassRefPtr<JSONObject>",
+        "pass_type": "PassRefPtr<JSONObject>",
+        "to_pass_type": "%s.release()",
+        "type": "RefPtr<JSONObject>",
+        "raw_type": "RefPtr<JSONObject>",
+        "optional_type": "RefPtr<JSONObject>",
+        "optional_pass_type": "PassRefPtr<JSONObject>",
+        "from_optional_out": "%s.release()",
+        "json_getter": "getObject(%s)",
+        "json_type": "TypeObject",
+        "nullable": True,
+    }
 
-frontend_cpp_file.write(Templates.frontend_cpp.substitute(None,
-    constructorInit="".join(Generator.frontend_constructor_init_list),
-    methods="\n".join(Generator.frontend_method_list)))
 
-typebuilder_h_file.write(Templates.typebuilder_h.substitute(None,
-    typeBuilders="".join(flatten_list(Generator.type_builder_fragments)),
-    forwards="".join(Generator.type_builder_forwards),
-    validatorIfdefName=VALIDATOR_IFDEF_NAME))
+def create_any_type_definition():
+    return {
+        "return_type": "PassRefPtr<JSONValue>",
+        "pass_type": "PassRefPtr<JSONValue>",
+        "to_pass_type": "%s.release()",
+        "type": "RefPtr<JSONValue>",
+        "raw_type": "RefPtr<JSONValue>",
+        "optional_type": "RefPtr<JSONValue>",
+        "optional_pass_type": "PassRefPtr<JSONValue>",
+        "from_optional_out": "%s.release()",
+        "json_getter": "getValue(%s)",
+        "nullable": True,
+    }
 
-typebuilder_cpp_file.write(Templates.typebuilder_cpp.substitute(None,
-    enumConstantValues=EnumConstants.get_enum_constant_code(),
-    implCode="".join(flatten_list(Generator.type_builder_impl_list)),
-    validatorCode="".join(flatten_list(Generator.validator_impl_list)),
-    validatorIfdefName=VALIDATOR_IFDEF_NAME))
 
-backend_h_file.close()
-backend_cpp_file.close()
+def create_primitive_type_definition(type):
+    if type == "string":
+        return {
+            "return_type": "String",
+            "pass_type": "const String&",
+            "to_pass_type": "%s",
+            "type": "String",
+            "raw_type": "String",
+            "optional_type": "protocol::OptionalValue<String>",
+            "optional_pass_type": "const protocol::OptionalValue<String>&",
+            "from_optional_out": "%s.get()",
+            "json_getter": "getString(%s)",
+            "json_type": "TypeString",
+            "nullable": False,
+        }
 
-frontend_h_file.close()
-frontend_cpp_file.close()
+    typedefs = {
+        "number": "double",
+        "integer": "int",
+        "boolean": "bool"
+    }
+    jsontypes = {
+        "number": "TypeNumber",
+        "integer": "TypeNumber",
+        "boolean": "TypeBoolean",
+    }
+    return {
+        "return_type": typedefs[type],
+        "pass_type": typedefs[type],
+        "to_pass_type": "%s",
+        "type": typedefs[type],
+        "raw_type": typedefs[type],
+        "optional_type": "protocol::OptionalValue<" + typedefs[type] + ">",
+        "optional_pass_type": "const protocol::OptionalValue<" + typedefs[type] + ">&",
+        "from_optional_out": "%s.get()",
+        "json_getter": "get" + to_title_case(type) + "(%s)",
+        "json_type": jsontypes[type],
+        "nullable": False,
+    }
 
-typebuilder_h_file.close()
-typebuilder_cpp_file.close()
+type_definitions = {}
+type_definitions["string"] = create_primitive_type_definition("string")
+type_definitions["number"] = create_primitive_type_definition("number")
+type_definitions["integer"] = create_primitive_type_definition("integer")
+type_definitions["boolean"] = create_primitive_type_definition("boolean")
+type_definitions["object"] = create_object_type_definition()
+type_definitions["any"] = create_any_type_definition()
+
+
+def wrap_array_definition(type):
+    return {
+        "return_type": "PassOwnPtr<protocol::Array<%s>>" % type["raw_type"],
+        "pass_type": "PassOwnPtr<protocol::Array<%s>>" % type["raw_type"],
+        "to_pass_type": "%s.release()",
+        "type": "OwnPtr<protocol::Array<%s>>" % type["raw_type"],
+        "raw_type": "protocol::Array<%s>" % type["raw_type"],
+        "create_type": "adoptPtr(new protocol::Array<%s>())" % type["raw_type"],
+        "out_type": "protocol::Array<%s>&" % type["raw_type"],
+        "optional_type": "OwnPtr<protocol::Array<%s>>" % type["raw_type"],
+        "optional_pass_type": "PassOwnPtr<protocol::Array<%s>>" % type["raw_type"],
+        "from_optional_out": "%s.release()",
+        "json_getter": "protocol::Array<%s>::runtimeCast(getArray(%%s))" % type["raw_type"],
+        "json_type": "TypeArray",
+        "nullable": True,
+    }
+
+
+def create_type_definitions():
+    for domain in json_api["domains"]:
+        if not ("types" in domain):
+            continue
+        for type in domain["types"]:
+            if type["type"] == "object":
+                type_definitions[domain["domain"] + "." + type["id"]] = create_user_type_definition(domain["domain"], type)
+            elif type["type"] == "array":
+                items_type = type["items"]["type"]
+                type_definitions[domain["domain"] + "." + type["id"]] = wrap_array_definition(type_definitions[items_type])
+            else:
+                type_definitions[domain["domain"] + "." + type["id"]] = create_primitive_type_definition(type["type"])
+
+patch_full_qualified_refs()
+create_type_definitions()
+
+
+def type_definition(name):
+    return type_definitions[name]
+
+
+def resolve_type(property):
+    if "$ref" in property:
+        return type_definitions[property["$ref"]]
+    if property["type"] == "array":
+        return wrap_array_definition(resolve_type(property["items"]))
+    return type_definitions[property["type"]]
+
+
+def join_arrays(dict, keys):
+    result = []
+    for key in keys:
+        if key in dict:
+            result += dict[key]
+    return result
+
+
+def generate(class_name):
+    template_context = {
+        "class_name": class_name,
+        "api": json_api,
+        "join_arrays": join_arrays,
+        "resolve_type": resolve_type,
+        "type_definition": type_definition
+    }
+    h_template = jinja_env.get_template("/%s_h.template" % class_name)
+    cpp_template = jinja_env.get_template("/%s_cpp.template" % class_name)
+    h_file = output_file(output_dirname + "/" + class_name + ".h")
+    cpp_file = output_file(output_dirname + "/" + class_name + ".cpp")
+    h_file.write(h_template.render(template_context))
+    cpp_file.write(cpp_template.render(template_context))
+    h_file.close()
+    cpp_file.close()
+
+
+jinja_env = initialize_jinja_env(output_dirname)
+generate("Dispatcher")
+generate("Frontend")
+generate("TypeBuilder")
diff --git a/CodeGeneratorStrings.py b/CodeGeneratorStrings.py
deleted file mode 100644
index 0106d43..0000000
--- a/CodeGeneratorStrings.py
+++ /dev/null
@@ -1,912 +0,0 @@
-# Copyright (c) 2013 Google Inc. All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-#     * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-#     * Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following disclaimer
-# in the documentation and/or other materials provided with the
-# distribution.
-#     * Neither the name of Google Inc. nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-# THis file contains string resources for CodeGenerator.
-# Its syntax is a Python syntax subset, suitable for manual parsing.
-
-frontend_domain_class = (
-"""    class PLATFORM_EXPORT $domainClassName {
-    public:
-        static $domainClassName* from(Frontend* frontend) { return &(frontend->m_$domainFieldName) ;}
-        $domainClassName(FrontendChannel* frontendChannel) : m_frontendChannel(frontendChannel) { }
-${frontendDomainMethodDeclarations}
-        void flush() { m_frontendChannel->flush(); }
-    private:
-        FrontendChannel* m_frontendChannel;
-    };
-
-""")
-
-backend_method = (
-"""void DispatcherImpl::${domainName}_$methodName(int sessionId, int callId, JSONObject*$requestMessageObject, JSONArray* protocolErrors)
-{
-    if (!$agentField)
-        protocolErrors->pushString("${domainName} handler is not available.");
-$methodCode
-    if (protocolErrors->length()) {
-        reportProtocolError(sessionId, callId, InvalidParams, String::format(InvalidParamsFormatString, commandName($commandNameIndex)), protocolErrors);
-        return;
-    }
-$agentCallParamsDeclaration
-    $agentField->$methodName($agentCallParams);
-$responseCook
-    sendResponse(sessionId, callId, $sendResponseCallParams);
-}
-""")
-
-frontend_method = ("""void Frontend::$domainName::$eventName($parameters)
-{
-    RefPtr<JSONObject> jsonMessage = JSONObject::create();
-    jsonMessage->setString("method", "$domainName.$eventName");
-$code    if (m_frontendChannel)
-        m_frontendChannel->sendProtocolNotification(jsonMessage.release());
-}
-""")
-
-callback_main_methods = ("""
-Dispatcher::$agentName::$callbackName::$callbackName(PassRefPtr<DispatcherImpl> backendImpl, int sessionId, int id) : CallbackBase(backendImpl, sessionId, id) {}
-
-void Dispatcher::$agentName::$callbackName::sendSuccess($parameters)
-{
-    RefPtr<JSONObject> jsonMessage = JSONObject::create();
-$code    sendIfActive(jsonMessage, ErrorString(), PassRefPtr<JSONValue>());
-}
-""")
-
-
-frontend_h = (
-"""#ifndef Frontend_h
-#define Frontend_h
-
-#include "platform/inspector_protocol/TypeBuilder.h"
-
-#include "platform/JSONValues.h"
-#include "platform/PlatformExport.h"
-#include "platform/inspector_protocol/FrontendChannel.h"
-#include "wtf/PassRefPtr.h"
-#include "wtf/text/WTFString.h"
-
-namespace blink {
-namespace protocol {
-
-using ErrorString = String;
-
-class PLATFORM_EXPORT Frontend {
-public:
-    Frontend(FrontendChannel*);
-    FrontendChannel* channel() { return m_frontendChannel; }
-
-$domainClassList
-private:
-    FrontendChannel* m_frontendChannel;
-${fieldDeclarations}};
-
-} // namespace protocol
-} // namespace blink
-#endif // !defined(Frontend_h)
-""")
-
-backend_h = (
-"""#ifndef Dispatcher_h
-#define Dispatcher_h
-
-#include "platform/inspector_protocol/TypeBuilder.h"
-
-#include "platform/PlatformExport.h"
-#include "platform/heap/Handle.h"
-#include "wtf/PassRefPtr.h"
-#include "wtf/RefCounted.h"
-#include "wtf/text/WTFString.h"
-
-namespace blink {
-
-class JSONObject;
-class JSONArray;
-
-namespace protocol {
-
-class FrontendChannel;
-
-using ErrorString = String;
-
-class DispatcherImpl;
-
-class PLATFORM_EXPORT Dispatcher: public RefCounted<Dispatcher> {
-public:
-    static PassRefPtr<Dispatcher> create(FrontendChannel* frontendChannel);
-    virtual ~Dispatcher() { }
-
-    class PLATFORM_EXPORT CallbackBase: public RefCounted<CallbackBase> {
-    public:
-        CallbackBase(PassRefPtr<DispatcherImpl> backendImpl, int sessionId, int id);
-        virtual ~CallbackBase();
-        void sendFailure(const ErrorString&);
-        bool isActive();
-
-    protected:
-        void sendIfActive(PassRefPtr<JSONObject> partialMessage, const ErrorString& invocationError, PassRefPtr<JSONValue> errorData);
-
-    private:
-        void disable() { m_alreadySent = true; }
-
-        RefPtr<DispatcherImpl> m_backendImpl;
-        int m_sessionId;
-        int m_id;
-        bool m_alreadySent;
-
-        friend class DispatcherImpl;
-    };
-
-$agentInterfaces
-$virtualSetters
-
-    virtual void clearFrontend() = 0;
-
-    enum CommonErrorCode {
-        ParseError = 0,
-        InvalidRequest,
-        MethodNotFound,
-        InvalidParams,
-        InternalError,
-        ServerError,
-        LastEntry,
-    };
-
-    void reportProtocolError(int sessionId, int callId, CommonErrorCode, const String& errorMessage) const;
-    virtual void reportProtocolError(int sessionId, int callId, CommonErrorCode, const String& errorMessage, PassRefPtr<JSONValue> data) const = 0;
-    virtual void dispatch(int sessionId, const String& message) = 0;
-    static bool getCommandName(const String& message, String* result);
-
-    enum MethodNames {
-$methodNamesEnumContent
-
-        kMethodNamesEnumSize
-    };
-
-    static const char* commandName(MethodNames);
-
-private:
-    static const char commandNames[];
-    static const unsigned short commandNamesIndex[];
-};
-
-} // namespace protocol
-} // namespace blink
-
-using blink::protocol::ErrorString;
-
-#endif // !defined(Dispatcher_h)
-
-
-""")
-
-backend_cpp = (
-"""
-
-#include "platform/inspector_protocol/Dispatcher.h"
-
-#include "platform/JSONParser.h"
-#include "platform/JSONValues.h"
-#include "platform/inspector_protocol/FrontendChannel.h"
-#include "wtf/text/CString.h"
-#include "wtf/text/WTFString.h"
-
-namespace blink {
-namespace protocol {
-
-const char Dispatcher::commandNames[] = {
-$methodNameDeclarations
-};
-
-const unsigned short Dispatcher::commandNamesIndex[] = {
-$methodNameDeclarationsIndex
-};
-
-const char* Dispatcher::commandName(MethodNames index) {
-    static_assert(static_cast<int>(kMethodNamesEnumSize) == WTF_ARRAY_LENGTH(commandNamesIndex), "MethodNames enum should have the same number of elements as commandNamesIndex");
-    return commandNames + commandNamesIndex[index];
-}
-
-class DispatcherImpl : public Dispatcher {
-public:
-    DispatcherImpl(FrontendChannel* frontendChannel)
-        : m_frontendChannel(frontendChannel)
-$constructorInit
-    {
-        // Initialize dispatch map.
-        const CallHandler handlers[] = {
-  $messageHandlers
-        };
-        for (size_t i = 0; i < kMethodNamesEnumSize; ++i)
-            m_dispatchMap.add(commandName(static_cast<MethodNames>(i)), handlers[i]);
-
-        // Initialize common errors.
-        m_commonErrors.insert(ParseError, -32700);
-        m_commonErrors.insert(InvalidRequest, -32600);
-        m_commonErrors.insert(MethodNotFound, -32601);
-        m_commonErrors.insert(InvalidParams, -32602);
-        m_commonErrors.insert(InternalError, -32603);
-        m_commonErrors.insert(ServerError, -32000);
-    }
-
-    virtual void clearFrontend() { m_frontendChannel = 0; }
-    virtual void dispatch(int sessionId, const String& message);
-    virtual void reportProtocolError(int sessionId, int callId, CommonErrorCode, const String& errorMessage, PassRefPtr<JSONValue> data) const;
-    using Dispatcher::reportProtocolError;
-
-    void sendResponse(int sessionId, int callId, const ErrorString& invocationError, PassRefPtr<JSONValue> errorData, PassRefPtr<JSONObject> result);
-    bool isActive() { return m_frontendChannel; }
-
-$setters
-private:
-    using CallHandler = void (DispatcherImpl::*)(int sessionId, int callId, JSONObject* messageObject, JSONArray* protocolErrors);
-    using DispatchMap = HashMap<String, CallHandler>;
-
-$methodDeclarations
-
-    FrontendChannel* m_frontendChannel;
-$fieldDeclarations
-
-    template<typename R, typename V, typename V0>
-    static R getPropertyValueImpl(JSONObject* object, const char* name, bool* valueFound, JSONArray* protocolErrors, V0 initial_value, bool (*as_method)(JSONValue*, V*), const char* type_name);
-
-    static int getInt(JSONObject* object, const char* name, bool* valueFound, JSONArray* protocolErrors);
-    static double getDouble(JSONObject* object, const char* name, bool* valueFound, JSONArray* protocolErrors);
-    static String getString(JSONObject* object, const char* name, bool* valueFound, JSONArray* protocolErrors);
-    static bool getBoolean(JSONObject* object, const char* name, bool* valueFound, JSONArray* protocolErrors);
-    static PassRefPtr<JSONObject> getObject(JSONObject* object, const char* name, bool* valueFound, JSONArray* protocolErrors);
-    static PassRefPtr<JSONArray> getArray(JSONObject* object, const char* name, bool* valueFound, JSONArray* protocolErrors);
-
-    void sendResponse(int sessionId, int callId, ErrorString invocationError, PassRefPtr<JSONObject> result)
-    {
-        sendResponse(sessionId, callId, invocationError, RefPtr<JSONValue>(), result);
-    }
-    void sendResponse(int sessionId, int callId, ErrorString invocationError)
-    {
-        sendResponse(sessionId, callId, invocationError, RefPtr<JSONValue>(), JSONObject::create());
-    }
-    static const char InvalidParamsFormatString[];
-
-    DispatchMap m_dispatchMap;
-    Vector<int> m_commonErrors;
-};
-
-const char DispatcherImpl::InvalidParamsFormatString[] = "Some arguments of method '%s' can't be processed";
-
-$methods
-
-PassRefPtr<Dispatcher> Dispatcher::create(FrontendChannel* frontendChannel)
-{
-    return adoptRef(new DispatcherImpl(frontendChannel));
-}
-
-
-void DispatcherImpl::dispatch(int sessionId, const String& message)
-{
-    RefPtr<Dispatcher> protect(this);
-    int callId = 0;
-    RefPtr<JSONValue> parsedMessage = parseJSON(message);
-    ASSERT(parsedMessage);
-    RefPtr<JSONObject> messageObject = parsedMessage->asObject();
-    ASSERT(messageObject);
-
-    RefPtr<JSONValue> callIdValue = messageObject->get("id");
-    bool success = callIdValue->asNumber(&callId);
-    ASSERT_UNUSED(success, success);
-
-    RefPtr<JSONValue> methodValue = messageObject->get("method");
-    String method;
-    success = methodValue && methodValue->asString(&method);
-    ASSERT_UNUSED(success, success);
-
-    HashMap<String, CallHandler>::iterator it = m_dispatchMap.find(method);
-    if (it == m_dispatchMap.end()) {
-        reportProtocolError(sessionId, callId, MethodNotFound, "'" + method + "' wasn't found");
-        return;
-    }
-
-    RefPtr<JSONArray> protocolErrors = JSONArray::create();
-    ((*this).*it->value)(sessionId, callId, messageObject.get(), protocolErrors.get());
-}
-
-void DispatcherImpl::sendResponse(int sessionId, int callId, const ErrorString& invocationError, PassRefPtr<JSONValue> errorData, PassRefPtr<JSONObject> result)
-{
-    if (invocationError.length()) {
-        reportProtocolError(sessionId, callId, ServerError, invocationError, errorData);
-        return;
-    }
-
-    RefPtr<JSONObject> responseMessage = JSONObject::create();
-    responseMessage->setNumber("id", callId);
-    responseMessage->setObject("result", result);
-    if (m_frontendChannel)
-        m_frontendChannel->sendProtocolResponse(sessionId, callId, responseMessage.release());
-}
-
-void Dispatcher::reportProtocolError(int sessionId, int callId, CommonErrorCode code, const String& errorMessage) const
-{
-    reportProtocolError(sessionId, callId, code, errorMessage, PassRefPtr<JSONValue>());
-}
-
-void DispatcherImpl::reportProtocolError(int sessionId, int callId, CommonErrorCode code, const String& errorMessage, PassRefPtr<JSONValue> data) const
-{
-    ASSERT(code >=0);
-    ASSERT((unsigned)code < m_commonErrors.size());
-    ASSERT(m_commonErrors[code]);
-    RefPtr<JSONObject> error = JSONObject::create();
-    error->setNumber("code", m_commonErrors[code]);
-    error->setString("message", errorMessage);
-    ASSERT(error);
-    if (data)
-        error->setValue("data", data);
-    RefPtr<JSONObject> message = JSONObject::create();
-    message->setObject("error", error);
-    message->setNumber("id", callId);
-    if (m_frontendChannel)
-        m_frontendChannel->sendProtocolResponse(sessionId, callId, message.release());
-}
-
-template<typename R, typename V, typename V0>
-R DispatcherImpl::getPropertyValueImpl(JSONObject* object, const char* name, bool* valueFound, JSONArray* protocolErrors, V0 initial_value, bool (*as_method)(JSONValue*, V*), const char* type_name)
-{
-    ASSERT(protocolErrors);
-
-    if (valueFound)
-        *valueFound = false;
-
-    V value = initial_value;
-
-    if (!object) {
-        if (!valueFound) {
-            // Required parameter in missing params container.
-            protocolErrors->pushString(String::format("'params' object must contain required parameter '%s' with type '%s'.", name, type_name));
-        }
-        return value;
-    }
-
-    JSONObject::const_iterator end = object->end();
-    JSONObject::const_iterator valueIterator = object->find(name);
-
-    if (valueIterator == end) {
-        if (!valueFound)
-            protocolErrors->pushString(String::format("Parameter '%s' with type '%s' was not found.", name, type_name));
-        return value;
-    }
-
-    if (!as_method(valueIterator->value.get(), &value))
-        protocolErrors->pushString(String::format("Parameter '%s' has wrong type. It must be '%s'.", name, type_name));
-    else
-        if (valueFound)
-            *valueFound = true;
-    return value;
-}
-
-struct AsMethodBridges {
-    static bool asInt(JSONValue* value, int* output) { return value->asNumber(output); }
-    static bool asDouble(JSONValue* value, double* output) { return value->asNumber(output); }
-    static bool asString(JSONValue* value, String* output) { return value->asString(output); }
-    static bool asBoolean(JSONValue* value, bool* output) { return value->asBoolean(output); }
-    static bool asObject(JSONValue* value, RefPtr<JSONObject>* output) { return value->asObject(output); }
-    static bool asArray(JSONValue* value, RefPtr<JSONArray>* output) { return value->asArray(output); }
-};
-
-int DispatcherImpl::getInt(JSONObject* object, const char* name, bool* valueFound, JSONArray* protocolErrors)
-{
-    return getPropertyValueImpl<int, int, int>(object, name, valueFound, protocolErrors, 0, AsMethodBridges::asInt, "Number");
-}
-
-double DispatcherImpl::getDouble(JSONObject* object, const char* name, bool* valueFound, JSONArray* protocolErrors)
-{
-    return getPropertyValueImpl<double, double, double>(object, name, valueFound, protocolErrors, 0, AsMethodBridges::asDouble, "Number");
-}
-
-String DispatcherImpl::getString(JSONObject* object, const char* name, bool* valueFound, JSONArray* protocolErrors)
-{
-    return getPropertyValueImpl<String, String, String>(object, name, valueFound, protocolErrors, "", AsMethodBridges::asString, "String");
-}
-
-bool DispatcherImpl::getBoolean(JSONObject* object, const char* name, bool* valueFound, JSONArray* protocolErrors)
-{
-    return getPropertyValueImpl<bool, bool, bool>(object, name, valueFound, protocolErrors, false, AsMethodBridges::asBoolean, "Boolean");
-}
-
-PassRefPtr<JSONObject> DispatcherImpl::getObject(JSONObject* object, const char* name, bool* valueFound, JSONArray* protocolErrors)
-{
-    return getPropertyValueImpl<PassRefPtr<JSONObject>, RefPtr<JSONObject>, JSONObject*>(object, name, valueFound, protocolErrors, 0, AsMethodBridges::asObject, "Object");
-}
-
-PassRefPtr<JSONArray> DispatcherImpl::getArray(JSONObject* object, const char* name, bool* valueFound, JSONArray* protocolErrors)
-{
-    return getPropertyValueImpl<PassRefPtr<JSONArray>, RefPtr<JSONArray>, JSONArray*>(object, name, valueFound, protocolErrors, 0, AsMethodBridges::asArray, "Array");
-}
-
-bool Dispatcher::getCommandName(const String& message, String* result)
-{
-    RefPtr<JSONValue> value = parseJSON(message);
-    if (!value)
-        return false;
-
-    RefPtr<JSONObject> object = value->asObject();
-    if (!object)
-        return false;
-
-    if (!object->getString("method", result))
-        return false;
-
-    return true;
-}
-
-Dispatcher::CallbackBase::CallbackBase(PassRefPtr<DispatcherImpl> backendImpl, int sessionId, int id)
-    : m_backendImpl(backendImpl), m_sessionId(sessionId), m_id(id), m_alreadySent(false) {}
-
-Dispatcher::CallbackBase::~CallbackBase() {}
-
-void Dispatcher::CallbackBase::sendFailure(const ErrorString& error)
-{
-    ASSERT(error.length());
-    sendIfActive(nullptr, error, PassRefPtr<JSONValue>());
-}
-
-bool Dispatcher::CallbackBase::isActive()
-{
-    return !m_alreadySent && m_backendImpl->isActive();
-}
-
-void Dispatcher::CallbackBase::sendIfActive(PassRefPtr<JSONObject> partialMessage, const ErrorString& invocationError, PassRefPtr<JSONValue> errorData)
-{
-    if (m_alreadySent)
-        return;
-    m_backendImpl->sendResponse(m_sessionId, m_id, invocationError, errorData, partialMessage);
-    m_alreadySent = true;
-}
-
-} // namespace protocol
-} // namespace blink
-
-""")
-
-frontend_cpp = (
-"""
-
-#include "platform/inspector_protocol/Frontend.h"
-
-#include "platform/JSONValues.h"
-#include "platform/inspector_protocol/FrontendChannel.h"
-#include "wtf/text/CString.h"
-#include "wtf/text/WTFString.h"
-
-namespace blink {
-namespace protocol {
-
-Frontend::Frontend(FrontendChannel* frontendChannel)
-    : m_frontendChannel(frontendChannel)
-    , $constructorInit
-{
-}
-
-$methods
-
-} // namespace protocol
-} // namespace blink
-
-""")
-
-typebuilder_h = (
-"""
-#ifndef TypeBuilder_h
-#define TypeBuilder_h
-
-#include "platform/JSONValues.h"
-#include "platform/PlatformExport.h"
-#include "wtf/Assertions.h"
-#include "wtf/PassRefPtr.h"
-
-namespace blink {
-namespace protocol {
-
-namespace TypeBuilder {
-
-template<typename T>
-class OptOutput {
-public:
-    OptOutput() : m_assigned(false) { }
-
-    void operator=(T value)
-    {
-        m_value = value;
-        m_assigned = true;
-    }
-
-    bool isAssigned() { return m_assigned; }
-
-    T getValue()
-    {
-        ASSERT(isAssigned());
-        return m_value;
-    }
-
-private:
-    T m_value;
-    bool m_assigned;
-
-    WTF_MAKE_NONCOPYABLE(OptOutput);
-};
-
-class RuntimeCastHelper {
-public:
-#if $validatorIfdefName
-    template<JSONValue::Type TYPE>
-    static void assertType(JSONValue* value)
-    {
-        ASSERT(value->type() == TYPE);
-    }
-    static void assertAny(JSONValue*);
-    static void assertInt(JSONValue* value);
-#endif
-};
-
-
-// This class provides "Traits" type for the input type T. It is programmed using C++ template specialization
-// technique. By default it simply takes "ItemTraits" type from T, but it doesn't work with the base types.
-template<typename T>
-struct ArrayItemHelper {
-    typedef typename T::ItemTraits Traits;
-};
-
-template<typename T>
-class Array : public JSONArrayBase {
-private:
-    Array() { }
-
-    JSONArray* openAccessors() {
-        static_assert(sizeof(JSONArray) == sizeof(Array<T>), "JSONArray should be the same size as Array<T>");
-        return static_cast<JSONArray*>(static_cast<JSONArrayBase*>(this));
-    }
-
-public:
-    void addItem(PassRefPtr<T> value)
-    {
-        ArrayItemHelper<T>::Traits::pushRefPtr(this->openAccessors(), value);
-    }
-
-    void addItem(T value)
-    {
-        ArrayItemHelper<T>::Traits::pushRaw(this->openAccessors(), value);
-    }
-
-    static PassRefPtr<Array<T>> create()
-    {
-        return adoptRef(new Array<T>());
-    }
-
-    static PassRefPtr<Array<T>> runtimeCast(PassRefPtr<JSONValue> value)
-    {
-        RefPtr<JSONArray> array;
-        bool castRes = value->asArray(&array);
-        ASSERT_UNUSED(castRes, castRes);
-#if $validatorIfdefName
-        assertCorrectValue(array.get());
-#endif  // $validatorIfdefName
-        static_assert(sizeof(Array<T>) == sizeof(JSONArray), "Array<T> should be the same size as JSONArray");
-        return static_cast<Array<T>*>(static_cast<JSONArrayBase*>(array.get()));
-    }
-
-    void concat(PassRefPtr<Array<T>> array)
-    {
-        return ArrayItemHelper<T>::Traits::concat(this->openAccessors(), array->openAccessors());
-    }
-
-#if $validatorIfdefName
-    static void assertCorrectValue(JSONValue* value)
-    {
-        RefPtr<JSONArray> array;
-        bool castRes = value->asArray(&array);
-        ASSERT_UNUSED(castRes, castRes);
-        for (unsigned i = 0; i < array->length(); i++)
-            ArrayItemHelper<T>::Traits::template assertCorrectValue<T>(array->get(i).get());
-    }
-
-#endif // $validatorIfdefName
-};
-
-struct StructItemTraits {
-    static void pushRefPtr(JSONArray* array, PassRefPtr<JSONValue> value)
-    {
-        array->pushValue(value);
-    }
-
-    static void concat(JSONArray* array, JSONArray* anotherArray)
-    {
-        for (JSONArray::iterator it = anotherArray->begin(); it != anotherArray->end(); ++it)
-            array->pushValue(*it);
-    }
-
-#if $validatorIfdefName
-    template<typename T>
-    static void assertCorrectValue(JSONValue* value) {
-        T::assertCorrectValue(value);
-    }
-#endif  // $validatorIfdefName
-};
-
-template<>
-struct ArrayItemHelper<String> {
-    struct Traits {
-        static void pushRaw(JSONArray* array, const String& value)
-        {
-            array->pushString(value);
-        }
-
-#if $validatorIfdefName
-        template<typename T>
-        static void assertCorrectValue(JSONValue* value) {
-            RuntimeCastHelper::assertType<JSONValue::TypeString>(value);
-        }
-#endif  // $validatorIfdefName
-    };
-};
-
-template<>
-struct ArrayItemHelper<int> {
-    struct Traits {
-        static void pushRaw(JSONArray* array, int value)
-        {
-            array->pushInt(value);
-        }
-
-#if $validatorIfdefName
-        template<typename T>
-        static void assertCorrectValue(JSONValue* value) {
-            RuntimeCastHelper::assertInt(value);
-        }
-#endif  // $validatorIfdefName
-    };
-};
-
-template<>
-struct ArrayItemHelper<double> {
-    struct Traits {
-        static void pushRaw(JSONArray* array, double value)
-        {
-            array->pushNumber(value);
-        }
-
-#if $validatorIfdefName
-        template<typename T>
-        static void assertCorrectValue(JSONValue* value) {
-            RuntimeCastHelper::assertType<JSONValue::TypeNumber>(value);
-        }
-#endif  // $validatorIfdefName
-    };
-};
-
-template<>
-struct ArrayItemHelper<bool> {
-    struct Traits {
-        static void pushRaw(JSONArray* array, bool value)
-        {
-            array->pushBoolean(value);
-        }
-
-#if $validatorIfdefName
-        template<typename T>
-        static void assertCorrectValue(JSONValue* value) {
-            RuntimeCastHelper::assertType<JSONValue::TypeBoolean>(value);
-        }
-#endif  // $validatorIfdefName
-    };
-};
-
-template<>
-struct ArrayItemHelper<JSONValue> {
-    struct Traits {
-        static void pushRefPtr(JSONArray* array, PassRefPtr<JSONValue> value)
-        {
-            array->pushValue(value);
-        }
-
-#if $validatorIfdefName
-        template<typename T>
-        static void assertCorrectValue(JSONValue* value) {
-            RuntimeCastHelper::assertAny(value);
-        }
-#endif  // $validatorIfdefName
-    };
-};
-
-template<>
-struct ArrayItemHelper<JSONObject> {
-    struct Traits {
-        static void pushRefPtr(JSONArray* array, PassRefPtr<JSONValue> value)
-        {
-            array->pushValue(value);
-        }
-
-#if $validatorIfdefName
-        template<typename T>
-        static void assertCorrectValue(JSONValue* value) {
-            RuntimeCastHelper::assertType<JSONValue::TypeObject>(value);
-        }
-#endif  // $validatorIfdefName
-    };
-};
-
-template<>
-struct ArrayItemHelper<JSONArray> {
-    struct Traits {
-        static void pushRefPtr(JSONArray* array, PassRefPtr<JSONArray> value)
-        {
-            array->pushArray(value);
-        }
-
-#if $validatorIfdefName
-        template<typename T>
-        static void assertCorrectValue(JSONValue* value) {
-            RuntimeCastHelper::assertType<JSONValue::TypeArray>(value);
-        }
-#endif  // $validatorIfdefName
-    };
-};
-
-template<typename T>
-struct ArrayItemHelper<protocol::TypeBuilder::Array<T>> {
-    struct Traits {
-        static void pushRefPtr(JSONArray* array, PassRefPtr<protocol::TypeBuilder::Array<T>> value)
-        {
-            array->pushValue(value);
-        }
-
-#if $validatorIfdefName
-        template<typename S>
-        static void assertCorrectValue(JSONValue* value) {
-            S::assertCorrectValue(value);
-        }
-#endif  // $validatorIfdefName
-    };
-};
-
-${forwards}
-
-PLATFORM_EXPORT String getEnumConstantValue(int code);
-
-${typeBuilders}
-} // namespace TypeBuilder
-
-} // namespace protocol
-} // namespace blink
-
-#endif // !defined(TypeBuilder_h)
-
-""")
-
-typebuilder_cpp = (
-"""
-
-#include "platform/inspector_protocol/TypeBuilder.h"
-#include "wtf/text/CString.h"
-
-namespace blink {
-namespace protocol {
-
-namespace TypeBuilder {
-
-const char* const enum_constant_values[] = {
-$enumConstantValues};
-
-String getEnumConstantValue(int code) {
-    return enum_constant_values[code];
-}
-
-} // namespace TypeBuilder
-
-$implCode
-
-#if $validatorIfdefName
-
-void TypeBuilder::RuntimeCastHelper::assertAny(JSONValue*)
-{
-    // No-op.
-}
-
-
-void TypeBuilder::RuntimeCastHelper::assertInt(JSONValue* value)
-{
-    double v;
-    bool castRes = value->asNumber(&v);
-    ASSERT_UNUSED(castRes, castRes);
-    ASSERT(static_cast<double>(static_cast<int>(v)) == v);
-}
-
-$validatorCode
-
-#endif // $validatorIfdefName
-
-} // namespace protocol
-} // namespace blink
-
-""")
-
-param_container_access_code = """
-    RefPtr<JSONObject> paramsContainer = requestMessageObject->getObject("params");
-    JSONObject* paramsContainerPtr = paramsContainer.get();
-"""
-
-class_binding_builder_part_1 = (
-"""        AllFieldsSet = %s
-    };
-
-    template<int STATE>
-    class Builder {
-    private:
-        RefPtr<JSONObject> m_result;
-
-        template<int STEP> Builder<STATE | STEP>& castState()
-        {
-            return *reinterpret_cast<Builder<STATE | STEP>*>(this);
-        }
-
-        Builder(PassRefPtr</*%s*/JSONObject> ptr)
-        {
-            static_assert(STATE == NoFieldsSet, "builder should not be created in non-init state");
-            m_result = ptr;
-        }
-        friend class %s;
-    public:
-""")
-
-class_binding_builder_part_2 = ("""
-        Builder<STATE | %s>& set%s(%s value)
-        {
-            static_assert(!(STATE & %s), "property %s should not be set yet");
-            m_result->set%s("%s", %s);
-            return castState<%s>();
-        }
-""")
-
-class_binding_builder_part_3 = ("""
-        operator RefPtr<%s>& ()
-        {
-            static_assert(STATE == AllFieldsSet, "state should be AllFieldsSet");
-            static_assert(sizeof(%s) == sizeof(JSONObject), "%s should be the same size as JSONObject");
-            return *reinterpret_cast<RefPtr<%s>*>(&m_result);
-        }
-
-        PassRefPtr<%s> release()
-        {
-            return RefPtr<%s>(*this).release();
-        }
-    };
-
-""")
-
-class_binding_builder_part_4 = (
-"""    static Builder<NoFieldsSet> create()
-    {
-        return Builder<NoFieldsSet>(JSONObject::create());
-    }
-""")
diff --git a/Dispatcher_cpp.template b/Dispatcher_cpp.template
new file mode 100644
index 0000000..95538cf
--- /dev/null
+++ b/Dispatcher_cpp.template
@@ -0,0 +1,400 @@
+// This file is generated
+
+// Copyright (c) 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "platform/inspector_protocol/{{class_name}}.h"
+
+#include "platform/JSONParser.h"
+#include "platform/inspector_protocol/FrontendChannel.h"
+#include "wtf/text/CString.h"
+
+namespace blink {
+namespace protocol {
+
+using protocol::OptionalValue;
+
+class DispatcherImpl : public Dispatcher {
+public:
+    DispatcherImpl(FrontendChannel* frontendChannel)
+        : m_frontendChannel(frontendChannel)
+{% for domain in api.domains %}
+        , m_{{domain.domain | lower}}Agent(0)
+{% endfor %}
+    {
+{% for domain in api.domains %}
+  {% for command in domain.commands %}
+    {% if "redirect" in command %}{% continue %}{% endif %}
+    {% if "handlers" in command and not ("renderer" in command["handlers"]) %}{% continue %}{% endif %}
+        m_dispatchMap.add("{{domain.domain}}.{{command.name}}", &DispatcherImpl::{{domain.domain}}_{{command.name}});
+  {% endfor %}
+{% endfor %}
+
+        // Initialize common errors.
+        m_commonErrors.insert(ParseError, -32700);
+        m_commonErrors.insert(InvalidRequest, -32600);
+        m_commonErrors.insert(MethodNotFound, -32601);
+        m_commonErrors.insert(InvalidParams, -32602);
+        m_commonErrors.insert(InternalError, -32603);
+        m_commonErrors.insert(ServerError, -32000);
+    }
+
+    virtual void clearFrontend() { m_frontendChannel = 0; }
+    virtual void dispatch(int sessionId, const String& message);
+    virtual void reportProtocolError(int sessionId, int callId, CommonErrorCode, const String& errorMessage, PassRefPtr<JSONValue> data) const;
+    using Dispatcher::reportProtocolError;
+
+    void sendResponse(int sessionId, int callId, const ErrorString& invocationError, PassRefPtr<JSONValue> errorData, PassRefPtr<JSONObject> result);
+    bool isActive() { return m_frontendChannel; }
+
+{% for domain in api.domains %}
+    virtual void registerAgent({{domain.domain}}CommandHandler* agent) { ASSERT(!m_{{domain.domain | lower}}Agent); m_{{domain.domain | lower}}Agent = agent; }
+{% endfor %}
+
+private:
+    using CallHandler = void (DispatcherImpl::*)(int sessionId, int callId, JSONObject* messageObject, JSONArray* protocolErrors);
+    using DispatchMap = HashMap<String, CallHandler>;
+
+{% for domain in api.domains %}
+  {% for command in domain.commands %}
+    {% if "redirect" in command %}{% continue %}{% endif %}
+    {% if "handlers" in command and not ("renderer" in command["handlers"]) %}{% continue %}{% endif %}
+    void {{domain.domain}}_{{command.name}}(int sessionId, int callId, JSONObject* requestMessageObject, JSONArray* protocolErrors);
+  {% endfor %}
+{% endfor %}
+
+    FrontendChannel* m_frontendChannel;
+
+{% for domain in api.domains %}
+    {{domain.domain}}CommandHandler* m_{{domain.domain | lower}}Agent;
+{% endfor %}
+
+    template<typename R, typename V, typename V0>
+    static R getPropertyValueImpl(JSONObject* object, const char* name, bool* valueFound, JSONArray* protocolErrors, V0 initial_value, bool (*as_method)(JSONValue*, V*), const char* type_name);
+
+    static OptionalValue<int> getInteger(JSONObject* object, const char* name, bool isOptional, JSONArray* protocolErrors);
+    static OptionalValue<double> getNumber(JSONObject* object, const char* name, bool isOptional, JSONArray* protocolErrors);
+    static OptionalValue<String> getString(JSONObject* object, const char* name, bool isOptional, JSONArray* protocolErrors);
+    static OptionalValue<bool> getBoolean(JSONObject* object, const char* name, bool isOptional, JSONArray* protocolErrors);
+    static PassRefPtr<JSONObject> getObject(JSONObject* object, const char* name, bool isOptional, JSONArray* protocolErrors);
+    static PassRefPtr<JSONArray> getArray(JSONObject* object, const char* name, bool isOptional, JSONArray* protocolErrors);
+
+    void sendResponse(int sessionId, int callId, ErrorString invocationError, PassRefPtr<JSONObject> result)
+    {
+        sendResponse(sessionId, callId, invocationError, RefPtr<JSONValue>(), result);
+    }
+
+    void sendResponse(int sessionId, int callId, ErrorString invocationError)
+    {
+        sendResponse(sessionId, callId, invocationError, RefPtr<JSONValue>(), JSONObject::create());
+    }
+
+    static const char InvalidParamsFormatString[];
+
+    DispatchMap m_dispatchMap;
+    Vector<int> m_commonErrors;
+};
+
+const char DispatcherImpl::InvalidParamsFormatString[] = "Some arguments of method '%s' can't be processed";
+{% for domain in api.domains %}
+  {% for command in domain.commands %}
+    {% if "redirect" in command %}{% continue %}{% endif %}
+    {% if "handlers" in command and not ("renderer" in command["handlers"]) %}{% continue %}{% endif %}
+
+    {% if "async" in command %}
+Dispatcher::{{domain.domain}}CommandHandler::{{command.name | to_title_case}}Callback::{{command.name | to_title_case}}Callback(PassRefPtr<DispatcherImpl> backendImpl, int sessionId, int id) : CallbackBase(backendImpl, sessionId, id) { }
+
+void Dispatcher::{{domain.domain}}CommandHandler::{{command.name | to_title_case}}Callback::sendSuccess(
+      {%- for parameter in command.returns -%}
+        {%- if "optional" in parameter -%}
+        {{resolve_type(parameter).optional_pass_type}} {{parameter.name}}
+        {%- else -%}
+        {{resolve_type(parameter).pass_type}} {{parameter.name}}
+        {%- endif -%}
+        {%- if not loop.last -%}, {% endif -%}
+      {% endfor %})
+{
+    RefPtr<JSONObject> resultObject = JSONObject::create();
+      {% for parameter in command.returns %}
+        {% if "optional" in parameter %}
+    {{resolve_type(parameter).optional_type}} opt_{{parameter.name}} = {{parameter.name}};
+    if (hasValue({{parameter.name}}))
+        resultObject->setValue("{{parameter.name}}", toValue({{resolve_type(parameter).from_optional_out % ("opt_" + parameter.name)}}));
+       {% else %}
+    resultObject->setValue("{{parameter.name}}", toValue({{parameter.name}}));
+        {% endif %}
+      {% endfor %}
+    sendIfActive(resultObject.release(), ErrorString(), PassRefPtr<JSONValue>());
+}
+    {% endif %}
+
+void DispatcherImpl::{{domain.domain}}_{{command.name}}(int sessionId, int callId, JSONObject* requestMessageObject, JSONArray* protocolErrors)
+{
+    if (!m_{{domain.domain | lower}}Agent)
+        protocolErrors->pushString("Inspector handler is not available.");
+
+    if (protocolErrors->length()) {
+        reportProtocolError(sessionId, callId, InvalidParams, String::format(InvalidParamsFormatString, "{{domain.domain}}.{{command.name}}"), protocolErrors);
+        return;
+    }
+
+    {% if "parameters" in command %}
+    // Prepare input parameters.
+    RefPtr<JSONObject> paramsContainer = requestMessageObject->getObject("params");
+    JSONObject* paramsContainerPtr = paramsContainer.get();
+      {% for property in command.parameters %}
+    {{resolve_type(property).optional_type}} in_{{property.name}} = {{resolve_type(property).json_getter % ("paramsContainerPtr, \"" + property.name + "\", " + ("true" if "optional" in property else "false") + ", protocolErrors")}};
+      {% endfor %}
+    {% endif %}
+
+    if (protocolErrors->length()) {
+        reportProtocolError(sessionId, callId, InvalidParams, String::format(InvalidParamsFormatString, "{{domain.domain}}.{{command.name}}"), protocolErrors);
+        return;
+    }
+
+    {% if "async" in command %}
+    RefPtr<{{domain.domain}}CommandHandler::{{command.name | to_title_case}}Callback> callback = adoptRef(new {{domain.domain}}CommandHandler::{{command.name | to_title_case}}Callback(this, sessionId, callId));
+    {% elif "returns" in command %}
+    // Declare output parameters.
+    RefPtr<JSONObject> result = JSONObject::create();
+      {% for property in command.returns %}
+        {% if "optional" in property %}
+    {{resolve_type(property).optional_type}} out_{{property.name}};
+        {% else %}
+    {{resolve_type(property).type}} out_{{property.name}};
+        {% endif %}
+      {% endfor %}
+    {% endif %}
+
+    ErrorString error;
+    m_{{domain.domain | lower}}Agent->{{command.name}}(&error
+      {%- for property in command.parameters -%}
+        {%- if "optional" in property -%}
+        , {{resolve_type(property).to_pass_type % ("in_" + property.name)}}
+        {%- else -%}
+        , {{resolve_type(property).from_optional_out % ("in_" + property.name)}}
+        {%- endif -%}
+      {%- endfor %}
+      {%- if "async" in command -%}
+        , callback.release()
+      {%- elif "returns" in command %}
+        {%- for property in command.returns -%}
+          , &out_{{property.name}}
+        {%- endfor %}
+      {% endif %});
+    {% if "returns" in command and not("async" in command) %}
+    if (!error.length()) {
+      {% for parameter in command.returns %}
+        {% if "optional" in parameter %}
+        if (hasValue(out_{{parameter.name}}))
+            result->setValue("{{parameter.name}}", toValue({{resolve_type(parameter).from_optional_out % ("out_" + parameter.name)}}));
+        {% else %}
+        result->setValue("{{parameter.name}}", toValue(out_{{resolve_type(parameter).to_pass_type % parameter.name}}));
+        {% endif %}
+      {% endfor %}
+    }
+    sendResponse(sessionId, callId, error, result);
+    {% elif not("async" in command) %}
+    sendResponse(sessionId, callId, error);
+    {% endif %}
+}
+  {% endfor %}
+{% endfor %}
+
+PassRefPtr<Dispatcher> Dispatcher::create(FrontendChannel* frontendChannel)
+{
+    return adoptRef(new DispatcherImpl(frontendChannel));
+}
+
+void DispatcherImpl::dispatch(int sessionId, const String& message)
+{
+    RefPtr<Dispatcher> protect(this);
+    int callId = 0;
+    RefPtr<JSONValue> parsedMessage = parseJSON(message);
+    ASSERT(parsedMessage);
+    RefPtr<JSONObject> messageObject = parsedMessage->asObject();
+    ASSERT(messageObject);
+
+    RefPtr<JSONValue> callIdValue = messageObject->get("id");
+    bool success = callIdValue->asNumber(&callId);
+    ASSERT_UNUSED(success, success);
+
+    RefPtr<JSONValue> methodValue = messageObject->get("method");
+    String method;
+    success = methodValue && methodValue->asString(&method);
+    ASSERT_UNUSED(success, success);
+
+    HashMap<String, CallHandler>::iterator it = m_dispatchMap.find(method);
+    if (it == m_dispatchMap.end()) {
+        reportProtocolError(sessionId, callId, MethodNotFound, "'" + method + "' wasn't found");
+        return;
+    }
+
+    RefPtr<JSONArray> protocolErrors = JSONArray::create();
+    ((*this).*it->value)(sessionId, callId, messageObject.get(), protocolErrors.get());
+}
+
+void DispatcherImpl::sendResponse(int sessionId, int callId, const ErrorString& invocationError, PassRefPtr<JSONValue> errorData, PassRefPtr<JSONObject> result)
+{
+    if (invocationError.length()) {
+        reportProtocolError(sessionId, callId, ServerError, invocationError, errorData);
+        return;
+    }
+
+    RefPtr<JSONObject> responseMessage = JSONObject::create();
+    responseMessage->setNumber("id", callId);
+    responseMessage->setObject("result", result);
+    if (m_frontendChannel)
+        m_frontendChannel->sendProtocolResponse(sessionId, callId, responseMessage.release());
+}
+
+void Dispatcher::reportProtocolError(int sessionId, int callId, CommonErrorCode code, const String& errorMessage) const
+{
+    reportProtocolError(sessionId, callId, code, errorMessage, PassRefPtr<JSONValue>());
+}
+
+void DispatcherImpl::reportProtocolError(int sessionId, int callId, CommonErrorCode code, const String& errorMessage, PassRefPtr<JSONValue> data) const
+{
+    ASSERT(code >=0);
+    ASSERT((unsigned)code < m_commonErrors.size());
+    ASSERT(m_commonErrors[code]);
+    RefPtr<JSONObject> error = JSONObject::create();
+    error->setNumber("code", m_commonErrors[code]);
+    error->setString("message", errorMessage);
+    ASSERT(error);
+    if (data)
+        error->setValue("data", data);
+    RefPtr<JSONObject> message = JSONObject::create();
+    message->setObject("error", error);
+    message->setNumber("id", callId);
+    if (m_frontendChannel)
+        m_frontendChannel->sendProtocolResponse(sessionId, callId, message.release());
+}
+
+template<typename R, typename V, typename V0>
+R DispatcherImpl::getPropertyValueImpl(JSONObject* object, const char* name, bool* valueFound, JSONArray* protocolErrors, V0 initial_value, bool (*as_method)(JSONValue*, V*), const char* type_name)
+{
+    ASSERT(protocolErrors);
+
+    if (valueFound)
+        *valueFound = false;
+
+    V value = initial_value;
+
+    if (!object) {
+        if (!valueFound) {
+            // Required parameter in missing params container.
+            protocolErrors->pushString(String::format("'params' object must contain required parameter '%s' with type '%s'.", name, type_name));
+        }
+        return value;
+    }
+
+    JSONObject::const_iterator end = object->end();
+    JSONObject::const_iterator valueIterator = object->find(name);
+
+    if (valueIterator == end) {
+        if (!valueFound)
+            protocolErrors->pushString(String::format("Parameter '%s' with type '%s' was not found.", name, type_name));
+        return value;
+    }
+
+    if (!as_method(valueIterator->value.get(), &value))
+        protocolErrors->pushString(String::format("Parameter '%s' has wrong type. It must be '%s'.", name, type_name));
+    else
+        if (valueFound)
+            *valueFound = true;
+    return value;
+}
+
+struct AsMethodBridges {
+    static bool asInteger(JSONValue* value, int* output) { return value->asNumber(output); }
+    static bool asNumber(JSONValue* value, double* output) { return value->asNumber(output); }
+    static bool asString(JSONValue* value, String* output) { return value->asString(output); }
+    static bool asBoolean(JSONValue* value, bool* output) { return value->asBoolean(output); }
+    static bool asObject(JSONValue* value, RefPtr<JSONObject>* output) { return value->asObject(output); }
+    static bool asArray(JSONValue* value, RefPtr<JSONArray>* output) { return value->asArray(output); }
+};
+
+OptionalValue<int> DispatcherImpl::getInteger(JSONObject* object, const char* name, bool isOptional, JSONArray* protocolErrors)
+{
+    bool valueFound = false;
+    int result = getPropertyValueImpl<int, int, int>(object, name, isOptional ? &valueFound : 0, protocolErrors, 0, AsMethodBridges::asInteger, "Number");
+    return valueFound || !isOptional ? OptionalValue<int>(result) : OptionalValue<int>();
+}
+
+OptionalValue<double> DispatcherImpl::getNumber(JSONObject* object, const char* name, bool isOptional, JSONArray* protocolErrors)
+{
+    bool valueFound = false;
+    double result = getPropertyValueImpl<double, double, double>(object, name, isOptional ? &valueFound : 0, protocolErrors, 0, AsMethodBridges::asNumber, "Number");
+    return valueFound || !isOptional ? OptionalValue<double>(result) : OptionalValue<double>();
+}
+
+OptionalValue<String> DispatcherImpl::getString(JSONObject* object, const char* name, bool isOptional, JSONArray* protocolErrors)
+{
+    bool valueFound = false;
+    String result = getPropertyValueImpl<String, String, String>(object, name, isOptional ? &valueFound : 0, protocolErrors, "", AsMethodBridges::asString, "String");
+    return valueFound || !isOptional ? OptionalValue<String>(result) : OptionalValue<String>();
+}
+
+OptionalValue<bool> DispatcherImpl::getBoolean(JSONObject* object, const char* name, bool isOptional, JSONArray* protocolErrors)
+{
+    bool valueFound = false;
+    bool result = getPropertyValueImpl<bool, bool, bool>(object, name, isOptional ? &valueFound : 0, protocolErrors, false, AsMethodBridges::asBoolean, "Boolean");
+    return valueFound || !isOptional ? OptionalValue<bool>(result) : OptionalValue<bool>();
+}
+
+PassRefPtr<JSONObject> DispatcherImpl::getObject(JSONObject* object, const char* name, bool isOptional, JSONArray* protocolErrors)
+{
+    bool valueFound = false;
+    return getPropertyValueImpl<PassRefPtr<JSONObject>, RefPtr<JSONObject>, JSONObject*>(object, name, isOptional ? &valueFound : 0, protocolErrors, 0, AsMethodBridges::asObject, "Object");
+}
+
+PassRefPtr<JSONArray> DispatcherImpl::getArray(JSONObject* object, const char* name, bool isOptional, JSONArray* protocolErrors)
+{
+    bool valueFound = false;
+    return getPropertyValueImpl<PassRefPtr<JSONArray>, RefPtr<JSONArray>, JSONArray*>(object, name, isOptional ? &valueFound : 0, protocolErrors, 0, AsMethodBridges::asArray, "Array");
+}
+
+bool Dispatcher::getCommandName(const String& message, String* result)
+{
+    RefPtr<JSONValue> value = parseJSON(message);
+    if (!value)
+        return false;
+
+    RefPtr<JSONObject> object = value->asObject();
+    if (!object)
+        return false;
+
+    if (!object->getString("method", result))
+        return false;
+
+    return true;
+}
+
+Dispatcher::CallbackBase::CallbackBase(PassRefPtr<DispatcherImpl> backendImpl, int sessionId, int id)
+    : m_backendImpl(backendImpl), m_sessionId(sessionId), m_id(id), m_alreadySent(false) { }
+
+Dispatcher::CallbackBase::~CallbackBase() { }
+
+void Dispatcher::CallbackBase::sendFailure(const ErrorString& error)
+{
+    ASSERT(error.length());
+    sendIfActive(nullptr, error, PassRefPtr<JSONValue>());
+}
+
+bool Dispatcher::CallbackBase::isActive()
+{
+    return !m_alreadySent && m_backendImpl->isActive();
+}
+
+void Dispatcher::CallbackBase::sendIfActive(PassRefPtr<JSONObject> partialMessage, const ErrorString& invocationError, PassRefPtr<JSONValue> errorData)
+{
+    if (m_alreadySent)
+        return;
+    m_backendImpl->sendResponse(m_sessionId, m_id, invocationError, errorData, partialMessage);
+    m_alreadySent = true;
+}
+
+} // namespace protocol
+} // namespace blink
diff --git a/Dispatcher_h.template b/Dispatcher_h.template
new file mode 100644
index 0000000..e0cc255
--- /dev/null
+++ b/Dispatcher_h.template
@@ -0,0 +1,121 @@
+// This file is generated
+
+// Copyright (c) 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef {{class_name}}_h
+#define {{class_name}}_h
+
+#include "platform/inspector_protocol/TypeBuilder.h"
+
+namespace blink {
+namespace protocol {
+
+class FrontendChannel;
+class DispatcherImpl;
+using ErrorString = String;
+
+class PLATFORM_EXPORT Dispatcher: public RefCounted<Dispatcher> {
+public:
+    static PassRefPtr<Dispatcher> create(FrontendChannel* frontendChannel);
+    virtual ~Dispatcher() { }
+
+    class PLATFORM_EXPORT CallbackBase: public RefCounted<CallbackBase> {
+    public:
+        CallbackBase(PassRefPtr<DispatcherImpl> backendImpl, int sessionId, int id);
+        virtual ~CallbackBase();
+        void sendFailure(const ErrorString&);
+        bool isActive();
+
+    protected:
+        void sendIfActive(PassRefPtr<JSONObject> partialMessage, const ErrorString& invocationError, PassRefPtr<JSONValue> errorData);
+
+    private:
+        void disable() { m_alreadySent = true; }
+
+        RefPtr<DispatcherImpl> m_backendImpl;
+        int m_sessionId;
+        int m_id;
+        bool m_alreadySent;
+
+        friend class DispatcherImpl;
+    };
+
+{% for domain in api.domains %}
+    class PLATFORM_EXPORT {{domain.domain}}CommandHandler {
+    public:
+  {% for command in domain.commands %}
+    {% if "redirect" in command %}{% continue %}{% endif %}
+    {% if ("handlers" in command) and not ("renderer" in command["handlers"]) %}{% continue %}{% endif %}
+    {% if "async" in command %}
+        class PLATFORM_EXPORT {{command.name | to_title_case}}Callback : public CallbackBase {
+        public:
+            {{command.name | to_title_case}}Callback(PassRefPtr<DispatcherImpl>, int sessionId, int id);
+            void sendSuccess(
+            {%- for parameter in command.returns -%}
+              {%- if "optional" in parameter -%}
+                {{resolve_type(parameter).optional_pass_type}} {{parameter.name}}
+              {%- else -%}
+                {{resolve_type(parameter).pass_type}} {{parameter.name}}
+              {%- endif -%}
+              {%- if not loop.last -%}, {% endif -%}
+            {%- endfor -%}
+            );
+        };
+    {% endif %}
+        virtual void {{command.name}}(ErrorString*
+    {%- for parameter in command.parameters -%}
+        {%- if "optional" in parameter -%}
+            , {{resolve_type(parameter).optional_pass_type}} in_{{parameter.name}}
+        {%- else -%}
+            , {{resolve_type(parameter).pass_type}} in_{{parameter.name}}
+        {%- endif -%}
+    {%- endfor -%}
+    {%- if "async" in command -%}
+            , PassRefPtr<{{command.name | to_title_case}}Callback> callback
+    {%- else -%}
+      {%- for parameter in command.returns -%}
+        {%- if "optional" in parameter -%}
+            , {{resolve_type(parameter).optional_type}}* out_{{parameter.name}}
+        {%- else -%}
+            , {{resolve_type(parameter).type}}* out_{{parameter.name}}
+        {%- endif -%}
+      {%- endfor -%}
+    {%- endif -%}
+        ) = 0;
+  {% endfor %}
+
+    protected:
+        virtual ~{{domain.domain}}CommandHandler() { }
+    };
+{% endfor %}
+
+{% for domain in api.domains %}
+    virtual void registerAgent({{domain.domain | to_title_case}}CommandHandler*) = 0;
+{% endfor %}
+
+    virtual void clearFrontend() = 0;
+
+    enum CommonErrorCode {
+        ParseError = 0,
+        InvalidRequest,
+        MethodNotFound,
+        InvalidParams,
+        InternalError,
+        ServerError,
+        LastEntry,
+    };
+
+    void reportProtocolError(int sessionId, int callId, CommonErrorCode, const String& errorMessage) const;
+    virtual void reportProtocolError(int sessionId, int callId, CommonErrorCode, const String& errorMessage, PassRefPtr<JSONValue> data) const = 0;
+    virtual void dispatch(int sessionId, const String& message) = 0;
+    static bool getCommandName(const String& message, String* result);
+};
+
+} // namespace protocol
+} // namespace blink
+
+using blink::protocol::ErrorString;
+
+#endif // !defined({{class_name}}_h)
diff --git a/Frontend_cpp.template b/Frontend_cpp.template
new file mode 100644
index 0000000..f68e040
--- /dev/null
+++ b/Frontend_cpp.template
@@ -0,0 +1,55 @@
+// This file is generated
+
+// Copyright (c) 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "platform/inspector_protocol/{{class_name}}.h"
+
+#include "wtf/text/CString.h"
+#include "wtf/text/WTFString.h"
+
+namespace blink {
+namespace protocol {
+
+Frontend::Frontend(FrontendChannel* frontendChannel)
+    : m_frontendChannel(frontendChannel)
+{% for domain in api.domains %}
+    , m_{{domain.domain | lower}}(frontendChannel)
+{% endfor %}
+{
+}
+
+{% for domain in api.domains %}
+  {% for event in domain.events %}
+    {% if "handlers" in event and not ("renderer" in event["handlers"]) %}{% continue %}{% endif %}
+void Frontend::{{domain.domain}}::{{event.name}}(
+    {%- for parameter in event.parameters %}
+      {% if "optional" in parameter -%}
+        {{resolve_type(parameter).optional_pass_type}}
+      {%- else -%}
+        {{resolve_type(parameter).pass_type}}
+      {%- endif %} {{parameter.name}}{%- if not loop.last -%}, {% endif -%}
+    {% endfor -%})
+{
+    RefPtr<JSONObject> jsonMessage = JSONObject::create();
+    jsonMessage->setString("method", "{{domain.domain}}.{{event.name}}");
+    RefPtr<JSONObject> paramsObject = JSONObject::create();
+    {% for parameter in event.parameters %}
+      {% if "optional" in parameter %}
+    {{resolve_type(parameter).optional_type}} opt_{{parameter.name}} = {{parameter.name}};
+    if (hasValue(opt_{{parameter.name}}))
+        paramsObject->setValue("{{parameter.name}}", toValue({{resolve_type(parameter).from_optional_out % ("opt_" + parameter.name)}}));
+      {% else %}
+    paramsObject->setValue("{{parameter.name}}", toValue({{parameter.name}}));
+      {% endif %}
+    {% endfor %}
+    jsonMessage->setObject("params", paramsObject);
+    if (m_frontendChannel)
+        m_frontendChannel->sendProtocolNotification(jsonMessage.release());
+}
+  {% endfor %}
+{% endfor %}
+
+} // namespace protocol
+} // namespace blink
diff --git a/Frontend_h.template b/Frontend_h.template
new file mode 100644
index 0000000..d0a630c
--- /dev/null
+++ b/Frontend_h.template
@@ -0,0 +1,64 @@
+// This file is generated
+
+// Copyright (c) 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef {{class_name}}_h
+#define {{class_name}}_h
+
+
+#include "platform/inspector_protocol/FrontendChannel.h"
+#include "platform/inspector_protocol/TypeBuilder.h"
+
+namespace blink {
+namespace protocol {
+
+using ErrorString = String;
+
+class PLATFORM_EXPORT Frontend {
+public:
+    Frontend(FrontendChannel*);
+    FrontendChannel* channel() { return m_frontendChannel; }
+
+{% for domain in api.domains %}
+
+    class PLATFORM_EXPORT {{domain.domain}} {
+    public:
+        static {{domain.domain}}* from(Frontend* frontend) { return &(frontend->m_{{domain.domain | lower}}) ;}
+        {{domain.domain}}(FrontendChannel* frontendChannel) : m_frontendChannel(frontendChannel) { }
+  {% for event in domain.events %}
+    {% if "handlers" in event and not ("renderer" in event["handlers"]) %}{% continue %}{% endif %}
+        void {{event.name}}(
+    {%- for parameter in event.parameters -%}
+      {%- if "optional" in parameter -%}
+            {{resolve_type(parameter).optional_pass_type}}
+        {%- if resolve_type(parameter).nullable -%}
+              {{parameter.name}} = nullptr
+        {%- else -%}
+              {{parameter.name}} = {{resolve_type(parameter).optional_type}}()
+        {%- endif %}
+      {%- else -%}
+            {{resolve_type(parameter).pass_type}} {{parameter.name}}
+      {%- endif -%}{%- if not loop.last -%}, {% endif -%}
+    {%- endfor -%}
+        );
+  {% endfor %}
+
+        void flush() { m_frontendChannel->flush(); }
+    private:
+        FrontendChannel* m_frontendChannel;
+    };
+{% endfor %}
+
+private:
+    FrontendChannel* m_frontendChannel;
+{% for domain in api.domains %}
+    {{domain.domain}} m_{{domain.domain | lower}};
+{% endfor %}
+};
+
+} // namespace protocol
+} // namespace blink
+
+#endif // !defined({{class_name}}_h)
diff --git a/TypeBuilder_cpp.template b/TypeBuilder_cpp.template
new file mode 100644
index 0000000..96db157
--- /dev/null
+++ b/TypeBuilder_cpp.template
@@ -0,0 +1,69 @@
+// This file is generated
+
+// Copyright (c) 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "platform/inspector_protocol/{{class_name}}.h"
+
+namespace blink {
+namespace protocol {
+
+template<>
+PassRefPtr<JSONValue> toValue(const String& param)
+{
+    return JSONString::create(param);
+}
+
+OptionalValue<String> optional(const String& value)
+{
+    return value.isNull() ? OptionalValue<String>() : OptionalValue<String>(value);
+}
+
+// ------------- Enum values from types.
+{% for domain in api.domains %}
+  {% for type in domain.types %}
+    {% if "enum" in type %}
+
+namespace {{domain.domain}} {
+namespace {{type.id}}Enum {
+      {% for literal in type.enum %}
+const char* {{ literal | dash_to_camelcase}} = "{{literal}}";
+      {% endfor %}
+} // {{type.id}}Enum
+} // {{domain.domain}}
+    {% endif %}
+    {% for property in type.properties %}
+      {% if "enum" in property %}
+namespace {{domain.domain}} {
+        {% for literal in property.enum %}
+const char* {{type.id}}::{{property.name | to_title_case}}Enum::{{ literal | dash_to_camelcase}} = "{{literal}}";
+        {% endfor %}
+} // {{domain.domain}}
+      {% endif %}
+    {% endfor %}
+  {% endfor %}
+{% endfor %}
+
+// ------------- Enum values from params.
+{% for domain in api.domains %}
+  {% for command in join_arrays(domain, ["commands", "events"]) %}
+    {% for param in join_arrays(command, ["parameters", "returns"]) %}
+      {% if "enum" in param %}
+
+namespace {{domain.domain}} {
+namespace {{command.name | to_title_case}} {
+namespace {{param.name | to_title_case}}Enum {
+        {% for literal in param.enum %}
+const char* {{ literal | to_title_case}} = "{{literal}}";
+        {% endfor %}
+} // {{param.name | to_title_case}}Enum
+} // {{command.name | to_title_case }}
+} // {{domain.domain}}
+      {% endif %}
+    {% endfor %}
+  {% endfor %}
+{% endfor %}
+
+} // namespace protocol
+} // namespace blink
diff --git a/TypeBuilder_h.template b/TypeBuilder_h.template
new file mode 100644
index 0000000..7374d9e
--- /dev/null
+++ b/TypeBuilder_h.template
@@ -0,0 +1,463 @@
+// This file is generated
+
+// Copyright (c) 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef {{class_name}}_h
+#define {{class_name}}_h
+
+#include "platform/JSONValues.h"
+#include "platform/PlatformExport.h"
+#include "wtf/Assertions.h"
+#include "wtf/PassOwnPtr.h"
+#include "wtf/PassRefPtr.h"
+#include "wtf/text/WTFString.h"
+
+namespace blink {
+namespace protocol {
+
+template<typename T>
+class OptionalValue {
+public:
+    OptionalValue() : m_hasValue(false) { }
+    OptionalValue(const T& value) : m_hasValue(true), m_value(value) { }
+
+    void operator=(T value)
+    {
+        m_value = value;
+        m_hasValue = true;
+    }
+
+    T get() const
+    {
+        ASSERT(m_hasValue);
+        return m_value;
+    }
+
+    T get(const T& defaultValue) const
+    {
+        return m_hasValue ? m_value : defaultValue;
+    }
+
+    bool hasValue() const
+    {
+        return m_hasValue;
+    }
+
+private:
+    bool m_hasValue;
+    T m_value;
+};
+
+template<typename T>
+OptionalValue<T> optional(const T* value)
+{
+    return value ? OptionalValue<T>(*value) : OptionalValue<T>();
+}
+
+PLATFORM_EXPORT OptionalValue<String> optional(const String& value);
+
+template<typename T>
+OptionalValue<T> optional(const T& value)
+{
+    return OptionalValue<T>(value);
+}
+
+template<typename T> class Array;
+
+template<typename T>
+bool hasValue(const protocol::OptionalValue<T>& t) { return t.hasValue(); }
+
+template<typename T>
+bool hasValue(T* value) { return !!value; }
+
+template<typename T>
+bool hasValue(const OwnPtr<T>& value) { return !!value; }
+
+template<typename T>
+bool hasValue(const PassOwnPtr<T>& value) { return !!value; }
+
+template<typename T>
+bool hasValue(const RefPtr<T>& value) { return !!value; }
+
+template<typename T>
+PassRefPtr<JSONValue> toValue(const T& param)
+{
+    return JSONBasicValue::create(param);
+}
+
+template<>
+PLATFORM_EXPORT PassRefPtr<JSONValue> toValue(const String& param);
+
+template<typename T>
+PassRefPtr<JSONValue> toValue(PassRefPtr<T> param)
+{
+    return param;
+}
+
+template<typename T>
+PassRefPtr<JSONValue> toValue(const PassOwnPtr<protocol::Array<T>> param)
+{
+    return param->asValue();
+}
+
+template<typename T>
+PassRefPtr<JSONValue> toValue(PassOwnPtr<T> param)
+{
+    return param->asValue();
+}
+
+template<typename T>
+struct FromValue
+{
+    static PassOwnPtr<T> convert(RefPtr<JSONValue> value)
+    {
+        if (!value)
+            return nullptr;
+        RefPtr<JSONObject> object;
+        bool success = value->asObject(&object);
+        ASSERT_UNUSED(success, success);
+        return T::runtimeCast(object.release());
+    }
+};
+
+template<>
+struct FromValue<bool>
+{
+    static bool convert(RefPtr<JSONValue> value)
+    {
+        bool result;
+        bool success = value->asBoolean(&result);
+        ASSERT_UNUSED(success, success);
+        return result;
+    }
+};
+
+template<>
+struct FromValue<int>
+{
+    static int convert(RefPtr<JSONValue> value)
+    {
+        int result;
+        bool success = value->asNumber(&result);
+        ASSERT_UNUSED(success, success);
+        return result;
+    }
+};
+
+template<>
+struct FromValue<double>
+{
+    static double convert(RefPtr<JSONValue> value)
+    {
+        double result;
+        bool success = value->asNumber(&result);
+        ASSERT_UNUSED(success, success);
+        return result;
+    }
+};
+
+template<>
+struct FromValue<String>
+{
+    static String convert(RefPtr<JSONValue> value)
+    {
+        String result;
+        bool success = value->asString(&result);
+        ASSERT_UNUSED(success, success);
+        return result;
+    }
+};
+
+template<typename T>
+struct FromValue<RefPtr<T>>
+{
+    static PassRefPtr<T> convert(RefPtr<T> value)
+    {
+        return value.release();
+    }
+};
+
+template<typename T>
+struct FromValue<protocol::Array<T>>
+{
+    static PassOwnPtr<protocol::Array<T>> convert(RefPtr<JSONValue> value)
+    {
+        RefPtr<JSONArray> array = value->asArray();
+        ASSERT_UNUSED(array, array);
+        return protocol::Array<T>::runtimeCast(array);
+    }
+};
+
+template<typename T>
+class ArrayBase {
+public:
+    static PassOwnPtr<Array<T>> create()
+    {
+        OwnPtr<Array<T>> result = adoptPtr(new Array<T>());
+        result->m_array = JSONArray::create();
+        return result.release();
+    }
+
+    static PassOwnPtr<Array<T>> runtimeCast(PassRefPtr<JSONArray> array)
+    {
+        if (!array)
+            return nullptr;
+        OwnPtr<Array<T>> result = adoptPtr(new Array<T>());
+        result->m_array = array;
+        return result.release();
+    }
+
+    void addItem(const T& value)
+    {
+        m_array->pushValue(toValue(value));
+    }
+
+    size_t length() { return m_array->length(); }
+
+    T get(size_t index) { return FromValue<T>::convert(m_array->get(index)); }
+    PassRefPtr<JSONArray> asValue() { return m_array; }
+
+private:
+    RefPtr<JSONArray> m_array;
+};
+
+template<> class Array<String> : public ArrayBase<String> {};
+template<> class Array<int> : public ArrayBase<int> {};
+template<> class Array<double> : public ArrayBase<double> {};
+template<> class Array<bool> : public ArrayBase<bool> {};
+template<typename T> class Array<RefPtr<T>> : public ArrayBase<RefPtr<T>> {};
+
+template<typename T>
+class Array {
+public:
+    static PassOwnPtr<Array<T>> create()
+    {
+        OwnPtr<Array<T>> result = adoptPtr(new Array<T>());
+        result->m_array = JSONArray::create();
+        return result.release();
+    }
+
+    static PassOwnPtr<Array<T>> runtimeCast(PassRefPtr<JSONArray> array)
+    {
+        if (!array)
+            return nullptr;
+        OwnPtr<Array<T>> result = adoptPtr(new Array<T>());
+        result->m_array = array;
+        return result.release();
+    }
+
+    void addItem(PassOwnPtr<T> value)
+    {
+        m_array->pushValue(toValue(value));
+    }
+
+    size_t length() { return m_array->length(); }
+
+    PassOwnPtr<T> get(size_t index) { return FromValue<T>::convert(m_array->get(index)); }
+    PassRefPtr<JSONArray> asValue() { return m_array; }
+
+private:
+    RefPtr<JSONArray> m_array;
+};
+
+{% for domain in api.domains %}
+
+// ------------- Forward declarations and typedefs.
+
+namespace {{domain.domain}} {
+  {% for type in domain.types %}
+    {% if type.type == "object" %}
+// {{type.description}}
+class {{type.id}};
+    {% elif type.type != "array" %}
+// {{type.description}}
+using {{type.id}} = {{resolve_type(type).type}};
+    {% endif %}
+  {% endfor %}
+} // {{domain.domain}}
+{% endfor %}
+
+// ------------- Enum values from types.
+{% for domain in api.domains %}
+  {% for type in domain.types %}
+    {% if "enum" in type %}
+
+namespace {{domain.domain}} {
+namespace {{type.id}}Enum {
+      {% for literal in type.enum %}
+PLATFORM_EXPORT extern const char* {{ literal | dash_to_camelcase}};
+      {% endfor %}
+} // {{type.id}}Enum
+} // {{domain.domain}}
+    {% endif %}
+  {% endfor %}
+{% endfor %}
+
+// ------------- Enum values from params.
+{% for domain in api.domains %}
+  {% for command in join_arrays(domain, ["commands", "events"]) %}
+    {% for param in join_arrays(command, ["parameters", "returns"]) %}
+      {% if "enum" in param %}
+
+namespace {{domain.domain}} {
+namespace {{command.name | to_title_case}} {
+namespace {{param.name | to_title_case}}Enum {
+        {% for literal in param.enum %}
+PLATFORM_EXPORT extern const char* {{ literal | dash_to_camelcase}};
+        {% endfor %}
+} // {{param.name | to_title_case}}Enum
+} // {{command.name | to_title_case }}
+} // {{domain.domain}}
+      {% endif %}
+    {% endfor %}
+  {% endfor %}
+{% endfor %}
+
+// ------------- Type and builder declarations.
+{% for domain in api.domains %}
+
+namespace {{domain.domain}} {
+  {% for type in domain.types %}
+    {% if type.type == "object" %}
+      {% set type_def = type_definition(domain.domain + "." + type.id)%}
+
+// {{type.description}}
+class PLATFORM_EXPORT {{type.id}} {
+public:
+    static PassOwnPtr<{{type.id}}> runtimeCast(PassRefPtr<JSONObject> object)
+    {
+        return adoptPtr(new {{type.id}}(object));
+    }
+
+    {{type.id}}() : m_object(JSONObject::create()) { }
+
+    ~{{type.id}}() { }
+      {% for property in type.properties %}
+
+        {% if "enum" in property %}
+    struct PLATFORM_EXPORT {{property.name | to_title_case}}Enum {
+          {% for literal in property.enum %}
+        static const char* {{ literal | dash_to_camelcase}};
+          {% endfor %}
+    }; // {{property.name | to_title_case}}Enum
+        {% endif %}
+
+    bool has{{property.name | to_title_case}}()
+    {
+        RefPtr<JSONValue> value = m_object->get("{{property.name}}");
+        {% if resolve_type(property).json_type %}
+        return value && value->type() == JSONValue::{{resolve_type(property).json_type}};
+        {% else %}
+        return !!value;
+        {% endif %}
+    }
+
+        {% if property.optional %}
+    {{resolve_type(property).return_type}} get{{property.name | to_title_case}}({{resolve_type(property).return_type}} defaultValue)
+    {
+        RefPtr<JSONValue> value = m_object->get("{{property.name}}");
+        return value ? FromValue<{{resolve_type(property).raw_type}}>::convert(value) : defaultValue;
+    }
+        {% else %}
+    {{resolve_type(property).return_type}} get{{property.name | to_title_case}}()
+    {
+        ASSERT(has{{property.name | to_title_case}}());
+        RefPtr<JSONValue> value = m_object->get("{{property.name}}");
+        return FromValue<{{resolve_type(property).raw_type}}>::convert(value);
+    }
+        {% endif %}
+
+    void set{{property.name | to_title_case}}({{resolve_type(property).pass_type}} value)
+    {
+        {% if property.optional and resolve_type(property).nullable %}
+        if (value)
+            m_object->setValue("{{property.name}}", toValue(value));
+        {% else %}
+        m_object->setValue("{{property.name}}", toValue(value));
+        {% endif %}
+    }
+      {% endfor %}
+
+    PassRefPtr<JSONObject> asValue() { return m_object; }
+
+    PassOwnPtr<{{type.id}}> clone() { return adoptPtr(new {{type.id}}(m_object)); }
+
+    template<int STATE>
+    class {{type.id}}Builder {
+    public:
+        enum {
+            NoFieldsSet = 0,
+      {% set count = 0 %}
+      {% for property in type.properties %}
+        {% if not(property.optional) %}
+          {% set count = count + 1 %}
+            {{property.name | to_title_case}}Set = 1 << {{count}},
+        {% endif %}
+      {% endfor %}
+            AllFieldsSet = (
+      {%- for property in type.properties %}
+        {% if not(property.optional) %}{{property.name | to_title_case}}Set | {%endif %}
+      {% endfor %}0)};
+
+      {% for property in type.properties %}
+
+        {% if property.optional %}
+        {{type.id}}Builder<STATE>& set{{property.name | to_title_case}}({{resolve_type(property).pass_type}} value)
+        {
+          {% if resolve_type(property).nullable%}
+            if (!value)
+                return *this;
+          {% endif %}
+            m_result->set{{property.name | to_title_case}}(value);
+            return *this;
+        }
+        {% else %}
+        {{type.id}}Builder<STATE | {{property.name | to_title_case}}Set>& set{{property.name | to_title_case}}({{resolve_type(property).pass_type}} value)
+        {
+            static_assert(!(STATE & {{property.name | to_title_case}}Set), "property {{property.name}} should not be set yet");
+            m_result->set{{property.name | to_title_case}}(value);
+            return castState<{{property.name | to_title_case}}Set>();
+        }
+        {% endif %}
+      {% endfor %}
+
+        PassOwnPtr<{{type.id}}> build()
+        {
+            static_assert(STATE == AllFieldsSet, "state should be AllFieldsSet");
+            return m_result.release();
+        }
+
+    private:
+        friend class {{type.id}};
+        {{type.id}}Builder() : m_result({{type_def.create_type}}) { }
+
+        template<int STEP> {{type.id}}Builder<STATE | STEP>& castState()
+        {
+            return *reinterpret_cast<{{type.id}}Builder<STATE | STEP>*>(this);
+        }
+
+        {{type_def.type}} m_result;
+    };
+
+    static {{type.id}}Builder<0> create()
+    {
+        return {{type.id}}Builder<0>();
+    }
+
+private:
+    explicit {{type.id}}(PassRefPtr<JSONObject> object) : m_object(object) { }
+    RefPtr<JSONObject> m_object;
+};
+
+    {% endif %}
+  {% endfor %}
+
+} // {{domain.domain}}
+{% endfor %}
+
+} // namespace protocol
+} // namespace blink
+
+#endif // !defined({{class_name}}_h)
diff --git a/protocol.gyp b/protocol.gyp
index c5b8a88..b411c86 100644
--- a/protocol.gyp
+++ b/protocol.gyp
@@ -5,6 +5,11 @@
 {
   'variables': {
     'blink_platform_output_dir': '<(SHARED_INTERMEDIATE_DIR)/blink/platform',
+    'jinja_module_files': [
+      # jinja2/__init__.py contains version string, so sufficient for package
+      '<(DEPTH)/third_party/jinja2/__init__.py',
+      '<(DEPTH)/third_party/markupsafe/__init__.py',  # jinja2 dep
+    ],
   },
 
   'targets': [
@@ -19,12 +24,17 @@
         {
           'action_name': 'generateInspectorProtocolBackendSources',
           'inputs': [
+            '<@(jinja_module_files)',
             # The python script in action below.
             'CodeGenerator.py',
-            # The helper script imported by CodeGenerator.py.
-            'CodeGeneratorStrings.py',
-            # Input file for the script.
+            # Input files for the script.
             '../../devtools/protocol.json',
+            'Dispatcher_h.template',
+            'Dispatcher_cpp.template',
+            'Frontend_h.template',
+            'Frontend_cpp.template',
+            'TypeBuilder_h.template',
+            'TypeBuilder_cpp.template',
           ],
           'outputs': [
             '<(blink_platform_output_dir)/inspector_protocol/Dispatcher.cpp',
@@ -34,10 +44,6 @@
             '<(blink_platform_output_dir)/inspector_protocol/TypeBuilder.cpp',
             '<(blink_platform_output_dir)/inspector_protocol/TypeBuilder.h',
           ],
-          'variables': {
-            'generator_include_dirs': [
-            ],
-          },
           'action': [
             'python',
             'CodeGenerator.py',