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