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