xref: /aosp_15_r20/external/flatbuffers/src/idl_gen_php.cpp (revision 890232f25432b36107d06881e0a25aaa6b473652)
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:
PhpGenerator(const Parser & parser,const std::string & path,const std::string & file_name)32   PhpGenerator(const Parser &parser, const std::string &path,
33                const std::string &file_name)
34       : BaseGenerator(parser, path, file_name, "\\", "\\", "php") {}
generate()35   bool generate() {
36     if (!GenerateEnums()) return false;
37     if (!GenerateStructs()) return false;
38     return true;
39   }
40 
41  private:
GenerateEnums()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 
GenerateStructs()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.
BeginFile(const std::string & name_space_name,const bool needs_imports,std::string * code_ptr)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.
SaveType(const Definition & def,const std::string & classcode,bool needs_imports)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.
BeginClass(const StructDef & struct_def,std::string * code_ptr)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 
EndClass(std::string * code_ptr)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.
BeginEnum(const std::string & class_name,std::string * code_ptr)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.
EnumMember(const EnumDef & enum_def,const EnumVal & ev,std::string * code_ptr)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 += enum_def.ToString(ev) + ";\n";
129   }
130 
131   // End enum code.
EndEnum(std::string * code_ptr)132   static void EndEnum(std::string *code_ptr) {
133     std::string &code = *code_ptr;
134     code += "}\n";
135   }
136 
137   // Initialize a new struct or table from existing data.
NewRootTypeFromBuffer(const StructDef & struct_def,std::string * code_ptr)138   static void NewRootTypeFromBuffer(const StructDef &struct_def,
139                                     std::string *code_ptr) {
140     std::string &code = *code_ptr;
141 
142     code += Indent + "/**\n";
143     code += Indent + " * @param ByteBuffer $bb\n";
144     code += Indent + " * @return " + struct_def.name + "\n";
145     code += Indent + " */\n";
146     code += Indent + "public static function getRootAs";
147     code += struct_def.name;
148     code += "(ByteBuffer $bb)\n";
149     code += Indent + "{\n";
150 
151     code += Indent + Indent + "$obj = new " + struct_def.name + "();\n";
152     code += Indent + Indent;
153     code += "return ($obj->init($bb->getInt($bb->getPosition())";
154     code += " + $bb->getPosition(), $bb));\n";
155     code += Indent + "}\n\n";
156   }
157 
158   // Initialize an existing object with other data, to avoid an allocation.
InitializeExisting(const StructDef & struct_def,std::string * code_ptr)159   static void InitializeExisting(const StructDef &struct_def,
160                                  std::string *code_ptr) {
161     std::string &code = *code_ptr;
162 
163     code += Indent + "/**\n";
164     code += Indent + " * @param int $_i offset\n";
165     code += Indent + " * @param ByteBuffer $_bb\n";
166     code += Indent + " * @return " + struct_def.name + "\n";
167     code += Indent + " **/\n";
168     code += Indent + "public function init($_i, ByteBuffer $_bb)\n";
169     code += Indent + "{\n";
170     code += Indent + Indent + "$this->bb_pos = $_i;\n";
171     code += Indent + Indent + "$this->bb = $_bb;\n";
172     code += Indent + Indent + "return $this;\n";
173     code += Indent + "}\n\n";
174   }
175 
176   // Get the length of a vector.
GetVectorLen(const FieldDef & field,std::string * code_ptr)177   static void GetVectorLen(const FieldDef &field, std::string *code_ptr) {
178     std::string &code = *code_ptr;
179 
180     code += Indent + "/**\n";
181     code += Indent + " * @return int\n";
182     code += Indent + " */\n";
183     code += Indent + "public function get";
184     code += ConvertCase(field.name, Case::kUpperCamel) + "Length()\n";
185     code += Indent + "{\n";
186     code += Indent + Indent + "$o = $this->__offset(";
187     code += NumToString(field.value.offset) + ");\n";
188     code += Indent + Indent;
189     code += "return $o != 0 ? $this->__vector_len($o) : 0;\n";
190     code += Indent + "}\n\n";
191   }
192 
193   // Get a [ubyte] vector as a byte array.
GetUByte(const FieldDef & field,std::string * code_ptr)194   static void GetUByte(const FieldDef &field, std::string *code_ptr) {
195     std::string &code = *code_ptr;
196 
197     code += Indent + "/**\n";
198     code += Indent + " * @return string\n";
199     code += Indent + " */\n";
200     code += Indent + "public function get";
201     code += ConvertCase(field.name, Case::kUpperCamel) + "Bytes()\n";
202     code += Indent + "{\n";
203     code += Indent + Indent + "return $this->__vector_as_bytes(";
204     code += NumToString(field.value.offset) + ");\n";
205     code += Indent + "}\n\n";
206   }
207 
208   // Get the value of a struct's scalar.
GetScalarFieldOfStruct(const FieldDef & field,std::string * code_ptr)209   static void GetScalarFieldOfStruct(const FieldDef &field,
210                                      std::string *code_ptr) {
211     std::string &code = *code_ptr;
212     std::string getter = GenGetter(field.value.type);
213 
214     code += Indent + "/**\n";
215     code += Indent + " * @return ";
216     code += GenTypeGet(field.value.type) + "\n";
217     code += Indent + " */\n";
218     code += Indent + "public function " + getter;
219     code += ConvertCase(field.name, Case::kUpperCamel) + "()\n";
220     code += Indent + "{\n";
221     code += Indent + Indent + "return ";
222 
223     code += "$this->bb->get";
224     code += ConvertCase(GenTypeGet(field.value.type), Case::kUpperCamel);
225     code += "($this->bb_pos + ";
226     code += NumToString(field.value.offset) + ")";
227     code += ";\n";
228 
229     code += Indent + "}\n\n";
230   }
231 
232   // Get the value of a table's scalar.
GetScalarFieldOfTable(const FieldDef & field,std::string * code_ptr)233   void GetScalarFieldOfTable(const FieldDef &field, std::string *code_ptr) {
234     std::string &code = *code_ptr;
235 
236     code += Indent + "/**\n";
237     code += Indent + " * @return " + GenTypeGet(field.value.type) + "\n";
238     code += Indent + " */\n";
239     code += Indent + "public function get";
240     code += ConvertCase(field.name, Case::kUpperCamel);
241     code += "()\n";
242     code += Indent + "{\n";
243     code += Indent + Indent + "$o = $this->__offset(" +
244             NumToString(field.value.offset) + ");\n" + Indent + Indent +
245             "return $o != 0 ? ";
246     code += "$this->bb->get";
247     code += ConvertCase(GenTypeGet(field.value.type), Case::kUpperCamel) +
248             "($o + $this->bb_pos)";
249     code += " : " + GenDefaultValue(field.value) + ";\n";
250     code += Indent + "}\n\n";
251   }
252 
253   // Get a struct by initializing an existing struct.
254   // Specific to Struct.
GetStructFieldOfStruct(const FieldDef & field,std::string * code_ptr)255   void GetStructFieldOfStruct(const FieldDef &field, std::string *code_ptr) {
256     std::string &code = *code_ptr;
257 
258     code += Indent + "/**\n";
259     code += Indent + " * @return " + GenTypeGet(field.value.type) + "\n";
260     code += Indent + " */\n";
261     code += Indent + "public function get";
262     code += ConvertCase(field.name, Case::kUpperCamel) + "()\n";
263     code += Indent + "{\n";
264     code += Indent + Indent + "$obj = new ";
265     code += GenTypeGet(field.value.type) + "();\n";
266     code += Indent + Indent + "$obj->init($this->bb_pos + ";
267     code += NumToString(field.value.offset) + ", $this->bb);";
268     code += "\n" + Indent + Indent + "return $obj;\n";
269     code += Indent + "}\n\n";
270   }
271 
272   // Get a struct by initializing an existing struct.
273   // Specific to Table.
GetStructFieldOfTable(const FieldDef & field,std::string * code_ptr)274   void GetStructFieldOfTable(const FieldDef &field, std::string *code_ptr) {
275     std::string &code = *code_ptr;
276 
277     code += Indent + "public function get";
278     code += ConvertCase(field.name, Case::kUpperCamel);
279     code += "()\n";
280     code += Indent + "{\n";
281     code += Indent + Indent + "$obj = new ";
282     code +=
283         ConvertCase(GenTypeGet(field.value.type), Case::kUpperCamel) + "();\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.
GetStringField(const FieldDef & field,std::string * code_ptr)298   void GetStringField(const FieldDef &field, std::string *code_ptr) {
299     std::string &code = *code_ptr;
300     code += Indent + "public function get";
301     code += ConvertCase(field.name, Case::kUpperCamel);
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.
GetUnionField(const FieldDef & field,std::string * code_ptr)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 += ConvertCase(field.name, Case::kUpperCamel) + "($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.
GetMemberOfVectorOfStruct(const StructDef & struct_def,const FieldDef & field,std::string * code_ptr)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 += ConvertCase(field.name, Case::kUpperCamel);
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 +=
346         ConvertCase(GenTypeGet(field.value.type), Case::kUpperCamel) + "();\n";
347 
348     switch (field.value.type.base_type) {
349       case BASE_TYPE_STRUCT:
350         if (struct_def.fixed) {
351           code += Indent + Indent;
352           code += "return $o != 0 ? $obj->init($this->bb_pos +" +
353                   NumToString(field.value.offset) + ", $this->bb) : null;\n";
354         } else {
355           code += Indent + Indent + "return $o != 0 ? $obj->init(";
356           code += field.value.type.struct_def->fixed
357                       ? "$o + $this->bb_pos"
358                       : "$this->__indirect($o + $this->bb_pos)";
359           code += ", $this->bb) : null;\n";
360         }
361         break;
362       case BASE_TYPE_STRING:
363         code += "// base_type_string\n";
364         // TODO(chobie): do we need this?
365         break;
366       case BASE_TYPE_VECTOR:
367         if (vectortype.base_type == BASE_TYPE_STRUCT) {
368           code += Indent + Indent + "return $o != 0 ? $obj->init(";
369           if (vectortype.struct_def->fixed) {
370             code += "$this->__vector($o) + $j *";
371             code += NumToString(InlineSize(vectortype));
372           } else {
373             code += "$this->__indirect($this->__vector($o) + $j * ";
374             code += NumToString(InlineSize(vectortype)) + ")";
375           }
376           code += ", $this->bb) : null;\n";
377         }
378         break;
379       case BASE_TYPE_UNION:
380         code += Indent + Indent + "return $o != 0 ? $this->";
381         code += GenGetter(field.value.type) + "($obj, $o); null;\n";
382         break;
383       default: break;
384     }
385 
386     code += Indent + "}\n\n";
387   }
388 
389   // Get the value of a vector's non-struct member. Uses a named return
390   // argument to conveniently set the zero value for the result.
GetMemberOfVectorOfNonStruct(const FieldDef & field,std::string * code_ptr)391   void GetMemberOfVectorOfNonStruct(const FieldDef &field,
392                                     std::string *code_ptr) {
393     std::string &code = *code_ptr;
394     auto vectortype = field.value.type.VectorType();
395 
396     code += Indent + "/**\n";
397     code += Indent + " * @param int offset\n";
398     code += Indent + " * @return " + GenTypeGet(field.value.type) + "\n";
399     code += Indent + " */\n";
400     code += Indent + "public function get";
401     code += ConvertCase(field.name, Case::kUpperCamel);
402     code += "($j)\n";
403     code += Indent + "{\n";
404     code += Indent + Indent + "$o = $this->__offset(" +
405             NumToString(field.value.offset) + ");\n";
406 
407     if (IsString(field.value.type.VectorType())) {
408       code += Indent + Indent;
409       code += "return $o != 0 ? $this->__string($this->__vector($o) + $j * ";
410       code += NumToString(InlineSize(vectortype)) + ") : ";
411       code += GenDefaultValue(field.value) + ";\n";
412     } else {
413       code += Indent + Indent + "return $o != 0 ? $this->bb->get";
414       code += ConvertCase(GenTypeGet(field.value.type), Case::kUpperCamel);
415       code += "($this->__vector($o) + $j * ";
416       code += NumToString(InlineSize(vectortype)) + ") : ";
417       code += GenDefaultValue(field.value) + ";\n";
418     }
419     code += Indent + "}\n\n";
420   }
421 
422   // Get the value of a vector's union member. Uses a named return
423   // argument to conveniently set the zero value for the result.
GetMemberOfVectorOfUnion(const FieldDef & field,std::string * code_ptr)424   void GetMemberOfVectorOfUnion(const FieldDef &field, std::string *code_ptr) {
425     std::string &code = *code_ptr;
426     auto vectortype = field.value.type.VectorType();
427 
428     code += Indent + "/**\n";
429     code += Indent + " * @param int offset\n";
430     code += Indent + " * @return " + GenTypeGet(field.value.type) + "\n";
431     code += Indent + " */\n";
432     code += Indent + "public function get";
433     code += ConvertCase(field.name, Case::kUpperCamel);
434     code += "($j, $obj)\n";
435     code += Indent + "{\n";
436     code += Indent + Indent + "$o = $this->__offset(" +
437             NumToString(field.value.offset) + ");\n";
438     code += Indent + Indent + "return $o != 0 ? ";
439     code += "$this->__union($obj, $this->__vector($o) + $j * ";
440     code += NumToString(InlineSize(vectortype)) + " - $this->bb_pos) : null;\n";
441     code += Indent + "}\n\n";
442   }
443 
444   // Recursively generate arguments for a constructor, to deal with nested
445   // structs.
StructBuilderArgs(const StructDef & struct_def,const char * nameprefix,std::string * code_ptr)446   static void StructBuilderArgs(const StructDef &struct_def,
447                                 const char *nameprefix, std::string *code_ptr) {
448     for (auto it = struct_def.fields.vec.begin();
449          it != struct_def.fields.vec.end(); ++it) {
450       auto &field = **it;
451       if (IsStruct(field.value.type)) {
452         // Generate arguments for a struct inside a struct. To ensure names
453         // don't clash, and to make it obvious
454         // these arguments are constructing
455         // a nested struct, prefix the name with the field name.
456         StructBuilderArgs(*field.value.type.struct_def,
457                           (nameprefix + (field.name + "_")).c_str(), code_ptr);
458       } else {
459         std::string &code = *code_ptr;
460         code += std::string(", $") + nameprefix;
461         code += ConvertCase(field.name, Case::kLowerCamel);
462       }
463     }
464   }
465 
466   // Recursively generate struct construction statements and instert manual
467   // padding.
StructBuilderBody(const StructDef & struct_def,const char * nameprefix,std::string * code_ptr)468   static void StructBuilderBody(const StructDef &struct_def,
469                                 const char *nameprefix, std::string *code_ptr) {
470     std::string &code = *code_ptr;
471     code += Indent + Indent + "$builder->prep(";
472     code += NumToString(struct_def.minalign) + ", ";
473     code += NumToString(struct_def.bytesize) + ");\n";
474     for (auto it = struct_def.fields.vec.rbegin();
475          it != struct_def.fields.vec.rend(); ++it) {
476       auto &field = **it;
477       if (field.padding) {
478         code += Indent + Indent + "$builder->pad(";
479         code += NumToString(field.padding) + ");\n";
480       }
481       if (IsStruct(field.value.type)) {
482         StructBuilderBody(*field.value.type.struct_def,
483                           (nameprefix + (field.name + "_")).c_str(), code_ptr);
484       } else {
485         code += Indent + Indent + "$builder->put" + GenMethod(field) + "($";
486         code +=
487             nameprefix + ConvertCase(field.name, Case::kLowerCamel) + ");\n";
488       }
489     }
490   }
491 
492   // Get the value of a table's starting offset.
GetStartOfTable(const StructDef & struct_def,std::string * code_ptr)493   static void GetStartOfTable(const StructDef &struct_def,
494                               std::string *code_ptr) {
495     std::string &code = *code_ptr;
496 
497     code += Indent + "/**\n";
498     code += Indent + " * @param FlatBufferBuilder $builder\n";
499     code += Indent + " * @return void\n";
500     code += Indent + " */\n";
501     code += Indent + "public static function start" + struct_def.name;
502     code += "(FlatBufferBuilder $builder)\n";
503     code += Indent + "{\n";
504     code += Indent + Indent + "$builder->StartObject(";
505     code += NumToString(struct_def.fields.vec.size());
506     code += ");\n";
507     code += Indent + "}\n\n";
508 
509     code += Indent + "/**\n";
510     code += Indent + " * @param FlatBufferBuilder $builder\n";
511     code += Indent + " * @return " + struct_def.name + "\n";
512     code += Indent + " */\n";
513     code += Indent + "public static function create" + struct_def.name;
514     code += "(FlatBufferBuilder $builder, ";
515 
516     for (auto it = struct_def.fields.vec.begin();
517          it != struct_def.fields.vec.end(); ++it) {
518       auto &field = **it;
519 
520       if (field.deprecated) continue;
521       code += "$" + field.name;
522       if (!(it == (--struct_def.fields.vec.end()))) { code += ", "; }
523     }
524     code += ")\n";
525     code += Indent + "{\n";
526     code += Indent + Indent + "$builder->startObject(";
527     code += NumToString(struct_def.fields.vec.size());
528     code += ");\n";
529     for (auto it = struct_def.fields.vec.begin();
530          it != struct_def.fields.vec.end(); ++it) {
531       auto &field = **it;
532       if (field.deprecated) continue;
533 
534       code += Indent + Indent + "self::add";
535       code += ConvertCase(field.name, Case::kUpperCamel) + "($builder, $" +
536               field.name + ");\n";
537     }
538 
539     code += Indent + Indent + "$o = $builder->endObject();\n";
540 
541     for (auto it = struct_def.fields.vec.begin();
542          it != struct_def.fields.vec.end(); ++it) {
543       auto &field = **it;
544       if (!field.deprecated && field.IsRequired()) {
545         code += Indent + Indent + "$builder->required($o, ";
546         code += NumToString(field.value.offset);
547         code += ");  // " + field.name + "\n";
548       }
549     }
550     code += Indent + Indent + "return $o;\n";
551     code += Indent + "}\n\n";
552   }
553 
554   // Set the value of a table's field.
BuildFieldOfTable(const FieldDef & field,const size_t offset,std::string * code_ptr)555   static void BuildFieldOfTable(const FieldDef &field, const size_t offset,
556                                 std::string *code_ptr) {
557     std::string &code = *code_ptr;
558 
559     code += Indent + "/**\n";
560     code += Indent + " * @param FlatBufferBuilder $builder\n";
561     code += Indent + " * @param " + GenTypeBasic(field.value.type) + "\n";
562     code += Indent + " * @return void\n";
563     code += Indent + " */\n";
564     code += Indent + "public static function ";
565     code += "add" + ConvertCase(field.name, Case::kUpperCamel);
566     code += "(FlatBufferBuilder $builder, ";
567     code += "$" + ConvertCase(field.name, Case::kLowerCamel);
568     code += ")\n";
569     code += Indent + "{\n";
570     code += Indent + Indent + "$builder->add";
571     code += GenMethod(field) + "X(";
572     code += NumToString(offset) + ", ";
573 
574     code += "$" + ConvertCase(field.name, Case::kLowerCamel);
575     code += ", ";
576 
577     if (field.value.type.base_type == BASE_TYPE_BOOL) {
578       code += "false";
579     } else {
580       code += field.value.constant;
581     }
582     code += ");\n";
583     code += Indent + "}\n\n";
584   }
585 
586   // Set the value of one of the members of a table's vector.
BuildVectorOfTable(const FieldDef & field,std::string * code_ptr)587   static void BuildVectorOfTable(const FieldDef &field, std::string *code_ptr) {
588     std::string &code = *code_ptr;
589 
590     auto vector_type = field.value.type.VectorType();
591     auto alignment = InlineAlignment(vector_type);
592     auto elem_size = InlineSize(vector_type);
593     code += Indent + "/**\n";
594     code += Indent + " * @param FlatBufferBuilder $builder\n";
595     code += Indent + " * @param array offset array\n";
596     code += Indent + " * @return int vector offset\n";
597     code += Indent + " */\n";
598     code += Indent + "public static function create";
599     code += ConvertCase(field.name, Case::kUpperCamel);
600     code += "Vector(FlatBufferBuilder $builder, array $data)\n";
601     code += Indent + "{\n";
602     code += Indent + Indent + "$builder->startVector(";
603     code += NumToString(elem_size);
604     code += ", count($data), " + NumToString(alignment);
605     code += ");\n";
606     code += Indent + Indent;
607     code += "for ($i = count($data) - 1; $i >= 0; $i--) {\n";
608     if (IsScalar(field.value.type.VectorType().base_type)) {
609       code += Indent + Indent + Indent;
610       code += "$builder->put";
611       code += ConvertCase(GenTypeBasic(field.value.type.VectorType()),
612                           Case::kUpperCamel);
613       code += "($data[$i]);\n";
614     } else {
615       code += Indent + Indent + Indent;
616       code += "$builder->putOffset($data[$i]);\n";
617     }
618     code += Indent + Indent + "}\n";
619     code += Indent + Indent + "return $builder->endVector();\n";
620     code += Indent + "}\n\n";
621 
622     code += Indent + "/**\n";
623     code += Indent + " * @param FlatBufferBuilder $builder\n";
624     code += Indent + " * @param int $numElems\n";
625     code += Indent + " * @return void\n";
626     code += Indent + " */\n";
627     code += Indent + "public static function start";
628     code += ConvertCase(field.name, Case::kUpperCamel);
629     code += "Vector(FlatBufferBuilder $builder, $numElems)\n";
630     code += Indent + "{\n";
631     code += Indent + Indent + "$builder->startVector(";
632     code += NumToString(elem_size);
633     code += ", $numElems, " + NumToString(alignment);
634     code += ");\n";
635     code += Indent + "}\n\n";
636   }
637 
638   // Get the offset of the end of a table.
GetEndOffsetOnTable(const StructDef & struct_def,std::string * code_ptr)639   void GetEndOffsetOnTable(const StructDef &struct_def, std::string *code_ptr) {
640     std::string &code = *code_ptr;
641 
642     code += Indent + "/**\n";
643     code += Indent + " * @param FlatBufferBuilder $builder\n";
644     code += Indent + " * @return int table offset\n";
645     code += Indent + " */\n";
646     code += Indent + "public static function end" + struct_def.name;
647     code += "(FlatBufferBuilder $builder)\n";
648     code += Indent + "{\n";
649     code += Indent + Indent + "$o = $builder->endObject();\n";
650 
651     for (auto it = struct_def.fields.vec.begin();
652          it != struct_def.fields.vec.end(); ++it) {
653       auto &field = **it;
654       if (!field.deprecated && field.IsRequired()) {
655         code += Indent + Indent + "$builder->required($o, ";
656         code += NumToString(field.value.offset);
657         code += ");  // " + field.name + "\n";
658       }
659     }
660     code += Indent + Indent + "return $o;\n";
661     code += Indent + "}\n";
662 
663     if (parser_.root_struct_def_ == &struct_def) {
664       code += "\n";
665       code += Indent + "public static function finish";
666       code += struct_def.name;
667       code += "Buffer(FlatBufferBuilder $builder, $offset)\n";
668       code += Indent + "{\n";
669       code += Indent + Indent + "$builder->finish($offset";
670 
671       if (parser_.file_identifier_.length())
672         code += ", \"" + parser_.file_identifier_ + "\"";
673       code += ");\n";
674       code += Indent + "}\n";
675     }
676   }
677 
678   // Generate a struct field, conditioned on its child type(s).
GenStructAccessor(const StructDef & struct_def,const FieldDef & field,std::string * code_ptr)679   void GenStructAccessor(const StructDef &struct_def, const FieldDef &field,
680                          std::string *code_ptr) {
681     GenComment(field.doc_comment, code_ptr, nullptr, Indent.c_str());
682 
683     if (IsScalar(field.value.type.base_type)) {
684       if (struct_def.fixed) {
685         GetScalarFieldOfStruct(field, code_ptr);
686       } else {
687         GetScalarFieldOfTable(field, code_ptr);
688       }
689     } else {
690       switch (field.value.type.base_type) {
691         case BASE_TYPE_STRUCT:
692           if (struct_def.fixed) {
693             GetStructFieldOfStruct(field, code_ptr);
694           } else {
695             GetStructFieldOfTable(field, code_ptr);
696           }
697           break;
698         case BASE_TYPE_STRING: GetStringField(field, code_ptr); break;
699         case BASE_TYPE_VECTOR: {
700           auto vectortype = field.value.type.VectorType();
701           if (vectortype.base_type == BASE_TYPE_UNION) {
702             GetMemberOfVectorOfUnion(field, code_ptr);
703           } else if (vectortype.base_type == BASE_TYPE_STRUCT) {
704             GetMemberOfVectorOfStruct(struct_def, field, code_ptr);
705           } else {
706             GetMemberOfVectorOfNonStruct(field, code_ptr);
707           }
708           break;
709         }
710         case BASE_TYPE_UNION: GetUnionField(field, code_ptr); break;
711         default: FLATBUFFERS_ASSERT(0);
712       }
713     }
714     if (IsVector(field.value.type)) {
715       GetVectorLen(field, code_ptr);
716       if (field.value.type.element == BASE_TYPE_UCHAR) {
717         GetUByte(field, code_ptr);
718       }
719     }
720   }
721 
722   // Generate table constructors, conditioned on its members' types.
GenTableBuilders(const StructDef & struct_def,std::string * code_ptr)723   void GenTableBuilders(const StructDef &struct_def, std::string *code_ptr) {
724     GetStartOfTable(struct_def, code_ptr);
725 
726     for (auto it = struct_def.fields.vec.begin();
727          it != struct_def.fields.vec.end(); ++it) {
728       auto &field = **it;
729       if (field.deprecated) continue;
730 
731       auto offset = it - struct_def.fields.vec.begin();
732       if (field.value.type.base_type == BASE_TYPE_UNION) {
733         std::string &code = *code_ptr;
734         code += Indent + "public static function add";
735         code += ConvertCase(field.name, Case::kUpperCamel);
736         code += "(FlatBufferBuilder $builder, $offset)\n";
737         code += Indent + "{\n";
738         code += Indent + Indent + "$builder->addOffsetX(";
739         code += NumToString(offset) + ", $offset, 0);\n";
740         code += Indent + "}\n\n";
741       } else {
742         BuildFieldOfTable(field, offset, code_ptr);
743       }
744       if (IsVector(field.value.type)) { BuildVectorOfTable(field, code_ptr); }
745     }
746 
747     GetEndOffsetOnTable(struct_def, code_ptr);
748   }
749 
750   // Generate struct or table methods.
GenStruct(const StructDef & struct_def,std::string * code_ptr)751   void GenStruct(const StructDef &struct_def, std::string *code_ptr) {
752     if (struct_def.generated) return;
753 
754     GenComment(struct_def.doc_comment, code_ptr, nullptr);
755     BeginClass(struct_def, code_ptr);
756 
757     if (!struct_def.fixed) {
758       // Generate a special accessor for the table that has been declared as
759       // the root type.
760       NewRootTypeFromBuffer(struct_def, code_ptr);
761     }
762 
763     std::string &code = *code_ptr;
764     if (!struct_def.fixed) {
765       if (parser_.file_identifier_.length()) {
766         // Return the identifier
767         code += Indent + "public static function " + struct_def.name;
768         code += "Identifier()\n";
769         code += Indent + "{\n";
770         code += Indent + Indent + "return \"";
771         code += parser_.file_identifier_ + "\";\n";
772         code += Indent + "}\n\n";
773 
774         // Check if a buffer has the identifier.
775         code += Indent + "public static function " + struct_def.name;
776         code += "BufferHasIdentifier(ByteBuffer $buf)\n";
777         code += Indent + "{\n";
778         code += Indent + Indent + "return self::";
779         code += "__has_identifier($buf, self::";
780         code += struct_def.name + "Identifier());\n";
781         code += Indent + "}\n\n";
782       }
783 
784       if (parser_.file_extension_.length()) {
785         // Return the extension
786         code += Indent + "public static function " + struct_def.name;
787         code += "Extension()\n";
788         code += Indent + "{\n";
789         code += Indent + Indent + "return \"" + parser_.file_extension_;
790         code += "\";\n";
791         code += Indent + "}\n\n";
792       }
793     }
794 
795     // Generate the Init method that sets the field in a pre-existing
796     // accessor object. This is to allow object reuse.
797     InitializeExisting(struct_def, code_ptr);
798     for (auto it = struct_def.fields.vec.begin();
799          it != struct_def.fields.vec.end(); ++it) {
800       auto &field = **it;
801       if (field.deprecated) continue;
802 
803       GenStructAccessor(struct_def, field, code_ptr);
804     }
805 
806     if (struct_def.fixed) {
807       // create a struct constructor function
808       GenStructBuilder(struct_def, code_ptr);
809     } else {
810       // Create a set of functions that allow table construction.
811       GenTableBuilders(struct_def, code_ptr);
812     }
813     EndClass(code_ptr);
814   }
815 
816   // Generate enum declarations.
GenEnum(const EnumDef & enum_def,std::string * code_ptr)817   static void GenEnum(const EnumDef &enum_def, std::string *code_ptr) {
818     if (enum_def.generated) return;
819 
820     GenComment(enum_def.doc_comment, code_ptr, nullptr);
821     BeginEnum(enum_def.name, code_ptr);
822     for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
823       auto &ev = **it;
824       GenComment(ev.doc_comment, code_ptr, nullptr, Indent.c_str());
825       EnumMember(enum_def, ev, code_ptr);
826     }
827 
828     std::string &code = *code_ptr;
829     code += "\n";
830     code += Indent + "private static $names = array(\n";
831     for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
832       auto &ev = **it;
833       code += Indent + Indent + enum_def.name + "::" + ev.name + "=>" + "\"" +
834               ev.name + "\",\n";
835     }
836 
837     code += Indent + ");\n\n";
838     code += Indent + "public static function Name($e)\n";
839     code += Indent + "{\n";
840     code += Indent + Indent + "if (!isset(self::$names[$e])) {\n";
841     code += Indent + Indent + Indent + "throw new \\Exception();\n";
842     code += Indent + Indent + "}\n";
843     code += Indent + Indent + "return self::$names[$e];\n";
844     code += Indent + "}\n";
845     EndEnum(code_ptr);
846   }
847 
848   // Returns the function name that is able to read a value of the given type.
GenGetter(const Type & type)849   static std::string GenGetter(const Type &type) {
850     switch (type.base_type) {
851       case BASE_TYPE_STRING: return "__string";
852       case BASE_TYPE_STRUCT: return "__struct";
853       case BASE_TYPE_UNION: return "__union";
854       case BASE_TYPE_VECTOR: return GenGetter(type.VectorType());
855       default: return "Get";
856     }
857   }
858 
859   // Returns the method name for use with add/put calls.
GenMethod(const FieldDef & field)860   static std::string GenMethod(const FieldDef &field) {
861     return IsScalar(field.value.type.base_type)
862                ? ConvertCase(GenTypeBasic(field.value.type), Case::kUpperCamel)
863                : (IsStruct(field.value.type) ? "Struct" : "Offset");
864   }
865 
GenTypeBasic(const Type & type)866   static std::string GenTypeBasic(const Type &type) {
867     // clang-format off
868     static const char *ctypename[] = {
869       #define FLATBUFFERS_TD(ENUM, IDLTYPE, \
870               CTYPE, JTYPE, GTYPE, NTYPE, ...) \
871         #NTYPE,
872         FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
873       #undef FLATBUFFERS_TD
874     };
875     // clang-format on
876     return ctypename[type.base_type];
877   }
878 
GenDefaultValue(const Value & value)879   std::string GenDefaultValue(const Value &value) {
880     if (value.type.enum_def) {
881       if (auto val = value.type.enum_def->FindByValue(value.constant)) {
882         return WrapInNameSpace(*value.type.enum_def) + "::" + val->name;
883       }
884     }
885 
886     switch (value.type.base_type) {
887       case BASE_TYPE_BOOL: return value.constant == "0" ? "false" : "true";
888 
889       case BASE_TYPE_STRING: return "null";
890 
891       case BASE_TYPE_LONG:
892       case BASE_TYPE_ULONG:
893         if (value.constant != "0") {
894           int64_t constant = StringToInt(value.constant.c_str());
895           return NumToString(constant);
896         }
897         return "0";
898 
899       default: return value.constant;
900     }
901   }
902 
GenTypePointer(const Type & type)903   static std::string GenTypePointer(const Type &type) {
904     switch (type.base_type) {
905       case BASE_TYPE_STRING: return "string";
906       case BASE_TYPE_VECTOR: return GenTypeGet(type.VectorType());
907       case BASE_TYPE_STRUCT: return type.struct_def->name;
908       case BASE_TYPE_UNION:
909         // fall through
910       default: return "Table";
911     }
912   }
913 
GenTypeGet(const Type & type)914   static std::string GenTypeGet(const Type &type) {
915     return IsScalar(type.base_type) ? GenTypeBasic(type) : GenTypePointer(type);
916   }
917 
918   // Create a struct with a builder and the struct's arguments.
GenStructBuilder(const StructDef & struct_def,std::string * code_ptr)919   static void GenStructBuilder(const StructDef &struct_def,
920                                std::string *code_ptr) {
921     std::string &code = *code_ptr;
922     code += "\n";
923     code += Indent + "/**\n";
924     code += Indent + " * @return int offset\n";
925     code += Indent + " */\n";
926     code += Indent + "public static function create" + struct_def.name;
927     code += "(FlatBufferBuilder $builder";
928     StructBuilderArgs(struct_def, "", code_ptr);
929     code += ")\n";
930     code += Indent + "{\n";
931 
932     StructBuilderBody(struct_def, "", code_ptr);
933 
934     code += Indent + Indent + "return $builder->offset();\n";
935     code += Indent + "}\n";
936   }
937 };
938 }  // namespace php
939 
GeneratePhp(const Parser & parser,const std::string & path,const std::string & file_name)940 bool GeneratePhp(const Parser &parser, const std::string &path,
941                  const std::string &file_name) {
942   php::PhpGenerator generator(parser, path, file_name);
943   return generator.generate();
944 }
945 }  // namespace flatbuffers
946