blob: af3b06d57e643946c40f12cb6ed6818ca6b3b581 [file] [log] [blame]
Shuhei Taunma5ce86822015-11-05 16:19:28 +09001/*
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"
Lakedaemon6765c192016-04-26 17:08:13 +020024#include "flatbuffers/code_generators.h"
Shuhei Taunma5ce86822015-11-05 16:19:28 +090025
26namespace flatbuffers {
27namespace php {
lakedaemon66f2aac2016-06-14 19:19:55 +020028 // Hardcode spaces per indentation.
29 const std::string Indent = " ";
30 class PhpGenerator : public BaseGenerator {
31 public:
32 PhpGenerator(const Parser &parser, const std::string &path,
33 const std::string &file_name)
lakedaemon03ad8fa2016-06-14 23:17:43 +020034 : BaseGenerator(parser, path, file_name, "\\", "\\"){};
lakedaemon66f2aac2016-06-14 19:19:55 +020035 bool generate() {
36 if (!generateEnums()) return false;
37 if (!generateStructs()) return false;
38 return true;
39 }
Shuhei Taunma5ce86822015-11-05 16:19:28 +090040
lakedaemon66f2aac2016-06-14 19:19:55 +020041 private:
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
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;
lakedaemoncb6cc3d2016-06-14 19:26:08 +020058 GenStruct(struct_def, &declcode);
lakedaemon66f2aac2016-06-14 19:19:55 +020059 if (!SaveType(struct_def, declcode, true)) return false;
60 }
61 return true;
62 }
63
64 // Begin by declaring namespace and imports.
65 void BeginFile(const std::string name_space_name,
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.
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 kPathSeparator + def.name + ".php";
93 return SaveFile(filename.c_str(), code, false);
94 }
95
Shuhei Taunma5ce86822015-11-05 16:19:28 +090096 // Begin a class declaration.
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
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.
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.
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.
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.
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.
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";
Wouter van Oortmerssen45bda6e2015-11-30 17:42:19 -0800165 code += Indent + "{\n";
166 code += Indent + Indent + "$this->bb_pos = $_i;\n";
Shuhei Taunma5ce86822015-11-05 16:19:28 +0900167 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.
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
Armen Baghumian28a3c932016-03-14 17:37:22 +1100190 // Get a [ubyte] vector as a byte array.
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
Shuhei Taunma5ce86822015-11-05 16:19:28 +0900206 // Get the value of a struct's scalar.
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.
lakedaemoncb6cc3d2016-06-14 19:26:08 +0200231 void GetScalarFieldOfTable(const FieldDef &field, std::string *code_ptr) {
Shuhei Taunma5ce86822015-11-05 16:19:28 +0900232 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.
lakedaemoncb6cc3d2016-06-14 19:26:08 +0200254 void GetStructFieldOfStruct(const FieldDef &field, std::string *code_ptr) {
Shuhei Taunma5ce86822015-11-05 16:19:28 +0900255 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.
lakedaemoncb6cc3d2016-06-14 19:26:08 +0200273 void GetStructFieldOfTable(const FieldDef &field, std::string *code_ptr) {
Shuhei Taunma5ce86822015-11-05 16:19:28 +0900274 std::string &code = *code_ptr;
275
276 code += Indent + "public function get";
277 code += MakeCamel(field.name);
278 code += "()\n";
Wouter van Oortmerssen45bda6e2015-11-30 17:42:19 -0800279 code += Indent + "{\n";
Shuhei Taunma5ce86822015-11-05 16:19:28 +0900280 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;
Shuhei Tanumac9198db2015-12-17 11:35:31 +0900287 code += "return $o != 0 ? $obj->init(";
Armen Baghumian28a3c932016-03-14 17:37:22 +1100288 if (field.value.type.struct_def->fixed)
Shuhei Tanumac9198db2015-12-17 11:35:31 +0900289 {
290 code += "$o + $this->bb_pos, $this->bb) : ";
291 } else {
292 code += "$this->__indirect($o + $this->bb_pos), $this->bb) : ";
293 }
Shuhei Taunma5ce86822015-11-05 16:19:28 +0900294 code += GenDefaultValue(field.value) + ";\n";
Shuhei Taunma5ce86822015-11-05 16:19:28 +0900295 code += Indent + "}\n\n";
296 }
297
298 // Get the value of a string.
lakedaemoncb6cc3d2016-06-14 19:26:08 +0200299 void GetStringField(const FieldDef &field, std::string *code_ptr) {
Shuhei Taunma5ce86822015-11-05 16:19:28 +0900300 std::string &code = *code_ptr;
301 code += Indent + "public function get";
302 code += MakeCamel(field.name);
303 code += "()\n";
Wouter van Oortmerssen45bda6e2015-11-30 17:42:19 -0800304 code += Indent + "{\n";
Shuhei Taunma5ce86822015-11-05 16:19:28 +0900305 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.
lakedaemoncb6cc3d2016-06-14 19:26:08 +0200316 void GetUnionField(const FieldDef &field, std::string *code_ptr) {
Shuhei Taunma5ce86822015-11-05 16:19:28 +0900317 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.
lakedaemoncb6cc3d2016-06-14 19:26:08 +0200335 void GetMemberOfVectorOfStruct(const StructDef &struct_def,
336 const FieldDef &field, std::string *code_ptr) {
Shuhei Taunma5ce86822015-11-05 16:19:28 +0900337 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";
Wouter van Oortmerssen45bda6e2015-11-30 17:42:19 -0800346 code += Indent + "{\n";
Shuhei Taunma5ce86822015-11-05 16:19:28 +0900347 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.
lakedaemoncb6cc3d2016-06-14 19:26:08 +0200398 void GetMemberOfVectorOfNonStruct(const FieldDef &field,
Shuhei Taunma5ce86822015-11-05 16:19:28 +0900399 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";
Wouter van Oortmerssen45bda6e2015-11-30 17:42:19 -0800410 code += Indent + "{\n";
Shuhei Taunma5ce86822015-11-05 16:19:28 +0900411 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.
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.
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.
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";
Wouter van Oortmerssen45bda6e2015-11-30 17:42:19 -0800495 code += Indent + "{\n";
Shuhei Taunma5ce86822015-11-05 16:19:28 +0900496 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.
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";
Wouter van Oortmerssen45bda6e2015-11-30 17:42:19 -0800567 code += Indent + "{\n";
Shuhei Taunma5ce86822015-11-05 16:19:28 +0900568 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.
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";
Wouter van Oortmerssen45bda6e2015-11-30 17:42:19 -0800601 code += Indent + "{\n";
Shuhei Taunma5ce86822015-11-05 16:19:28 +0900602 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";
Wouter van Oortmerssen45bda6e2015-11-30 17:42:19 -0800630 code += Indent + "{\n";
Shuhei Taunma5ce86822015-11-05 16:19:28 +0900631 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.
lakedaemoncb6cc3d2016-06-14 19:26:08 +0200639 void GetEndOffsetOnTable(const StructDef &struct_def, std::string *code_ptr) {
Shuhei Taunma5ce86822015-11-05 16:19:28 +0900640 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";
Wouter van Oortmerssen45bda6e2015-11-30 17:42:19 -0800649 code += Indent + "{\n";
Shuhei Taunma5ce86822015-11-05 16:19:28 +0900650 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
lakedaemoncb6cc3d2016-06-14 19:26:08 +0200666 if (parser_.root_struct_def_ == &struct_def) {
Shuhei Taunma5ce86822015-11-05 16:19:28 +0900667 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
lakedaemoncb6cc3d2016-06-14 19:26:08 +0200674 if (parser_.file_identifier_.length())
675 code += ", \"" + parser_.file_identifier_ + "\"";
Shuhei Taunma5ce86822015-11-05 16:19:28 +0900676 code += ");\n";
677 code += Indent + "}\n";
678 }
679 }
680
Wouter van Oortmerssen45bda6e2015-11-30 17:42:19 -0800681 // Generate a struct field, conditioned on its child type(s).
lakedaemoncb6cc3d2016-06-14 19:26:08 +0200682 void GenStructAccessor(const StructDef &struct_def, const FieldDef &field,
Shuhei Taunma5ce86822015-11-05 16:19:28 +0900683 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);
Armen Baghumian28a3c932016-03-14 17:37:22 +1100722 if (field.value.type.element == BASE_TYPE_UCHAR) {
723 GetUByte(field, code_ptr);
724 }
Shuhei Taunma5ce86822015-11-05 16:19:28 +0900725 }
726 }
727
728 // Generate table constructors, conditioned on its members' types.
lakedaemoncb6cc3d2016-06-14 19:26:08 +0200729 void GenTableBuilders(const StructDef &struct_def, std::string *code_ptr) {
Shuhei Taunma5ce86822015-11-05 16:19:28 +0900730 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";
Wouter van Oortmerssen45bda6e2015-11-30 17:42:19 -0800744 code += Indent + "{\n";
Shuhei Taunma5ce86822015-11-05 16:19:28 +0900745 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
lakedaemoncb6cc3d2016-06-14 19:26:08 +0200756 GetEndOffsetOnTable(struct_def, code_ptr);
Shuhei Taunma5ce86822015-11-05 16:19:28 +0900757 }
758
759 // Generate struct or table methods.
lakedaemoncb6cc3d2016-06-14 19:26:08 +0200760 void GenStruct(const StructDef &struct_def,
Shuhei Taunma5ce86822015-11-05 16:19:28 +0900761 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) {
lakedaemoncb6cc3d2016-06-14 19:26:08 +0200775 if (parser_.file_identifier_.length()) {
Shuhei Taunma5ce86822015-11-05 16:19:28 +0900776 // 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 \"";
lakedaemoncb6cc3d2016-06-14 19:26:08 +0200781 code += parser_.file_identifier_ + "\";\n";
Shuhei Taunma5ce86822015-11-05 16:19:28 +0900782 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
lakedaemoncb6cc3d2016-06-14 19:26:08 +0200794 if (parser_.file_extension_.length()) {
Shuhei Taunma5ce86822015-11-05 16:19:28 +0900795 // Return the extension
796 code += Indent + "public static function " + struct_def.name;
797 code += "Extension()\n";
798 code += Indent + "{\n";
lakedaemoncb6cc3d2016-06-14 19:26:08 +0200799 code += Indent + Indent + "return \"" + parser_.file_extension_;
Shuhei Taunma5ce86822015-11-05 16:19:28 +0900800 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.
lakedaemoncb6cc3d2016-06-14 19:26:08 +0200822 GenTableBuilders(struct_def, code_ptr);
Shuhei Taunma5ce86822015-11-05 16:19:28 +0900823 }
824 EndClass(code_ptr);
825 }
826
827 // Generate enum declarations.
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";
Wouter van Oortmerssen45bda6e2015-11-30 17:42:19 -0800852 code += Indent + "{\n";
Shuhei Taunma5ce86822015-11-05 16:19:28 +0900853 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.
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.
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
Shuhei Taunma5ce86822015-11-05 16:19:28 +0900880 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
lakedaemoncb6cc3d2016-06-14 19:26:08 +0200890 std::string GenDefaultValue(const Value &value) {
Shuhei Taunma5ce86822015-11-05 16:19:28 +0900891 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
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
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.
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";
Wouter van Oortmerssen45bda6e2015-11-30 17:42:19 -0800951 code += Indent + "{\n";
Shuhei Taunma5ce86822015-11-05 16:19:28 +0900952
953 StructBuilderBody(struct_def, "", code_ptr);
954
955 code += Indent + Indent + "return $builder->offset();\n";
956 code += Indent + "}\n";
957 }
lakedaemon66f2aac2016-06-14 19:19:55 +0200958
Lakedaemon6765c192016-04-26 17:08:13 +0200959 };
960 } // namespace php
961
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();
Shuhei Taunma5ce86822015-11-05 16:19:28 +0900966 }
Lakedaemon6765c192016-04-26 17:08:13 +0200967 } // namespace flatbuffers