Przeglądaj źródła

Corrected type deduction for enums. Moved exception handling to a higher level to pass errors to protoc.

Bart Hertog 5 lat temu
rodzic
commit
30b7463507

+ 32 - 4
generator/protoc-gen-eams.py

@@ -64,10 +64,11 @@ def generate_code(request, respones):
             break
             break
 
 
     if not all_parameters_registered:
     if not all_parameters_registered:
-        raise Exception("Unable to register all template parameters")
+        raise Exception("Messages with repeated, string or byte fields use template parameters to define their length."
+                        "For some reason it was not to add all required template parameters.")
 
 
     curr_location = os.path.dirname(os.path.abspath(__file__))
     curr_location = os.path.dirname(os.path.abspath(__file__))
-    filepath =  os.path.join(curr_location, "templates")
+    filepath = os.path.join(curr_location, "templates")
     template_loader = jinja2.FileSystemLoader(searchpath=filepath)
     template_loader = jinja2.FileSystemLoader(searchpath=filepath)
     template_env = jinja2.Environment(loader=template_loader, trim_blocks=True, lstrip_blocks=True)
     template_env = jinja2.Environment(loader=template_loader, trim_blocks=True, lstrip_blocks=True)
 
 
@@ -100,7 +101,21 @@ def main_plugin():
     response = plugin.CodeGeneratorResponse()
     response = plugin.CodeGeneratorResponse()
 
 
     # Generate code
     # Generate code
-    generate_code(request, response)
+    try:
+        generate_code(request, response)
+    except jinja2.UndefinedError as e:
+        response.error = "Embedded Proto error - Template Undefined Error exception: " + str(e)
+    except jinja2.TemplateRuntimeError as e:
+        response.error = "Embedded Proto error - Template Runtime Error exception: " + str(e)
+    except jinja2.TemplateAssertionError as e:
+        response.error = "Embedded Proto error - TemplateAssertionError exception: " + str(e)
+    except jinja2.TemplateSyntaxError as e:
+        response.error = "Embedded Proto error - TemplateSyntaxError exception: " + str(e)
+    except jinja2.TemplateError as e:
+        response.error = "Embedded Proto error - TemplateError exception: " + str(e)
+    except Exception as e:
+        response.error = "Embedded Proto error - " + str(e)
+
 
 
     # Serialize response message
     # Serialize response message
     output = response.SerializeToString()
     output = response.SerializeToString()
@@ -123,7 +138,20 @@ def main_cli():
         response = plugin.CodeGeneratorResponse()
         response = plugin.CodeGeneratorResponse()
 
 
         # Generate code
         # Generate code
-        generate_code(request, response)
+        try:
+            generate_code(request, response)
+        except jinja2.UndefinedError as e:
+            response.error = "Embedded Proto error - Template Undefined Error exception: " + str(e)
+        except jinja2.TemplateRuntimeError as e:
+            response.error = "Embedded Proto error - Template Runtime Error exception: " + str(e)
+        except jinja2.TemplateAssertionError as e:
+            response.error = "Embedded Proto error - TemplateAssertionError exception: " + str(e)
+        except jinja2.TemplateSyntaxError as e:
+            response.error = "Embedded Proto error - TemplateSyntaxError exception: " + str(e)
+        except jinja2.TemplateError as e:
+            response.error = "Embedded Proto error - TemplateError exception: " + str(e)
+        except Exception as e:
+            response.error = "Embedded Proto error - " + str(e)
 
 
         # For debugging purposes print the result to the console.
         # For debugging purposes print the result to the console.
         for response_file in response.file:
         for response_file in response.file:

+ 35 - 37
generator/support/Field.py

@@ -30,7 +30,6 @@
 
 
 from google.protobuf.descriptor_pb2 import FieldDescriptorProto
 from google.protobuf.descriptor_pb2 import FieldDescriptorProto
 import copy
 import copy
-import jinja2
 
 
 
 
 # This class is the base class for any kind of field used in protobuf messages.
 # This class is the base class for any kind of field used in protobuf messages.
@@ -121,25 +120,23 @@ class Field:
     def get_which_oneof(self):
     def get_which_oneof(self):
         return self.oneof.get_which_oneof()
         return self.oneof.get_which_oneof()
 
 
+    # Get the scope relevant compared to the scope this field is used in.
+    def get_reduced_scope(self):
+        parent_scope = self.parent.scope.get()
+        def_scope = self.definition.scope.get()
+        start_index = 0
+        for ds, ps in zip(def_scope[:-1], parent_scope):
+            if ds == ps:
+                start_index += 1
+            else:
+                break
+        reduced_scope = def_scope[start_index:]
+        return reduced_scope
+
     def render(self, filename, jinja_environment):
     def render(self, filename, jinja_environment):
         template = jinja_environment.get_template(filename)
         template = jinja_environment.get_template(filename)
