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

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

Powered by Google App Engine
This is Rietveld 408576698