12a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#!/usr/bin/env python
22a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)# Copyright (c) 2013 Google Inc. All rights reserved.
32a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#
42a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)# Redistribution and use in source and binary forms, with or without
52a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)# modification, are permitted provided that the following conditions are
62a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)# met:
72a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#
82a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#     * Redistributions of source code must retain the above copyright
92a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)# notice, this list of conditions and the following disclaimer.
102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#     * Redistributions in binary form must reproduce the above
115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)# copyright notice, this list of conditions and the following disclaimer
122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)# in the documentation and/or other materials provided with the
132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)# distribution.
145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#     * Neither the name of Google Inc. nor the names of its
159ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch# contributors may be used to endorse or promote products derived from
162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)# this software without specific prior written permission.
172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#
185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)import optparse
312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)import re
325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)import string
335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)import sys
345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)template_h = string.Template("""// Code generated from InspectorInstrumentation.idl
365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#ifndef ${file_name}_h
385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#define ${file_name}_h
395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)${includes}
415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)namespace blink {
435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)${forward_declarations}
452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)namespace InspectorInstrumentation {
472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)$methods
495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} // namespace InspectorInstrumentation
505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} // namespace blink
522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#endif // !defined(${file_name}_h)
542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)""")
552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)template_inline = string.Template("""
572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)inline void ${name}(${params_public})
582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles){   ${fast_return}
592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (${condition})
605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        ${name}Impl(${params_impl});
612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)""")
632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)template_inline_forward = string.Template("""
652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)inline void ${name}(${params_public})
662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles){   ${fast_return}
672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    ${name}Impl(${params_impl});
682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)""")
702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)template_inline_returns_value = string.Template("""
722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)inline ${return_type} ${name}(${params_public})
732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles){   ${fast_return}
742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (${condition})
752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        return ${name}Impl(${params_impl});
762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return ${default_return_value};
775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)""")
792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)template_cpp = string.Template("""// Code generated from InspectorInstrumentation.idl
825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "config.h"
845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
85a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)${includes}
862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace blink {
882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)${extra_definitions}
892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace InspectorInstrumentation {
912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)$methods
922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} // namespace InspectorInstrumentation
942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} // namespace blink
962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)""")
972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)template_outofline = string.Template("""
992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)${return_type} ${name}Impl(${params_impl})
100a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles){${impl_lines}
1015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}""")
1025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)template_agent_call = string.Template("""
1042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (${agent_class}* agent = ${agent_fetch})
1052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        ${maybe_return}agent->${name}(${params_agent});""")
1062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)template_agent_call_timeline_returns_cookie = string.Template("""
1085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    int timelineAgentId = 0;
1095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (InspectorTimelineAgent* agent = agents->inspectorTimelineAgent()) {
1102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        if (agent->${name}(${params_agent}))
1112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            timelineAgentId = agent->id();
1122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }""")
1132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)template_instrumenting_agents_h = string.Template("""// Code generated from InspectorInstrumentation.idl
1162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#ifndef InstrumentingAgentsInl_h
1185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#define InstrumentingAgentsInl_h
1192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "platform/heap/Handle.h"
1212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "wtf/FastAllocBase.h"
1222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "wtf/Noncopyable.h"
1235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "wtf/PassRefPtr.h"
1242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "wtf/RefCounted.h"
1252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace blink {
1272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)${forward_list}
1292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)class InstrumentingAgents : public RefCountedWillBeGarbageCollectedFinalized<InstrumentingAgents> {
1312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    WTF_MAKE_NONCOPYABLE(InstrumentingAgents);
1322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    WTF_MAKE_FAST_ALLOCATED_WILL_BE_REMOVED;
1332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)public:
1342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    static PassRefPtrWillBeRawPtr<InstrumentingAgents> create()
1352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    {
1362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        return adoptRefWillBeNoop(new InstrumentingAgents());
1372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
1382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    ~InstrumentingAgents() { }
1392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    void trace(Visitor*);
1402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    void reset();
1412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)${accessor_list}
1432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)private:
1452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    InstrumentingAgents();
1462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)${member_list}
1482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)};
149a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
1505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
1515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#endif // !defined(InstrumentingAgentsInl_h)
1535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)""")
1542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)template_instrumenting_agent_accessor = string.Template("""
1562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    ${class_name}* ${getter_name}() const { return ${member_name}; }
1572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    void set${class_name}(${class_name}* agent) { ${member_name} = agent; }""")
1582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)template_instrumenting_agents_cpp = string.Template("""
160InstrumentingAgents::InstrumentingAgents()
161    : $init_list
162{
163}
164
165void InstrumentingAgents::trace(Visitor* visitor)
166{
167    $trace_list
168}
169
170void InstrumentingAgents::reset()
171{
172    $reset_list
173}""")
174
175
176
177def match_and_consume(pattern, source):
178    match = re.match(pattern, source)
179    if match:
180        return match, source[len(match.group(0)):].strip()
181    return None, source
182
183
184def load_model_from_idl(source):
185    source = re.sub("//.*", "", source)  # Remove line comments
186    source = re.sub("/\*(.|\n)*?\*/", "", source, re.MULTILINE)  # Remove block comments
187    source = re.sub("\]\s*?\n\s*", "] ", source)  # Merge the method annotation with the next line
188    source = source.strip()
189
190    model = []
191
192    while len(source):
193        match, source = match_and_consume("interface\s(\w*)\s?\{([^\{]*)\}", source)
194        if not match:
195            sys.stderr.write("Cannot parse %s\n" % source[:100])
196            sys.exit(1)
197        model.append(File(match.group(1), match.group(2)))
198
199    return model
200
201
202class File:
203    def __init__(self, name, source):
204        self.name = name
205        self.header_name = self.name + "Inl"
206        self.includes = [include_inspector_header("InspectorInstrumentation")]
207        self.forward_declarations = []
208        self.declarations = []
209        for line in map(str.strip, source.split("\n")):
210            line = re.sub("\s{2,}", " ", line).strip()  # Collapse whitespace
211            if len(line) == 0:
212                continue
213            if line[0] == "#":
214                self.includes.append(line)
215            elif line.startswith("class "):
216                self.forward_declarations.append(line)
217            else:
218                self.declarations.append(Method(line))
219        self.includes.sort()
220        self.forward_declarations.sort()
221
222    def generate(self, cpp_lines, used_agents):
223        header_lines = []
224        for declaration in self.declarations:
225            for agent in set(declaration.agents):
226                used_agents.add(agent)
227            declaration.generate_header(header_lines)
228            declaration.generate_cpp(cpp_lines)
229
230        return template_h.substitute(None,
231                                     file_name=self.header_name,
232                                     includes="\n".join(self.includes),
233                                     forward_declarations="\n".join(self.forward_declarations),
234                                     methods="\n".join(header_lines))
235
236
237class Method:
238    def __init__(self, source):
239        match = re.match("(\[[\w|,|=|\s]*\])?\s?(\w*\*?) (\w*)\((.*)\)\s?;", source)
240        if not match:
241            sys.stderr.write("Cannot parse %s\n" % source)
242            sys.exit(1)
243
244        self.options = []
245        if match.group(1):
246            options_str = re.sub("\s", "", match.group(1)[1:-1])
247            if len(options_str) != 0:
248                self.options = options_str.split(",")
249
250        self.return_type = match.group(2)
251
252        self.name = match.group(3)
253
254        # Splitting parameters by a comma, assuming that attribute lists contain no more than one attribute.
255        self.params = map(Parameter, map(str.strip, match.group(4).split(",")))
256
257        self.accepts_cookie = len(self.params) and self.params[0].type == "const InspectorInstrumentationCookie&"
258        self.returns_cookie = self.return_type == "InspectorInstrumentationCookie"
259
260        self.returns_value = self.return_type != "void"
261
262        if self.return_type == "bool":
263            self.default_return_value = "false"
264        elif self.return_type == "int":
265            self.default_return_value = "0"
266        elif self.return_type == "String":
267            self.default_return_value = "\"\""
268        else:
269            self.default_return_value = self.return_type + "()"
270
271        for param in self.params:
272            if "DefaultReturn" in param.options:
273                self.default_return_value = param.name
274
275        self.params_impl = self.params
276        if not self.accepts_cookie and not "Inline=Forward" in self.options:
277            if not "Keep" in self.params_impl[0].options:
278                self.params_impl = self.params_impl[1:]
279            self.params_impl = [Parameter("InstrumentingAgents* agents")] + self.params_impl
280
281        self.agents = filter(lambda option: not "=" in option, self.options)
282
283    def generate_header(self, header_lines):
284        if "Inline=Custom" in self.options:
285            return
286
287        header_lines.append("%s %sImpl(%s);" % (
288            self.return_type, self.name, ", ".join(map(Parameter.to_str_class, self.params_impl))))
289
290        if "Inline=FastReturn" in self.options or "Inline=Forward" in self.options:
291            fast_return = "\n    FAST_RETURN_IF_NO_FRONTENDS(%s);" % self.default_return_value
292        else:
293            fast_return = ""
294
295        for param in self.params:
296            if "FastReturn" in param.options:
297                fast_return += "\n    if (!%s)\n        return %s;" % (param.name, self.default_return_value)
298
299        if self.accepts_cookie:
300            condition = "%s.isValid()" % self.params_impl[0].name
301            template = template_inline
302        elif "Inline=Forward" in self.options:
303            condition = ""
304            template = template_inline_forward
305        else:
306            condition = "InstrumentingAgents* agents = instrumentingAgentsFor(%s)" % self.params[0].name
307
308            if self.returns_value:
309                template = template_inline_returns_value
310            else:
311                template = template_inline
312
313        header_lines.append(template.substitute(
314            None,
315            name=self.name,
316            fast_return=fast_return,
317            return_type=self.return_type,
318            default_return_value=self.default_return_value,
319            params_public=", ".join(map(Parameter.to_str_full, self.params)),
320            params_impl=", ".join(map(Parameter.to_str_name, self.params_impl)),
321            condition=condition))
322
323    def generate_cpp(self, cpp_lines):
324        if len(self.agents) == 0:
325            return
326
327        body_lines = map(self.generate_ref_ptr, self.params)
328        body_lines += map(self.generate_agent_call, self.agents)
329
330        if self.returns_cookie:
331            if "Timeline" in self.agents:
332                timeline_agent_id = "timelineAgentId"
333            else:
334                timeline_agent_id = "0"
335            body_lines.append("\n    return InspectorInstrumentationCookie(agents, %s);" % timeline_agent_id)
336        elif self.returns_value:
337            body_lines.append("\n    return %s;" % self.default_return_value)
338
339        cpp_lines.append(template_outofline.substitute(
340            None,
341            return_type=self.return_type,
342            name=self.name,
343            params_impl=", ".join(map(Parameter.to_str_class_and_name, self.params_impl)),
344            impl_lines="".join(body_lines)))
345
346    def generate_agent_call(self, agent):
347        agent_class, agent_getter = agent_getter_signature(agent)
348
349        leading_param_name = self.params_impl[0].name
350        if not self.accepts_cookie:
351            agent_fetch = "%s->%s()" % (leading_param_name, agent_getter)
352        elif agent == "Timeline":
353            agent_fetch = "retrieveTimelineAgent(%s)" % leading_param_name
354        else:
355            agent_fetch = "%s.instrumentingAgents()->%s()" % (leading_param_name, agent_getter)
356
357        if agent == "Timeline" and self.returns_cookie:
358            template = template_agent_call_timeline_returns_cookie
359        else:
360            template = template_agent_call
361
362        if not self.returns_value or self.returns_cookie:
363            maybe_return = ""
364        else:
365            maybe_return = "return "
366
367        return template.substitute(
368            None,
369            name=self.name,
370            agent_class=agent_class,
371            agent_fetch=agent_fetch,
372            maybe_return=maybe_return,
373            params_agent=", ".join(map(Parameter.to_str_value, self.params_impl)[1:]))
374
375    def generate_ref_ptr(self, param):
376        if param.is_prp:
377            return "\n    RefPtr<%s> %s = %s;" % (param.inner_type, param.value, param.name)
378        else:
379            return ""
380
381class Parameter:
382    def __init__(self, source):
383        self.options = []
384        match, source = match_and_consume("\[(\w*)\]", source)
385        if match:
386            self.options.append(match.group(1))
387
388        parts = map(str.strip, source.split("="))
389        if len(parts) == 1:
390            self.default_value = None
391        else:
392            self.default_value = parts[1]
393
394        param_decl = parts[0]
395
396        if re.match("(const|unsigned long) ", param_decl):
397            min_type_tokens = 2
398        else:
399            min_type_tokens = 1
400
401        if len(param_decl.split(" ")) > min_type_tokens:
402            parts = param_decl.split(" ")
403            self.type = " ".join(parts[:-1])
404            self.name = parts[-1]
405        else:
406            self.type = param_decl
407            self.name = generate_param_name(self.type)
408
409        if re.match("PassRefPtr<", param_decl):
410            self.is_prp = True
411            self.value = self.name
412            self.name = "prp" + self.name[0].upper() + self.name[1:]
413            self.inner_type = re.match("PassRefPtr<(.+)>", param_decl).group(1)
414        else:
415            self.is_prp = False
416            self.value = self.name
417
418
419    def to_str_full(self):
420        if self.default_value is None:
421            return self.to_str_class_and_name()
422        return "%s %s = %s" % (self.type, self.name, self.default_value)
423
424    def to_str_class_and_name(self):
425        return "%s %s" % (self.type, self.name)
426
427    def to_str_class(self):
428        return self.type
429
430    def to_str_name(self):
431        return self.name
432
433    def to_str_value(self):
434        return self.value
435
436
437def generate_param_name(param_type):
438    base_name = re.match("(const |PassRefPtr<)?(\w*)", param_type).group(2)
439    return "param" + base_name
440
441
442def agent_class_name(agent):
443    custom_agent_names = ["PageDebugger", "PageRuntime", "WorkerRuntime"]
444    if agent in custom_agent_names:
445        return "%sAgent" % agent
446    return "Inspector%sAgent" % agent
447
448
449def agent_getter_signature(agent):
450    agent_class = agent_class_name(agent)
451    return agent_class, agent_class[0].lower() + agent_class[1:]
452
453
454def include_header(name):
455    return "#include \"%s.h\"" % name
456
457
458def include_inspector_header(name):
459    return include_header("core/inspector/" + name)
460
461
462def generate_instrumenting_agents(used_agents):
463    agents = list(used_agents)
464
465    forward_list = []
466    accessor_list = []
467    member_list = []
468    init_list = []
469    trace_list = []
470    reset_list = []
471
472    for agent in agents:
473        class_name, getter_name = agent_getter_signature(agent)
474        member_name = "m_" + getter_name
475
476        forward_list.append("class %s;" % class_name)
477        accessor_list.append(template_instrumenting_agent_accessor.substitute(
478            None,
479            class_name=class_name,
480            getter_name=getter_name,
481            member_name=member_name))
482        member_list.append("    RawPtrWillBeMember<%s> %s;" % (class_name, member_name))
483        init_list.append("%s(nullptr)" % member_name)
484        trace_list.append("visitor->trace(%s);" % member_name)
485        reset_list.append("%s = nullptr;" % member_name)
486
487    forward_list.sort()
488    accessor_list.sort()
489    member_list.sort()
490    init_list.sort()
491    trace_list.sort()
492    reset_list.sort()
493
494    header_lines = template_instrumenting_agents_h.substitute(
495        None,
496        forward_list="\n".join(forward_list),
497        accessor_list="\n".join(accessor_list),
498        member_list="\n".join(member_list))
499
500    cpp_lines = template_instrumenting_agents_cpp.substitute(
501        None,
502        init_list="\n    , ".join(init_list),
503        trace_list="\n    ".join(trace_list),
504        reset_list="\n    ".join(reset_list))
505
506    return header_lines, cpp_lines
507
508
509def generate(input_path, output_dir):
510    fin = open(input_path, "r")
511    files = load_model_from_idl(fin.read())
512    fin.close()
513
514    cpp_includes = []
515    cpp_lines = []
516    used_agents = set()
517    for f in files:
518        cpp_includes.append(include_header(f.header_name))
519
520        fout = open(output_dir + "/" + f.header_name + ".h", "w")
521        fout.write(f.generate(cpp_lines, used_agents))
522        fout.close()
523
524    for agent in used_agents:
525        cpp_includes.append(include_inspector_header(agent_class_name(agent)))
526    cpp_includes.append(include_header("InstrumentingAgentsInl"))
527    cpp_includes.sort()
528
529    instrumenting_agents_header, instrumenting_agents_cpp = generate_instrumenting_agents(used_agents)
530
531    fout = open(output_dir + "/" + "InstrumentingAgentsInl.h", "w")
532    fout.write(instrumenting_agents_header)
533    fout.close()
534
535    fout = open(output_dir + "/InspectorInstrumentationImpl.cpp", "w")
536    fout.write(template_cpp.substitute(None,
537                                       includes="\n".join(cpp_includes),
538                                       extra_definitions=instrumenting_agents_cpp,
539                                       methods="\n".join(cpp_lines)))
540    fout.close()
541
542
543cmdline_parser = optparse.OptionParser()
544cmdline_parser.add_option("--output_dir")
545
546try:
547    arg_options, arg_values = cmdline_parser.parse_args()
548    if (len(arg_values) != 1):
549        raise Exception("Exactly one plain argument expected (found %s)" % len(arg_values))
550    input_path = arg_values[0]
551    output_dirpath = arg_options.output_dir
552    if not output_dirpath:
553        raise Exception("Output directory must be specified")
554except Exception:
555    # Work with python 2 and 3 http://docs.python.org/py3k/howto/pyporting.html
556    exc = sys.exc_info()[1]
557    sys.stderr.write("Failed to parse command-line arguments: %s\n\n" % exc)
558    sys.stderr.write("Usage: <script> --output_dir <output_dir> InspectorInstrumentation.idl\n")
559    exit(1)
560
561generate(input_path, output_dirpath)
562