-        try:
-            rendered_str = template.render(field=self, environment=jinja_environment)
-
-        except jinja2.UndefinedError as e:
-            print("UndefinedError exception: " + str(e))
-        except jinja2.TemplateRuntimeError as e:
-            print("TemplateRuntimeError exception: " + str(e))
-        except jinja2.TemplateAssertionError as e:
-            print("TemplateAssertionError exception: " + str(e))
-        except jinja2.TemplateSyntaxError as e:
-            print("TemplateSyntaxError exception: " + str(e))
-        except jinja2.TemplateError as e:
-            print("TemplateError exception: " + str(e))
-        except Exception as e:
-            print("Template renderer exception: " + str(e))
-        else:
-            return rendered_str
+        rendered_str = template.render(field=self, environment=jinja_environment)
+        return rendered_str
 
 
 # -----------------------------------------------------------------------------
 # -----------------------------------------------------------------------------
 
 
@@ -304,11 +301,24 @@ class FieldEnum(Field):
     def get_type(self):
     def get_type(self):
         if not self.definition:
         if not self.definition:
             # When the actual definition is unknown use the protobuf type.
             # When the actual definition is unknown use the protobuf type.
-            type = self.descriptor.type_name if "." != self.descriptor.type_name[0] else self.descriptor.type_name[1:]
-            type = type.replace(".", "::")
+            type_name = self.descriptor.type_name if "." != self.descriptor.type_name[0] else self.descriptor.type_name[1:]
+            type_name = type_name.replace(".", "::")
         else:
         else:
-            type = "TODO"
-        return type
+            scopes = self.get_reduced_scope()
+            type_name = ""
+            for scope in scopes:
+                if scope["templates"]:
+                    raise Exception("You are trying to use a field with the type: \"" + self.descriptor.type_name +
+                                    "\". It is defined in different scope as where you are using it. But the scope of "
+                                    "definition includes template parameters for repeated, string or byte fields. It "
+                                    "is there for not possible to define the field where you are using it as we do not "
+                                    "know the template value. Try defining the field in the main scope or the one you "
+                                    "are using it in.")
+
+                type_name += scope["name"] + "::"
+            # Remove the last ::
+            type_name = type_name[:-2]
+        return type_name
 
 
     def get_short_type(self):
     def get_short_type(self):
         return self.get_type().split("::")[-1]
         return self.get_type().split("::")[-1]
@@ -322,11 +332,12 @@ class FieldEnum(Field):
         for enum_defs in all_types_definitions["enums"]:
         for enum_defs in all_types_definitions["enums"]:
             other_scope = enum_defs.scope.get_scope_str()
             other_scope = enum_defs.scope.get_scope_str()
             if my_type == other_scope:
             if my_type == other_scope:
+                self.definition = enum_defs
                 found = True
                 found = True
                 break
                 break
 
 
         if not found:
         if not found:
-            raise Exception("Unable to match enum type for: " + self.name)
+            raise Exception("Unable to find the definition of this enum: " + self.name)
 
 
     def render_get_set(self, jinja_env):
     def render_get_set(self, jinja_env):
         return self.render("FieldEnum_GetSet.h", jinja_environment=jinja_env)
         return self.render("FieldEnum_GetSet.h", jinja_environment=jinja_env)
@@ -399,7 +410,7 @@ class FieldMessage(Field):
                 break
                 break
 
 
         if not found:
         if not found:
-            raise Exception("Unable to match enum type for: " + self.name)
+            raise Exception("Unable to find the definition of this message: " + self.name)
 
 
     def register_template_parameters(self):
     def register_template_parameters(self):
         if self.definition.all_parameters_registered:
         if self.definition.all_parameters_registered:
@@ -413,19 +424,6 @@ class FieldMessage(Field):
     def get_scope(self):
     def get_scope(self):
         return self.definition.scope.get()
         return self.definition.scope.get()
 
 
-    # Get the scope relevant compared to the scope this field is used in.
-    def get_reduced_scope(self):
-        parent_scope = self.parent.scope.get()
-        def_scope = self.definition.scope.get()
-        start_index = 0
-        for ds, ps in zip(def_scope[:-1], parent_scope):
-            if ds == ps:
-                start_index += 1
-            else:
-                break
-        reduced_scope = def_scope[start_index:]
-        return reduced_scope
-
     def render_get_set(self, jinja_env):
     def render_get_set(self, jinja_env):
         return self.render("FieldMsg_GetSet.h", jinja_environment=jinja_env)
         return self.render("FieldMsg_GetSet.h", jinja_environment=jinja_env)
 
 

+ 2 - 17
generator/support/ProtoFile.py

@@ -100,20 +100,5 @@ class ProtoFile:
     def render(self, jinja_environment):
     def render(self, jinja_environment):
         template_file = "Header.h"
         template_file = "Header.h"
         template = jinja_environment.get_template(template_file)
         template = jinja_environment.get_template(template_file)
