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

Side by Side Diff: third_party/dom_distiller_js/protoc_plugins/json_values_converter.py

Issue 2034373002: Generate the proto JSON converter for DOM distiller (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Windows-specific fixes Created 4 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 #!/usr/bin/env python
2 # Copyright 2016 The Chromium Authors. All rights reserved.
3 # Use of this source code is governed by a BSD-style license that can be
4 # found in the LICENSE file.
5
6 """protoc plugin to create C++ reader/writer for JSON-encoded protobufs
7
8 The reader/writer use Chrome's base::Values.
9 """
10
11 import optparse
12 import os
13
14 from util import plugin, plugin_protos, writer
15 from util.plugin import Indented
16
17 class CppConverterWriter(writer.CodeWriter):
18 def WriteProtoFile(self, proto_file, output_dir):
19 err = proto_file.CheckSupported()
20 if err:
21 self.AddError(err)
22 return
23
24 self.WriteCStyleHeader()
25
26 self.Output('#include "{output_dir}{generated_pb_h}"',
27 output_dir=output_dir + '/' if output_dir else '',
28 generated_pb_h=proto_file.CppBaseHeader())
29 self.Output('')
30
31 # import is not supported
32 assert [] == proto_file.GetDependencies()
33
34 self.Output('// base dependencies')
35 self.Output('#include "base/values.h"')
36 self.Output('')
37 self.Output('#include <memory>')
38 self.Output('#include <string>')
39 self.Output('#include <utility>')
40 self.Output('')
41
42 namespaces = proto_file.ProtoNamespaces() + ['json']
43 for name in namespaces:
44 self.Output('namespace {name} {{', name=name)
45 self.IncreaseIndent()
46
47 for message in proto_file.GetMessages():
48 self.WriteMessage(message)
49
50 # Nothing to do for enums
51
52 for name in namespaces:
53 self.DecreaseIndent()
54 self.Output('}}')
55
56 def WriteMessage(self, message):
57 self.Output('class {class_name} {{',
58 class_name=message.CppConverterClassName())
59 self.Output(' public:')
60 with self.AddIndent():
61 for nested_class in message.GetMessages():
62 self.WriteMessage(nested_class)
63
64 generated_class_name = message.QualifiedTypes().cpp_base
65 # Nothing to write for enums.
66
67 self.Output(
68 'static bool ReadFromValue(const base::Value* json, {generated_class_n ame}* message) {{\n'
69 #' {generated_class_name} message;\n'
70 ' const base::DictionaryValue* dict;\n'
71 ' if (!json->GetAsDictionary(&dict)) goto error;\n'
72 '',
73 generated_class_name=generated_class_name)
74
75 with self.AddIndent():
76 for field_proto in message.GetFields():
77 self.WriteFieldRead(field_proto)
78
79 self.Output(
80 ' return true;\n'
81 '\n'
82 'error:\n'
83 ' return false;\n'
84 '}}\n'
85 '\n'
86 'static std::unique_ptr<base::DictionaryValue> WriteToValue(const {gen erated_class_name}& message) {{\n'
87 ' std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryVal ue());\n'
88 '',
89 generated_class_name=generated_class_name)
90
91 with self.AddIndent():
92 for field_proto in message.GetFields():
93 self.FieldWriteToValue(field_proto)
94
95 self.Output(
96 ' return dict;\n'
97 '',
98 generated_class_name=generated_class_name)
99 self.Output('}}')
100
101 self.Output('}};')
102 self.Output('')
103
104 def FieldWriteToValue(self, field):
105 if field.IsRepeated():
106 self.Output('{{')
107 else:
108 self.Output('if (message.has_{field_name}()) {{\n', field_name=field.name)
109
110 with self.AddIndent():
111 if field.IsRepeated():
112 self.RepeatedMemberFieldWriteToValue(field)
113 else:
114 self.OptionalMemberFieldWriteToValue(field)
115
116 self.Output('}}')
117
118 def RepeatedMemberFieldWriteToValue(self, field):
119 prologue = (
120 'base::ListValue* field_list = new base::ListValue();\n'
121 'dict->Set("{field_number}", field_list);\n'
122 'for (int i = 0; i < message.{field_name}_size(); ++i) {{\n'
123 )
124
125 if field.IsClassType():
126 middle = (
127 'std::unique_ptr<base::Value> inner_message_value = \n'
128 ' {inner_class_converter}::WriteToValue(message.{field_name}(i));\n '
129 'field_list->Append(std::move(inner_message_value));\n'
130 )
131 else:
132 middle = (
133 'field_list->Append{value_type}(message.{field_name}(i));\n'
134 )
135 self.Output(
136 prologue + Indented(middle) + '\n}}',
137 field_number=field.JavascriptIndex(),
138 field_name=field.name,
139 value_type=field.CppValueType() if not field.IsClassType() else None,
140 inner_class_converter=field.CppConverterType()
141 )
142
143 def OptionalMemberFieldWriteToValue(self, field):
144 if field.IsClassType():
145 body = (
146 'std::unique_ptr<base::Value> inner_message_value = \n'
147 ' {inner_class_converter}::WriteToValue(message.{field_name}());\n'
148 'dict->Set("{field_number}", std::move(inner_message_value));\n'
149 )
150 else:
151 body = (
152 'dict->Set{value_type}("{field_number}", message.{field_name}());\n'
153 )
154
155 self.Output(
156 body,
157 field_number=field.JavascriptIndex(),
158 field_name=field.name,
159 value_type=field.CppValueType() if not field.IsClassType() else None,
160 inner_class_converter=field.CppConverterType(),
161 )
162
163 def WriteFieldRead(self, field):
164 self.Output('if (dict->HasKey("{field_number}")) {{',
165 field_number=field.JavascriptIndex())
166
167 with self.AddIndent():
168 if field.IsRepeated():
169 self.RepeatedMemberFieldRead(field)
170 else:
171 self.OptionalMemberFieldRead(field)
172
173 self.Output('}}')
174
175 def RepeatedMemberFieldRead(self, field):
176 prologue = (
177 'const base::ListValue* field_list;\n'
178 'if (!dict->GetList("{field_number}", &field_list)) {{\n'
179 ' goto error;\n'
180 '}}\n'
181 'for (size_t i = 0; i < field_list->GetSize(); ++i) {{\n'
182 )
183
184 if field.IsClassType():
185 middle = (
186 'const base::Value* inner_message_value;\n'
187 'if (!field_list->Get(i, &inner_message_value)) {{\n'
188 ' goto error;\n'
189 '}}\n'
190 'if (!{inner_class_parser}::ReadFromValue(inner_message_value, message ->add_{field_name}())) {{\n'
191 ' goto error;\n'
192 '}}\n'
193 )
194 else:
195 middle = (
196 '{cpp_type} field_value;\n'
197 'if (!field_list->Get{value_type}(i, &field_value)) {{\n'
198 ' goto error;\n'
199 '}}\n'
200 'message->add_{field_name}(field_value);\n'
201 )
202
203 self.Output(
204 prologue + Indented(middle) + '\n}}',
205 field_number=field.JavascriptIndex(),
206 field_name=field.name,
207 cpp_type=field.CppPrimitiveType() if not field.IsClassType() else None,
208 value_type=field.CppValueType() if not field.IsClassType() else None,
209 inner_class_parser=field.CppConverterType()
210 )
211
212 def OptionalMemberFieldRead(self, field):
213 if field.IsClassType():
214 self.Output(
215 'const base::Value* inner_message_value;\n'
216 'if (!dict->Get("{field_number}", &inner_message_value)) {{\n'
217 ' goto error;\n'
218 '}}\n'
219 'if (!{inner_class_parser}::ReadFromValue(inner_message_value, message ->mutable_{field_name}())) {{\n'
220 ' goto error;\n'
221 '}}\n'
222 '',
223 field_number=field.JavascriptIndex(),
224 field_name=field.name,
225 inner_class_parser=field.CppConverterType()
226 )
227 else:
228 self.Output(
229 '{cpp_type} field_value;\n'
230 'if (!dict->Get{value_type}("{field_number}", &field_value)) {{\n'
231 ' goto error;\n'
232 '}}\n'
233 'message->set_{field_name}(field_value);\n'
234 '',
235 field_number=field.JavascriptIndex(),
236 field_name=field.name,
237 cpp_type=field.CppPrimitiveType(),
238 value_type=field.CppValueType()
239 )
240
241
242 def main():
243 request = plugin.ReadRequestFromStdin()
244 response = plugin_protos.PluginResponse()
245
246 output_dir = request.GetArgs().get('output_dir', '')
247
248 for proto_file in request.GetAllFiles():
249 plugin.RegisterProtoFile(proto_file)
250
251 writer = CppConverterWriter()
252 writer.WriteProtoFile(proto_file, output_dir)
253
254 converter_filename = proto_file.CppConverterFilename()
255 if output_dir:
256 converter_filename = os.path.join(output_dir,
257 os.path.split(converter_filename)[1])
258
259 response.AddFileWithContent(converter_filename, writer.GetValue())
260 if writer.GetErrors():
261 response.AddError('\n'.join(writer.GetErrors()))
262
263 plugin.SetBinaryStdio()
264 response.WriteToStdout()
265
266
267 if __name__ == '__main__':
268 main()
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698