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