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