| 1 | // Protocol Buffers - Google's data interchange format |
| 2 | // Copyright 2008 Google Inc. All rights reserved. |
| 3 | // https://developers.google.com/protocol-buffers/ |
| 4 | // |
| 5 | // Redistribution and use in source and binary forms, with or without |
| 6 | // modification, are permitted provided that the following conditions are |
| 7 | // met: |
| 8 | // |
| 9 | // * Redistributions of source code must retain the above copyright |
| 10 | // notice, this list of conditions and the following disclaimer. |
| 11 | // * Redistributions in binary form must reproduce the above |
| 12 | // copyright notice, this list of conditions and the following disclaimer |
| 13 | // in the documentation and/or other materials provided with the |
| 14 | // distribution. |
| 15 | // * Neither the name of Google Inc. nor the names of its |
| 16 | // contributors may be used to endorse or promote products derived from |
| 17 | // this software without specific prior written permission. |
| 18 | // |
| 19 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| 20 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| 21 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| 22 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
| 23 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| 24 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| 25 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| 26 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| 27 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| 28 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| 29 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 30 | |
| 31 | #include <google/protobuf/compiler/python/helpers.h> |
| 32 | |
| 33 | #include <algorithm> |
| 34 | |
| 35 | #include <google/protobuf/stubs/strutil.h> |
| 36 | #include <google/protobuf/compiler/code_generator.h> |
| 37 | #include <google/protobuf/descriptor.h> |
| 38 | #include <google/protobuf/descriptor.pb.h> |
| 39 | |
| 40 | namespace google { |
| 41 | namespace protobuf { |
| 42 | namespace compiler { |
| 43 | namespace python { |
| 44 | |
| 45 | // Returns the Python module name expected for a given .proto filename. |
| 46 | std::string ModuleName(const std::string& filename) { |
| 47 | std::string basename = StripProto(filename); |
| 48 | ReplaceCharacters(s: &basename, remove: "-" , replacewith: '_'); |
| 49 | ReplaceCharacters(s: &basename, remove: "/" , replacewith: '.'); |
| 50 | return basename + "_pb2" ; |
| 51 | } |
| 52 | |
| 53 | std::string StrippedModuleName(const std::string& filename) { |
| 54 | std::string module_name = ModuleName(filename); |
| 55 | return module_name; |
| 56 | } |
| 57 | |
| 58 | // Keywords reserved by the Python language. |
| 59 | const char* const kKeywords[] = { |
| 60 | "False" , "None" , "True" , "and" , "as" , "assert" , |
| 61 | "async" , "await" , "break" , "class" , "continue" , "def" , |
| 62 | "del" , "elif" , "else" , "except" , "finally" , "for" , |
| 63 | "from" , "global" , "if" , "import" , "in" , "is" , |
| 64 | "lambda" , "nonlocal" , "not" , "or" , "pass" , "raise" , |
| 65 | "return" , "try" , "while" , "with" , "yield" , |
| 66 | }; |
| 67 | const char* const* kKeywordsEnd = |
| 68 | kKeywords + (sizeof(kKeywords) / sizeof(kKeywords[0])); |
| 69 | |
| 70 | bool ContainsPythonKeyword(const std::string& module_name) { |
| 71 | std::vector<std::string> tokens = Split(full: module_name, delim: "." ); |
| 72 | for (int i = 0; i < static_cast<int>(tokens.size()); ++i) { |
| 73 | if (std::find(first: kKeywords, last: kKeywordsEnd, val: tokens[i]) != kKeywordsEnd) { |
| 74 | return true; |
| 75 | } |
| 76 | } |
| 77 | return false; |
| 78 | } |
| 79 | |
| 80 | bool IsPythonKeyword(const std::string& name) { |
| 81 | return (std::find(first: kKeywords, last: kKeywordsEnd, val: name) != kKeywordsEnd); |
| 82 | } |
| 83 | |
| 84 | std::string ResolveKeyword(const std::string& name) { |
| 85 | if (IsPythonKeyword(name)) { |
| 86 | return "globals()['" + name + "']" ; |
| 87 | } |
| 88 | return name; |
| 89 | } |
| 90 | |
| 91 | std::string GetFileName(const FileDescriptor* file_des, |
| 92 | const std::string& suffix) { |
| 93 | std::string module_name = ModuleName(filename: file_des->name()); |
| 94 | std::string filename = module_name; |
| 95 | ReplaceCharacters(s: &filename, remove: "." , replacewith: '/'); |
| 96 | filename += suffix; |
| 97 | return filename; |
| 98 | } |
| 99 | |
| 100 | bool HasGenericServices(const FileDescriptor* file) { |
| 101 | return file->service_count() > 0 && file->options().py_generic_services(); |
| 102 | } |
| 103 | |
| 104 | template <typename DescriptorT> |
| 105 | std::string NamePrefixedWithNestedTypes(const DescriptorT& descriptor, |
| 106 | const std::string& separator) { |
| 107 | std::string name = descriptor.name(); |
| 108 | const Descriptor* parent = descriptor.containing_type(); |
| 109 | if (parent != nullptr) { |
| 110 | std::string prefix = NamePrefixedWithNestedTypes(descriptor: *parent, separator); |
| 111 | if (separator == "." && IsPythonKeyword(name)) { |
| 112 | return "getattr(" + prefix + ", '" + name + "')" ; |
| 113 | } else { |
| 114 | return prefix + separator + name; |
| 115 | } |
| 116 | } |
| 117 | if (separator == "." ) { |
| 118 | name = ResolveKeyword(name); |
| 119 | } |
| 120 | return name; |
| 121 | } |
| 122 | |
| 123 | template std::string NamePrefixedWithNestedTypes<Descriptor>( |
| 124 | const Descriptor& descriptor, const std::string& separator); |
| 125 | template std::string NamePrefixedWithNestedTypes<EnumDescriptor>( |
| 126 | const EnumDescriptor& descriptor, const std::string& separator); |
| 127 | |
| 128 | } // namespace python |
| 129 | } // namespace compiler |
| 130 | } // namespace protobuf |
| 131 | } // namespace google |
| 132 | |