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