1 | /* |
2 | * Copyright 2014 Google Inc. All rights reserved. |
3 | * |
4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
5 | * you may not use this file except in compliance with the License. |
6 | * You may obtain a copy of the License at |
7 | * |
8 | * http://www.apache.org/licenses/LICENSE-2.0 |
9 | * |
10 | * Unless required by applicable law or agreed to in writing, software |
11 | * distributed under the License is distributed on an "AS IS" BASIS, |
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
13 | * See the License for the specific language governing permissions and |
14 | * limitations under the License. |
15 | */ |
16 | |
17 | // independent from idl_parser, since this code is not needed for most clients |
18 | |
19 | #include <string> |
20 | |
21 | #include "flatbuffers/code_generators.h" |
22 | #include "flatbuffers/flatbuffers.h" |
23 | #include "flatbuffers/idl.h" |
24 | #include "flatbuffers/util.h" |
25 | |
26 | namespace flatbuffers { |
27 | namespace php { |
28 | // Hardcode spaces per indentation. |
29 | const std::string Indent = " " ; |
30 | class PhpGenerator : public BaseGenerator { |
31 | public: |
32 | PhpGenerator(const Parser &parser, const std::string &path, |
33 | const std::string &file_name) |
34 | : BaseGenerator(parser, path, file_name, "\\" , "\\" ) {} |
35 | bool generate() { |
36 | if (!GenerateEnums()) return false; |
37 | if (!GenerateStructs()) return false; |
38 | return true; |
39 | } |
40 | |
41 | private: |
42 | bool GenerateEnums() { |
43 | for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end(); |
44 | ++it) { |
45 | auto &enum_def = **it; |
46 | std::string enumcode; |
47 | GenEnum(enum_def, &enumcode); |
48 | if (!SaveType(enum_def, enumcode, false)) return false; |
49 | } |
50 | return true; |
51 | } |
52 | |
53 | bool GenerateStructs() { |
54 | for (auto it = parser_.structs_.vec.begin(); |
55 | it != parser_.structs_.vec.end(); ++it) { |
56 | auto &struct_def = **it; |
57 | std::string declcode; |
58 | GenStruct(struct_def, &declcode); |
59 | if (!SaveType(struct_def, declcode, true)) return false; |
60 | } |
61 | return true; |
62 | } |
63 | |
64 | // Begin by declaring namespace and imports. |
65 | void BeginFile(const std::string &name_space_name, const bool needs_imports, |
66 | std::string *code_ptr) { |
67 | auto &code = *code_ptr; |
68 | code += "<?php\n" ; |
69 | code = code + "// " + FlatBuffersGeneratedWarning() + "\n\n" ; |
70 | |
71 | if (!name_space_name.empty()) { |
72 | code += "namespace " + name_space_name + ";\n\n" ; |
73 | } |
74 | |
75 | if (needs_imports) { |
76 | code += "use \\Google\\FlatBuffers\\Struct;\n" ; |
77 | code += "use \\Google\\FlatBuffers\\Table;\n" ; |
78 | code += "use \\Google\\FlatBuffers\\ByteBuffer;\n" ; |
79 | code += "use \\Google\\FlatBuffers\\FlatBufferBuilder;\n" ; |
80 | code += "\n" ; |
81 | } |
82 | } |
83 | |
84 | // Save out the generated code for a Php Table type. |
85 | bool SaveType(const Definition &def, const std::string &classcode, |
86 | bool needs_imports) { |
87 | if (!classcode.length()) return true; |
88 | |
89 | std::string code = "" ; |
90 | BeginFile(FullNamespace("\\" , *def.defined_namespace), needs_imports, |
91 | &code); |
92 | code += classcode; |
93 | |
94 | std::string filename = |
95 | NamespaceDir(*def.defined_namespace) + def.name + ".php" ; |
96 | return SaveFile(filename.c_str(), code, false); |
97 | } |
98 | |
99 | // Begin a class declaration. |
100 | static void BeginClass(const StructDef &struct_def, std::string *code_ptr) { |
101 | std::string &code = *code_ptr; |
102 | if (struct_def.fixed) { |
103 | code += "class " + struct_def.name + " extends Struct\n" ; |
104 | } else { |
105 | code += "class " + struct_def.name + " extends Table\n" ; |
106 | } |
107 | code += "{\n" ; |
108 | } |
109 | |
110 | static void EndClass(std::string *code_ptr) { |
111 | std::string &code = *code_ptr; |
112 | code += "}\n" ; |
113 | } |
114 | |
115 | // Begin enum code with a class declaration. |
116 | static void BeginEnum(const std::string &class_name, std::string *code_ptr) { |
117 | std::string &code = *code_ptr; |
118 | code += "class " + class_name + "\n{\n" ; |
119 | } |
120 | |
121 | // A single enum member. |
122 | static void EnumMember(const EnumDef &enum_def, const EnumVal &ev, |
123 | std::string *code_ptr) { |
124 | std::string &code = *code_ptr; |
125 | code += Indent + "const " ; |
126 | code += ev.name; |
127 | code += " = " ; |
128 | code += NumToString(ev.value) + ";\n" ; |
129 | (void)enum_def; |
130 | } |
131 | |
132 | // End enum code. |
133 | static void EndEnum(std::string *code_ptr) { |
134 | std::string &code = *code_ptr; |
135 | code += "}\n" ; |
136 | } |
137 | |
138 | // Initialize a new struct or table from existing data. |
139 | static void NewRootTypeFromBuffer(const StructDef &struct_def, |
140 | std::string *code_ptr) { |
141 | std::string &code = *code_ptr; |
142 | |
143 | code += Indent + "/**\n" ; |
144 | code += Indent + " * @param ByteBuffer $bb\n" ; |
145 | code += Indent + " * @return " + struct_def.name + "\n" ; |
146 | code += Indent + " */\n" ; |
147 | code += Indent + "public static function getRootAs" ; |
148 | code += struct_def.name; |
149 | code += "(ByteBuffer $bb)\n" ; |
150 | code += Indent + "{\n" ; |
151 | |
152 | code += Indent + Indent + "$obj = new " + struct_def.name + "();\n" ; |
153 | code += Indent + Indent; |
154 | code += "return ($obj->init($bb->getInt($bb->getPosition())" ; |
155 | code += " + $bb->getPosition(), $bb));\n" ; |
156 | code += Indent + "}\n\n" ; |
157 | } |
158 | |
159 | // Initialize an existing object with other data, to avoid an allocation. |
160 | static void InitializeExisting(const StructDef &struct_def, |
161 | std::string *code_ptr) { |
162 | std::string &code = *code_ptr; |
163 | |
164 | code += Indent + "/**\n" ; |
165 | code += Indent + " * @param int $_i offset\n" ; |
166 | code += Indent + " * @param ByteBuffer $_bb\n" ; |
167 | code += Indent + " * @return " + struct_def.name + "\n" ; |
168 | code += Indent + " **/\n" ; |
169 | code += Indent + "public function init($_i, ByteBuffer $_bb)\n" ; |
170 | code += Indent + "{\n" ; |
171 | code += Indent + Indent + "$this->bb_pos = $_i;\n" ; |
172 | code += Indent + Indent + "$this->bb = $_bb;\n" ; |
173 | code += Indent + Indent + "return $this;\n" ; |
174 | code += Indent + "}\n\n" ; |
175 | } |
176 | |
177 | // Get the length of a vector. |
178 | static void GetVectorLen(const FieldDef &field, std::string *code_ptr) { |
179 | std::string &code = *code_ptr; |
180 | |
181 | code += Indent + "/**\n" ; |
182 | code += Indent + " * @return int\n" ; |
183 | code += Indent + " */\n" ; |
184 | code += Indent + "public function get" ; |
185 | code += MakeCamel(field.name) + "Length()\n" ; |
186 | code += Indent + "{\n" ; |
187 | code += Indent + Indent + "$o = $this->__offset(" ; |
188 | code += NumToString(field.value.offset) + ");\n" ; |
189 | code += Indent + Indent; |
190 | code += "return $o != 0 ? $this->__vector_len($o) : 0;\n" ; |
191 | code += Indent + "}\n\n" ; |
192 | } |
193 | |
194 | // Get a [ubyte] vector as a byte array. |
195 | static void GetUByte(const FieldDef &field, std::string *code_ptr) { |
196 | std::string &code = *code_ptr; |
197 | |
198 | code += Indent + "/**\n" ; |
199 | code += Indent + " * @return string\n" ; |
200 | code += Indent + " */\n" ; |
201 | code += Indent + "public function get" ; |
202 | code += MakeCamel(field.name) + "Bytes()\n" ; |
203 | code += Indent + "{\n" ; |
204 | code += Indent + Indent + "return $this->__vector_as_bytes(" ; |
205 | code += NumToString(field.value.offset) + ");\n" ; |
206 | code += Indent + "}\n\n" ; |
207 | } |
208 | |
209 | // Get the value of a struct's scalar. |
210 | static void GetScalarFieldOfStruct(const FieldDef &field, |
211 | std::string *code_ptr) { |
212 | std::string &code = *code_ptr; |
213 | std::string getter = GenGetter(field.value.type); |
214 | |
215 | code += Indent + "/**\n" ; |
216 | code += Indent + " * @return " ; |
217 | code += GenTypeGet(field.value.type) + "\n" ; |
218 | code += Indent + " */\n" ; |
219 | code += Indent + "public function " + getter; |
220 | code += MakeCamel(field.name) + "()\n" ; |
221 | code += Indent + "{\n" ; |
222 | code += Indent + Indent + "return " ; |
223 | |
224 | code += "$this->bb->get" ; |
225 | code += MakeCamel(GenTypeGet(field.value.type)); |
226 | code += "($this->bb_pos + " ; |
227 | code += NumToString(field.value.offset) + ")" ; |
228 | code += ";\n" ; |
229 | |
230 | code += Indent + "}\n\n" ; |
231 | } |
232 | |
233 | // Get the value of a table's scalar. |
234 | void GetScalarFieldOfTable(const FieldDef &field, std::string *code_ptr) { |
235 | std::string &code = *code_ptr; |
236 | std::string getter = GenGetter(field.value.type); |
237 | |
238 | code += Indent + "/**\n" ; |
239 | code += Indent + " * @return " + GenTypeGet(field.value.type) + "\n" ; |
240 | code += Indent + " */\n" ; |
241 | code += Indent + "public function get" ; |
242 | code += MakeCamel(field.name); |
243 | code += "()\n" ; |
244 | code += Indent + "{\n" ; |
245 | code += Indent + Indent + "$o = $this->__offset(" + |
246 | NumToString(field.value.offset) + ");\n" + Indent + Indent + |
247 | "return $o != 0 ? " ; |
248 | code += "$this->bb->get" ; |
249 | code += MakeCamel(GenTypeGet(field.value.type)) + "($o + $this->bb_pos)" ; |
250 | code += " : " + GenDefaultValue(field.value) + ";\n" ; |
251 | code += Indent + "}\n\n" ; |
252 | } |
253 | |
254 | // Get a struct by initializing an existing struct. |
255 | // Specific to Struct. |
256 | void GetStructFieldOfStruct(const FieldDef &field, std::string *code_ptr) { |
257 | std::string &code = *code_ptr; |
258 | |
259 | code += Indent + "/**\n" ; |
260 | code += Indent + " * @return " + GenTypeGet(field.value.type) + "\n" ; |
261 | code += Indent + " */\n" ; |
262 | code += Indent + "public function get" ; |
263 | code += MakeCamel(field.name) + "()\n" ; |
264 | code += Indent + "{\n" ; |
265 | code += Indent + Indent + "$obj = new " ; |
266 | code += GenTypeGet(field.value.type) + "();\n" ; |
267 | code += Indent + Indent + "$obj->init($this->bb_pos + " ; |
268 | code += NumToString(field.value.offset) + ", $this->bb);" ; |
269 | code += "\n" + Indent + Indent + "return $obj;\n" ; |
270 | code += Indent + "}\n\n" ; |
271 | } |
272 | |
273 | // Get a struct by initializing an existing struct. |
274 | // Specific to Table. |
275 | void GetStructFieldOfTable(const FieldDef &field, std::string *code_ptr) { |
276 | std::string &code = *code_ptr; |
277 | |
278 | code += Indent + "public function get" ; |
279 | code += MakeCamel(field.name); |
280 | code += "()\n" ; |
281 | code += Indent + "{\n" ; |
282 | code += Indent + Indent + "$obj = new " ; |
283 | code += MakeCamel(GenTypeGet(field.value.type)) + "();\n" ; |
284 | code += Indent + Indent + "$o = $this->__offset(" + |
285 | NumToString(field.value.offset) + ");\n" ; |
286 | code += Indent + Indent; |
287 | code += "return $o != 0 ? $obj->init(" ; |
288 | if (field.value.type.struct_def->fixed) { |
289 | code += "$o + $this->bb_pos, $this->bb) : " ; |
290 | } else { |
291 | code += "$this->__indirect($o + $this->bb_pos), $this->bb) : " ; |
292 | } |
293 | code += GenDefaultValue(field.value) + ";\n" ; |
294 | code += Indent + "}\n\n" ; |
295 | } |
296 | |
297 | // Get the value of a string. |
298 | void GetStringField(const FieldDef &field, std::string *code_ptr) { |
299 | std::string &code = *code_ptr; |
300 | code += Indent + "public function get" ; |
301 | code += MakeCamel(field.name); |
302 | code += "()\n" ; |
303 | code += Indent + "{\n" ; |
304 | code += Indent + Indent + "$o = $this->__offset(" + |
305 | NumToString(field.value.offset) + ");\n" ; |
306 | code += Indent + Indent; |
307 | code += "return $o != 0 ? $this->__string($o + $this->bb_pos) : " ; |
308 | code += GenDefaultValue(field.value) + ";\n" ; |
309 | code += Indent + "}\n\n" ; |
310 | } |
311 | |
312 | // Get the value of a union from an object. |
313 | void GetUnionField(const FieldDef &field, std::string *code_ptr) { |
314 | std::string &code = *code_ptr; |
315 | |
316 | code += Indent + "/**\n" ; |
317 | code += Indent + " * @return" + GenTypeBasic(field.value.type) + "\n" ; |
318 | code += Indent + " */\n" ; |
319 | code += Indent + "public function get" ; |
320 | code += MakeCamel(field.name) + "($obj)\n" ; |
321 | code += Indent + "{\n" ; |
322 | code += Indent + Indent + "$o = $this->__offset(" + |
323 | NumToString(field.value.offset) + ");\n" ; |
324 | code += Indent + Indent; |
325 | code += "return $o != 0 ? $this->__union($obj, $o) : null;\n" ; |
326 | code += Indent + "}\n\n" ; |
327 | } |
328 | |
329 | // Get the value of a vector's struct member. |
330 | void GetMemberOfVectorOfStruct(const StructDef &struct_def, |
331 | const FieldDef &field, std::string *code_ptr) { |
332 | std::string &code = *code_ptr; |
333 | auto vectortype = field.value.type.VectorType(); |
334 | |
335 | code += Indent + "/**\n" ; |
336 | code += Indent + " * @return" + GenTypeBasic(field.value.type) + "\n" ; |
337 | code += Indent + " */\n" ; |
338 | code += Indent + "public function get" ; |
339 | code += MakeCamel(field.name); |
340 | code += "($j)\n" ; |
341 | code += Indent + "{\n" ; |
342 | code += Indent + Indent + "$o = $this->__offset(" + |
343 | NumToString(field.value.offset) + ");\n" ; |
344 | code += Indent + Indent + "$obj = new " ; |
345 | code += MakeCamel(GenTypeGet(field.value.type)) + "();\n" ; |
346 | |
347 | switch (field.value.type.base_type) { |
348 | case BASE_TYPE_STRUCT: |
349 | if (struct_def.fixed) { |
350 | code += Indent + Indent; |
351 | code += "return $o != 0 ? $obj->init($this->bb_pos +" + |
352 | NumToString(field.value.offset) + ", $this->bb) : null;\n" ; |
353 | } else { |
354 | code += Indent + Indent + "return $o != 0 ? $obj->init(" ; |
355 | code += field.value.type.struct_def->fixed |
356 | ? "$o + $this->bb_pos" |
357 | : "$this->__indirect($o + $this->bb_pos)" ; |
358 | code += ", $this->bb) : null;\n" ; |
359 | } |
360 | break; |
361 | case BASE_TYPE_STRING: |
362 | code += "// base_type_string\n" ; |
363 | // TODO(chobie): do we need this? |
364 | break; |
365 | case BASE_TYPE_VECTOR: |
366 | if (vectortype.base_type == BASE_TYPE_STRUCT) { |
367 | code += Indent + Indent + "return $o != 0 ? $obj->init(" ; |
368 | if (vectortype.struct_def->fixed) { |
369 | code += "$this->__vector($o) + $j *" ; |
370 | code += NumToString(InlineSize(vectortype)); |
371 | } else { |
372 | code += "$this->__indirect($this->__vector($o) + $j * " ; |
373 | code += NumToString(InlineSize(vectortype)) + ")" ; |
374 | } |
375 | code += ", $this->bb) : null;\n" ; |
376 | } |
377 | break; |
378 | case BASE_TYPE_UNION: |
379 | code += Indent + Indent + "return $o != 0 ? $this->" ; |
380 | code += GenGetter(field.value.type) + "($obj, $o); null;\n" ; |
381 | break; |
382 | default: break; |
383 | } |
384 | |
385 | code += Indent + "}\n\n" ; |
386 | } |
387 | |
388 | // Get the value of a vector's non-struct member. Uses a named return |
389 | // argument to conveniently set the zero value for the result. |
390 | void GetMemberOfVectorOfNonStruct(const FieldDef &field, |
391 | std::string *code_ptr) { |
392 | std::string &code = *code_ptr; |
393 | auto vectortype = field.value.type.VectorType(); |
394 | |
395 | code += Indent + "/**\n" ; |
396 | code += Indent + " * @param int offset\n" ; |
397 | code += Indent + " * @return " + GenTypeGet(field.value.type) + "\n" ; |
398 | code += Indent + " */\n" ; |
399 | code += Indent + "public function get" ; |
400 | code += MakeCamel(field.name); |
401 | code += "($j)\n" ; |
402 | code += Indent + "{\n" ; |
403 | code += Indent + Indent + "$o = $this->__offset(" + |
404 | NumToString(field.value.offset) + ");\n" ; |
405 | |
406 | if (field.value.type.VectorType().base_type == BASE_TYPE_STRING) { |
407 | code += Indent + Indent; |
408 | code += "return $o != 0 ? $this->__string($this->__vector($o) + $j * " ; |
409 | code += NumToString(InlineSize(vectortype)) + ") : " ; |
410 | code += GenDefaultValue(field.value) + ";\n" ; |
411 | } else { |
412 | code += Indent + Indent + "return $o != 0 ? $this->bb->get" ; |
413 | code += MakeCamel(GenTypeGet(field.value.type)); |
414 | code += "($this->__vector($o) + $j * " ; |
415 | code += NumToString(InlineSize(vectortype)) + ") : " ; |
416 | code += GenDefaultValue(field.value) + ";\n" ; |
417 | } |
418 | code += Indent + "}\n\n" ; |
419 | } |
420 | |
421 | // Get the value of a vector's union member. Uses a named return |
422 | // argument to conveniently set the zero value for the result. |
423 | void GetMemberOfVectorOfUnion(const FieldDef &field, std::string *code_ptr) { |
424 | std::string &code = *code_ptr; |
425 | auto vectortype = field.value.type.VectorType(); |
426 | |
427 | code += Indent + "/**\n" ; |
428 | code += Indent + " * @param int offset\n" ; |
429 | code += Indent + " * @return " + GenTypeGet(field.value.type) + "\n" ; |
430 | code += Indent + " */\n" ; |
431 | code += Indent + "public function get" ; |
432 | code += MakeCamel(field.name); |
433 | code += "($j, $obj)\n" ; |
434 | code += Indent + "{\n" ; |
435 | code += Indent + Indent + "$o = $this->__offset(" + |
436 | NumToString(field.value.offset) + ");\n" ; |
437 | code += Indent + Indent + "return $o != 0 ? " ; |
438 | code += "$this->__union($obj, $this->__vector($o) + $j * " ; |
439 | code += NumToString(InlineSize(vectortype)) + " - $this->bb_pos) : null;\n" ; |
440 | code += Indent + "}\n\n" ; |
441 | } |
442 | |
443 | // Recursively generate arguments for a constructor, to deal with nested |
444 | // structs. |
445 | static void StructBuilderArgs(const StructDef &struct_def, |
446 | const char *nameprefix, std::string *code_ptr) { |
447 | for (auto it = struct_def.fields.vec.begin(); |
448 | it != struct_def.fields.vec.end(); ++it) { |
449 | auto &field = **it; |
450 | if (IsStruct(field.value.type)) { |
451 | // Generate arguments for a struct inside a struct. To ensure names |
452 | // don't clash, and to make it obvious |
453 | // these arguments are constructing |
454 | // a nested struct, prefix the name with the field name. |
455 | StructBuilderArgs(*field.value.type.struct_def, |
456 | (nameprefix + (field.name + "_" )).c_str(), code_ptr); |
457 | } else { |
458 | std::string &code = *code_ptr; |
459 | code += std::string(", $" ) + nameprefix; |
460 | code += MakeCamel(field.name, false); |
461 | } |
462 | } |
463 | } |
464 | |
465 | // Recursively generate struct construction statements and instert manual |
466 | // padding. |
467 | static void StructBuilderBody(const StructDef &struct_def, |
468 | const char *nameprefix, std::string *code_ptr) { |
469 | std::string &code = *code_ptr; |
470 | code += Indent + Indent + "$builder->prep(" ; |
471 | code += NumToString(struct_def.minalign) + ", " ; |
472 | code += NumToString(struct_def.bytesize) + ");\n" ; |
473 | for (auto it = struct_def.fields.vec.rbegin(); |
474 | it != struct_def.fields.vec.rend(); ++it) { |
475 | auto &field = **it; |
476 | if (field.padding) { |
477 | code += Indent + Indent + "$builder->pad(" ; |
478 | code += NumToString(field.padding) + ");\n" ; |
479 | } |
480 | if (IsStruct(field.value.type)) { |
481 | StructBuilderBody(*field.value.type.struct_def, |
482 | (nameprefix + (field.name + "_" )).c_str(), code_ptr); |
483 | } else { |
484 | code += Indent + Indent + "$builder->put" + GenMethod(field) + "($" ; |
485 | code += nameprefix + MakeCamel(field.name, false) + ");\n" ; |
486 | } |
487 | } |
488 | } |
489 | |
490 | // Get the value of a table's starting offset. |
491 | static void GetStartOfTable(const StructDef &struct_def, |
492 | std::string *code_ptr) { |
493 | std::string &code = *code_ptr; |
494 | |
495 | code += Indent + "/**\n" ; |
496 | code += Indent + " * @param FlatBufferBuilder $builder\n" ; |
497 | code += Indent + " * @return void\n" ; |
498 | code += Indent + " */\n" ; |
499 | code += Indent + "public static function start" + struct_def.name; |
500 | code += "(FlatBufferBuilder $builder)\n" ; |
501 | code += Indent + "{\n" ; |
502 | code += Indent + Indent + "$builder->StartObject(" ; |
503 | code += NumToString(struct_def.fields.vec.size()); |
504 | code += ");\n" ; |
505 | code += Indent + "}\n\n" ; |
506 | |
507 | code += Indent + "/**\n" ; |
508 | code += Indent + " * @param FlatBufferBuilder $builder\n" ; |
509 | code += Indent + " * @return " + struct_def.name + "\n" ; |
510 | code += Indent + " */\n" ; |
511 | code += Indent + "public static function create" + struct_def.name; |
512 | code += "(FlatBufferBuilder $builder, " ; |
513 | |
514 | for (auto it = struct_def.fields.vec.begin(); |
515 | it != struct_def.fields.vec.end(); ++it) { |
516 | auto &field = **it; |
517 | |
518 | if (field.deprecated) continue; |
519 | code += "$" + field.name; |
520 | if (!(it == (--struct_def.fields.vec.end()))) { code += ", " ; } |
521 | } |
522 | code += ")\n" ; |
523 | code += Indent + "{\n" ; |
524 | code += Indent + Indent + "$builder->startObject(" ; |
525 | code += NumToString(struct_def.fields.vec.size()); |
526 | code += ");\n" ; |
527 | for (auto it = struct_def.fields.vec.begin(); |
528 | it != struct_def.fields.vec.end(); ++it) { |
529 | auto &field = **it; |
530 | if (field.deprecated) continue; |
531 | |
532 | code += Indent + Indent + "self::add" ; |
533 | code += MakeCamel(field.name) + "($builder, $" + field.name + ");\n" ; |
534 | } |
535 | |
536 | code += Indent + Indent + "$o = $builder->endObject();\n" ; |
537 | |
538 | for (auto it = struct_def.fields.vec.begin(); |
539 | it != struct_def.fields.vec.end(); ++it) { |
540 | auto &field = **it; |
541 | if (!field.deprecated && field.required) { |
542 | code += Indent + Indent + "$builder->required($o, " ; |
543 | code += NumToString(field.value.offset); |
544 | code += "); // " + field.name + "\n" ; |
545 | } |
546 | } |
547 | code += Indent + Indent + "return $o;\n" ; |
548 | code += Indent + "}\n\n" ; |
549 | } |
550 | |
551 | // Set the value of a table's field. |
552 | static void BuildFieldOfTable(const FieldDef &field, const size_t offset, |
553 | std::string *code_ptr) { |
554 | std::string &code = *code_ptr; |
555 | |
556 | code += Indent + "/**\n" ; |
557 | code += Indent + " * @param FlatBufferBuilder $builder\n" ; |
558 | code += Indent + " * @param " + GenTypeBasic(field.value.type) + "\n" ; |
559 | code += Indent + " * @return void\n" ; |
560 | code += Indent + " */\n" ; |
561 | code += Indent + "public static function " ; |
562 | code += "add" + MakeCamel(field.name); |
563 | code += "(FlatBufferBuilder $builder, " ; |
564 | code += "$" + MakeCamel(field.name, false); |
565 | code += ")\n" ; |
566 | code += Indent + "{\n" ; |
567 | code += Indent + Indent + "$builder->add" ; |
568 | code += GenMethod(field) + "X(" ; |
569 | code += NumToString(offset) + ", " ; |
570 | |
571 | code += "$" + MakeCamel(field.name, false); |
572 | code += ", " ; |
573 | |
574 | if (field.value.type.base_type == BASE_TYPE_BOOL) { |
575 | code += "false" ; |
576 | } else { |
577 | code += field.value.constant; |
578 | } |
579 | code += ");\n" ; |
580 | code += Indent + "}\n\n" ; |
581 | } |
582 | |
583 | // Set the value of one of the members of a table's vector. |
584 | static void BuildVectorOfTable(const FieldDef &field, std::string *code_ptr) { |
585 | std::string &code = *code_ptr; |
586 | |
587 | auto vector_type = field.value.type.VectorType(); |
588 | auto alignment = InlineAlignment(vector_type); |
589 | auto elem_size = InlineSize(vector_type); |
590 | code += Indent + "/**\n" ; |
591 | code += Indent + " * @param FlatBufferBuilder $builder\n" ; |
592 | code += Indent + " * @param array offset array\n" ; |
593 | code += Indent + " * @return int vector offset\n" ; |
594 | code += Indent + " */\n" ; |
595 | code += Indent + "public static function create" ; |
596 | code += MakeCamel(field.name); |
597 | code += "Vector(FlatBufferBuilder $builder, array $data)\n" ; |
598 | code += Indent + "{\n" ; |
599 | code += Indent + Indent + "$builder->startVector(" ; |
600 | code += NumToString(elem_size); |
601 | code += ", count($data), " + NumToString(alignment); |
602 | code += ");\n" ; |
603 | code += Indent + Indent; |
604 | code += "for ($i = count($data) - 1; $i >= 0; $i--) {\n" ; |
605 | if (IsScalar(field.value.type.VectorType().base_type)) { |
606 | code += Indent + Indent + Indent; |
607 | code += "$builder->put" ; |
608 | code += MakeCamel(GenTypeBasic(field.value.type.VectorType())); |
609 | code += "($data[$i]);\n" ; |
610 | } else { |
611 | code += Indent + Indent + Indent; |
612 | code += "$builder->putOffset($data[$i]);\n" ; |
613 | } |
614 | code += Indent + Indent + "}\n" ; |
615 | code += Indent + Indent + "return $builder->endVector();\n" ; |
616 | code += Indent + "}\n\n" ; |
617 | |
618 | code += Indent + "/**\n" ; |
619 | code += Indent + " * @param FlatBufferBuilder $builder\n" ; |
620 | code += Indent + " * @param int $numElems\n" ; |
621 | code += Indent + " * @return void\n" ; |
622 | code += Indent + " */\n" ; |
623 | code += Indent + "public static function start" ; |
624 | code += MakeCamel(field.name); |
625 | code += "Vector(FlatBufferBuilder $builder, $numElems)\n" ; |
626 | code += Indent + "{\n" ; |
627 | code += Indent + Indent + "$builder->startVector(" ; |
628 | code += NumToString(elem_size); |
629 | code += ", $numElems, " + NumToString(alignment); |
630 | code += ");\n" ; |
631 | code += Indent + "}\n\n" ; |
632 | } |
633 | |
634 | // Get the offset of the end of a table. |
635 | void GetEndOffsetOnTable(const StructDef &struct_def, std::string *code_ptr) { |
636 | std::string &code = *code_ptr; |
637 | |
638 | code += Indent + "/**\n" ; |
639 | code += Indent + " * @param FlatBufferBuilder $builder\n" ; |
640 | code += Indent + " * @return int table offset\n" ; |
641 | code += Indent + " */\n" ; |
642 | code += Indent + "public static function end" + struct_def.name; |
643 | code += "(FlatBufferBuilder $builder)\n" ; |
644 | code += Indent + "{\n" ; |
645 | code += Indent + Indent + "$o = $builder->endObject();\n" ; |
646 | |
647 | for (auto it = struct_def.fields.vec.begin(); |
648 | it != struct_def.fields.vec.end(); ++it) { |
649 | auto &field = **it; |
650 | if (!field.deprecated && field.required) { |
651 | code += Indent + Indent + "$builder->required($o, " ; |
652 | code += NumToString(field.value.offset); |
653 | code += "); // " + field.name + "\n" ; |
654 | } |
655 | } |
656 | code += Indent + Indent + "return $o;\n" ; |
657 | code += Indent + "}\n" ; |
658 | |
659 | if (parser_.root_struct_def_ == &struct_def) { |
660 | code += "\n" ; |
661 | code += Indent + "public static function finish" ; |
662 | code += struct_def.name; |
663 | code += "Buffer(FlatBufferBuilder $builder, $offset)\n" ; |
664 | code += Indent + "{\n" ; |
665 | code += Indent + Indent + "$builder->finish($offset" ; |
666 | |
667 | if (parser_.file_identifier_.length()) |
668 | code += ", \"" + parser_.file_identifier_ + "\"" ; |
669 | code += ");\n" ; |
670 | code += Indent + "}\n" ; |
671 | } |
672 | } |
673 | |
674 | // Generate a struct field, conditioned on its child type(s). |
675 | void GenStructAccessor(const StructDef &struct_def, const FieldDef &field, |
676 | std::string *code_ptr) { |
677 | GenComment(field.doc_comment, code_ptr, nullptr); |
678 | |
679 | if (IsScalar(field.value.type.base_type)) { |
680 | if (struct_def.fixed) { |
681 | GetScalarFieldOfStruct(field, code_ptr); |
682 | } else { |
683 | GetScalarFieldOfTable(field, code_ptr); |
684 | } |
685 | } else { |
686 | switch (field.value.type.base_type) { |
687 | case BASE_TYPE_STRUCT: |
688 | if (struct_def.fixed) { |
689 | GetStructFieldOfStruct(field, code_ptr); |
690 | } else { |
691 | GetStructFieldOfTable(field, code_ptr); |
692 | } |
693 | break; |
694 | case BASE_TYPE_STRING: GetStringField(field, code_ptr); break; |
695 | case BASE_TYPE_VECTOR: { |
696 | auto vectortype = field.value.type.VectorType(); |
697 | if (vectortype.base_type == BASE_TYPE_UNION) { |
698 | GetMemberOfVectorOfUnion(field, code_ptr); |
699 | } else if (vectortype.base_type == BASE_TYPE_STRUCT) { |
700 | GetMemberOfVectorOfStruct(struct_def, field, code_ptr); |
701 | } else { |
702 | GetMemberOfVectorOfNonStruct(field, code_ptr); |
703 | } |
704 | break; |
705 | } |
706 | case BASE_TYPE_UNION: GetUnionField(field, code_ptr); break; |
707 | default: FLATBUFFERS_ASSERT(0); |
708 | } |
709 | } |
710 | if (field.value.type.base_type == BASE_TYPE_VECTOR) { |
711 | GetVectorLen(field, code_ptr); |
712 | if (field.value.type.element == BASE_TYPE_UCHAR) { |
713 | GetUByte(field, code_ptr); |
714 | } |
715 | } |
716 | } |
717 | |
718 | // Generate table constructors, conditioned on its members' types. |
719 | void GenTableBuilders(const StructDef &struct_def, std::string *code_ptr) { |
720 | GetStartOfTable(struct_def, code_ptr); |
721 | |
722 | for (auto it = struct_def.fields.vec.begin(); |
723 | it != struct_def.fields.vec.end(); ++it) { |
724 | auto &field = **it; |
725 | if (field.deprecated) continue; |
726 | |
727 | auto offset = it - struct_def.fields.vec.begin(); |
728 | if (field.value.type.base_type == BASE_TYPE_UNION) { |
729 | std::string &code = *code_ptr; |
730 | code += Indent + "public static function add" ; |
731 | code += MakeCamel(field.name); |
732 | code += "(FlatBufferBuilder $builder, $offset)\n" ; |
733 | code += Indent + "{\n" ; |
734 | code += Indent + Indent + "$builder->addOffsetX(" ; |
735 | code += NumToString(offset) + ", $offset, 0);\n" ; |
736 | code += Indent + "}\n\n" ; |
737 | } else { |
738 | BuildFieldOfTable(field, offset, code_ptr); |
739 | } |
740 | if (field.value.type.base_type == BASE_TYPE_VECTOR) { |
741 | BuildVectorOfTable(field, code_ptr); |
742 | } |
743 | } |
744 | |
745 | GetEndOffsetOnTable(struct_def, code_ptr); |
746 | } |
747 | |
748 | // Generate struct or table methods. |
749 | void GenStruct(const StructDef &struct_def, std::string *code_ptr) { |
750 | if (struct_def.generated) return; |
751 | |
752 | GenComment(struct_def.doc_comment, code_ptr, nullptr); |
753 | BeginClass(struct_def, code_ptr); |
754 | |
755 | if (!struct_def.fixed) { |
756 | // Generate a special accessor for the table that has been declared as |
757 | // the root type. |
758 | NewRootTypeFromBuffer(struct_def, code_ptr); |
759 | } |
760 | |
761 | std::string &code = *code_ptr; |
762 | if (!struct_def.fixed) { |
763 | if (parser_.file_identifier_.length()) { |
764 | // Return the identifier |
765 | code += Indent + "public static function " + struct_def.name; |
766 | code += "Identifier()\n" ; |
767 | code += Indent + "{\n" ; |
768 | code += Indent + Indent + "return \"" ; |
769 | code += parser_.file_identifier_ + "\";\n" ; |
770 | code += Indent + "}\n\n" ; |
771 | |
772 | // Check if a buffer has the identifier. |
773 | code += Indent + "public static function " + struct_def.name; |
774 | code += "BufferHasIdentifier(ByteBuffer $buf)\n" ; |
775 | code += Indent + "{\n" ; |
776 | code += Indent + Indent + "return self::" ; |
777 | code += "__has_identifier($buf, self::" ; |
778 | code += struct_def.name + "Identifier());\n" ; |
779 | code += Indent + "}\n\n" ; |
780 | } |
781 | |
782 | if (parser_.file_extension_.length()) { |
783 | // Return the extension |
784 | code += Indent + "public static function " + struct_def.name; |
785 | code += "Extension()\n" ; |
786 | code += Indent + "{\n" ; |
787 | code += Indent + Indent + "return \"" + parser_.file_extension_; |
788 | code += "\";\n" ; |
789 | code += Indent + "}\n\n" ; |
790 | } |
791 | } |
792 | |
793 | // Generate the Init method that sets the field in a pre-existing |
794 | // accessor object. This is to allow object reuse. |
795 | InitializeExisting(struct_def, code_ptr); |
796 | for (auto it = struct_def.fields.vec.begin(); |
797 | it != struct_def.fields.vec.end(); ++it) { |
798 | auto &field = **it; |
799 | if (field.deprecated) continue; |
800 | |
801 | GenStructAccessor(struct_def, field, code_ptr); |
802 | } |
803 | |
804 | if (struct_def.fixed) { |
805 | // create a struct constructor function |
806 | GenStructBuilder(struct_def, code_ptr); |
807 | } else { |
808 | // Create a set of functions that allow table construction. |
809 | GenTableBuilders(struct_def, code_ptr); |
810 | } |
811 | EndClass(code_ptr); |
812 | } |
813 | |
814 | // Generate enum declarations. |
815 | static void GenEnum(const EnumDef &enum_def, std::string *code_ptr) { |
816 | if (enum_def.generated) return; |
817 | |
818 | GenComment(enum_def.doc_comment, code_ptr, nullptr); |
819 | BeginEnum(enum_def.name, code_ptr); |
820 | for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) { |
821 | auto &ev = **it; |
822 | GenComment(ev.doc_comment, code_ptr, nullptr); |
823 | EnumMember(enum_def, ev, code_ptr); |
824 | } |
825 | |
826 | std::string &code = *code_ptr; |
827 | code += "\n" ; |
828 | code += Indent + "private static $names = array(\n" ; |
829 | for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) { |
830 | auto &ev = **it; |
831 | code += Indent + Indent + enum_def.name + "::" + ev.name + "=>" + "\"" + ev.name + "\",\n" ; |
832 | } |
833 | |
834 | code += Indent + ");\n\n" ; |
835 | code += Indent + "public static function Name($e)\n" ; |
836 | code += Indent + "{\n" ; |
837 | code += Indent + Indent + "if (!isset(self::$names[$e])) {\n" ; |
838 | code += Indent + Indent + Indent + "throw new \\Exception();\n" ; |
839 | code += Indent + Indent + "}\n" ; |
840 | code += Indent + Indent + "return self::$names[$e];\n" ; |
841 | code += Indent + "}\n" ; |
842 | EndEnum(code_ptr); |
843 | } |
844 | |
845 | // Returns the function name that is able to read a value of the given type. |
846 | static std::string GenGetter(const Type &type) { |
847 | switch (type.base_type) { |
848 | case BASE_TYPE_STRING: return "__string" ; |
849 | case BASE_TYPE_STRUCT: return "__struct" ; |
850 | case BASE_TYPE_UNION: return "__union" ; |
851 | case BASE_TYPE_VECTOR: return GenGetter(type.VectorType()); |
852 | default: return "Get" ; |
853 | } |
854 | } |
855 | |
856 | // Returns the method name for use with add/put calls. |
857 | static std::string GenMethod(const FieldDef &field) { |
858 | return IsScalar(field.value.type.base_type) |
859 | ? MakeCamel(GenTypeBasic(field.value.type)) |
860 | : (IsStruct(field.value.type) ? "Struct" : "Offset" ); |
861 | } |
862 | |
863 | static std::string GenTypeBasic(const Type &type) { |
864 | static const char *ctypename[] = { |
865 | // clang-format off |
866 | #define FLATBUFFERS_TD(ENUM, IDLTYPE, \ |
867 | CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, RTYPE) \ |
868 | #NTYPE, |
869 | FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD) |
870 | #undef FLATBUFFERS_TD |
871 | // clang-format on |
872 | }; |
873 | return ctypename[type.base_type]; |
874 | } |
875 | |
876 | std::string GenDefaultValue(const Value &value) { |
877 | if (value.type.enum_def) { |
878 | if (auto val = value.type.enum_def->ReverseLookup( |
879 | StringToInt(value.constant.c_str()), false)) { |
880 | return WrapInNameSpace(*value.type.enum_def) + "::" + val->name; |
881 | } |
882 | } |
883 | |
884 | switch (value.type.base_type) { |
885 | case BASE_TYPE_BOOL: return value.constant == "0" ? "false" : "true" ; |
886 | |
887 | case BASE_TYPE_STRING: return "null" ; |
888 | |
889 | case BASE_TYPE_LONG: |
890 | case BASE_TYPE_ULONG: |
891 | if (value.constant != "0" ) { |
892 | int64_t constant = StringToInt(value.constant.c_str()); |
893 | return NumToString(constant); |
894 | } |
895 | return "0" ; |
896 | |
897 | default: return value.constant; |
898 | } |
899 | } |
900 | |
901 | static std::string GenTypePointer(const Type &type) { |
902 | switch (type.base_type) { |
903 | case BASE_TYPE_STRING: return "string" ; |
904 | case BASE_TYPE_VECTOR: return GenTypeGet(type.VectorType()); |
905 | case BASE_TYPE_STRUCT: return type.struct_def->name; |
906 | case BASE_TYPE_UNION: |
907 | // fall through |
908 | default: return "Table" ; |
909 | } |
910 | } |
911 | |
912 | static std::string GenTypeGet(const Type &type) { |
913 | return IsScalar(type.base_type) ? GenTypeBasic(type) : GenTypePointer(type); |
914 | } |
915 | |
916 | // Create a struct with a builder and the struct's arguments. |
917 | static void GenStructBuilder(const StructDef &struct_def, |
918 | std::string *code_ptr) { |
919 | std::string &code = *code_ptr; |
920 | code += "\n" ; |
921 | code += Indent + "/**\n" ; |
922 | code += Indent + " * @return int offset\n" ; |
923 | code += Indent + " */\n" ; |
924 | code += Indent + "public static function create" + struct_def.name; |
925 | code += "(FlatBufferBuilder $builder" ; |
926 | StructBuilderArgs(struct_def, "" , code_ptr); |
927 | code += ")\n" ; |
928 | code += Indent + "{\n" ; |
929 | |
930 | StructBuilderBody(struct_def, "" , code_ptr); |
931 | |
932 | code += Indent + Indent + "return $builder->offset();\n" ; |
933 | code += Indent + "}\n" ; |
934 | } |
935 | }; |
936 | } // namespace php |
937 | |
938 | bool GeneratePhp(const Parser &parser, const std::string &path, |
939 | const std::string &file_name) { |
940 | php::PhpGenerator generator(parser, path, file_name); |
941 | return generator.generate(); |
942 | } |
943 | } // namespace flatbuffers |
944 | |