-        try:
-            file_str = template.render(proto_file=self, environment=jinja_environment)
-
-        except jinja2.UndefinedError as e:
-            print("UndefinedError exception: " + str(e))
-        except jinja2.TemplateRuntimeError as e:
-            print("TemplateRuntimeError exception: " + str(e))
-        except jinja2.TemplateAssertionError as e:
-            print("TemplateAssertionError exception: " + str(e))
-        except jinja2.TemplateSyntaxError as e:
-            print("TemplateSyntaxError exception: " + str(e))
-        except jinja2.TemplateError as e:
-            print("TemplateError exception: " + str(e))
-        except Exception as e:
-            print("Template renderer exception: " + str(e))
-        else:
-            return file_str
+        file_str = template.render(proto_file=self, environment=jinja_environment)
+        return file_str

+ 4 - 23
generator/support/TypeDefinitions.py

@@ -89,11 +89,6 @@ class Scope:
         result.extend([{"name": self.name, "templates": self.get_template_parameters()}])
         result.extend([{"name": self.name, "templates": self.get_template_parameters()}])
         return result
         return result
 
 
-    # Given two scopes, return scope that is uncommon for this object.
-    def reduced(self, other_scope):
-        pass
-
-
 # -----------------------------------------------------------------------------
 # -----------------------------------------------------------------------------
 
 
 
 
@@ -109,23 +104,8 @@ class TypeDefinition:
 
 
     def render(self, jinja_environment):
     def render(self, jinja_environment):
         template = jinja_environment.get_template(self.template_file)
         template = jinja_environment.get_template(self.template_file)
-        try:
-            render_result = template.render(typedef=self, environment=jinja_environment)
-
-        except jinja2.UndefinedError as e:
-            print("UndefinedError exception: " + str(e))
-        except jinja2.TemplateRuntimeError as e:
-            print("TemplateRuntimeError exception: " + str(e))
-        except jinja2.TemplateAssertionError as e:
-            print("TemplateAssertionError exception: " + str(e))
-        except jinja2.TemplateSyntaxError as e:
-            print("TemplateSyntaxError exception: " + str(e))
-        except jinja2.TemplateError as e:
-            print("TemplateError exception: " + str(e))
-        except Exception as e:
-            print("Template renderer exception: " + str(e))
-        else:
-            return render_result
+        render_result = template.render(typedef=self, environment=jinja_environment)
+        return render_result
 
 
 
 
 # -----------------------------------------------------------------------------
 # -----------------------------------------------------------------------------
@@ -180,7 +160,8 @@ class MessageDefinition(TypeDefinition):
 
 
     # Obtain a dictionary with references to all nested enums and messages
     # Obtain a dictionary with references to all nested enums and messages
     def get_all_nested_types(self):
     def get_all_nested_types(self):
-        nested_types = {"enums": self.nested_enum_definitions, "messages": []}
+        nested_types = {"enums": [], "messages": []}
+        nested_types["enums"].extend(self.nested_enum_definitions)
         for msg in self.nested_msg_definitions:
         for msg in self.nested_msg_definitions:
             nt = msg.get_all_nested_types()
             nt = msg.get_all_nested_types()
             nested_types["enums"].extend(nt["enums"])
             nested_types["enums"].extend(nt["enums"])

+ 1 - 1
src/MessageInterface.cpp

@@ -37,7 +37,7 @@ namespace EmbeddedProto
   Error MessageInterface::MessageInterface::serialize_with_id(uint32_t field_number, ::EmbeddedProto::WriteBufferInterface& buffer) const
   Error MessageInterface::MessageInterface::serialize_with_id(uint32_t field_number, ::EmbeddedProto::WriteBufferInterface& buffer) const
   {
   {
     const uint32_t size_x = this->serialized_size();
     const uint32_t size_x = this->serialized_size();
-    bool result = (size_x < buffer.get_available_size());
+    bool result = (size_x <= buffer.get_available_size());
     Error return_value = result ? Error::NO_ERRORS : Error::BUFFER_FULL;
     Error return_value = result ? Error::NO_ERRORS : Error::BUFFER_FULL;
     if(result && (0 < size_x))
     if(result && (0 < size_x))
     {
     {

+ 3 - 0
test/test_NestedMessage.cpp

@@ -203,6 +203,9 @@ TEST(NestedMessage, serialize_nested_in_nested_max)
     EXPECT_CALL(buffer, push(e)).Times(1).WillOnce(Return(true));
     EXPECT_CALL(buffer, push(e)).Times(1).WillOnce(Return(true));
   }
   }
 
 
+  // In serializing D, even if it is not set, we check the size of the buffer.
+  EXPECT_CALL(buffer, get_available_size()).Times(1).WillOnce(Return(0));
+
   EXPECT_EQ(::EmbeddedProto::Error::NO_ERRORS, msg.serialize(buffer));
   EXPECT_EQ(::EmbeddedProto::Error::NO_ERRORS, msg.serialize(buffer));
 }
 }