Adding support for cancelling code generation of function with no input connected
authorlbessard
Mon, 19 Jan 2009 17:08:17 +0100
changeset 307 fd1f6ae26d4f
parent 306 eecc53781498
child 308 bf1facfd1d36
Adding support for cancelling code generation of function with no input connected
PLCControler.py
PLCGenerator.py
PLCOpenEditor.py
generate_IEC_std.py
plcopen/structures.py
--- a/PLCControler.py	Mon Jan 19 17:07:03 2009 +0100
+++ b/PLCControler.py	Mon Jan 19 17:08:17 2009 +0100
@@ -499,9 +499,11 @@
         return False
 
     def GenerateProgram(self, filepath=None):
+        errors = []
+        warnings = []
         if self.Project is not None:
             try:
-                self.ProgramChunks = GenerateCurrentProgram(self, self.Project)
+                self.ProgramChunks = GenerateCurrentProgram(self, self.Project, errors, warnings)
                 self.NextCompiledProject = self.Copy(self.Project)
                 program_text = "".join([item[0] for item in self.ProgramChunks])
                 if filepath is not None:
@@ -509,12 +511,12 @@
                     programfile.write(program_text)
                     programfile.close()
                     self.ProgramFilePath = filepath
-                    return None
-                else:
-                    return program_text
+                return program_text, errors, warnings
             except PLCGenException, e:
-                return e.message
-        return "No project opened"
+                errors.append(e.message)
+        else:
+            errors.append("No project opened")
+        return "", errors, warnings
 
     def ProgramTransferred(self):
         self.CurrentCompiledProject = self.NextCompiledProject
--- a/PLCGenerator.py	Mon Jan 19 17:07:03 2009 +0100
+++ b/PLCGenerator.py	Mon Jan 19 17:08:17 2009 +0100
@@ -86,7 +86,7 @@
 class ProgramGenerator:
 
     # Create a new PCL program generator
-    def __init__(self, controler, project):
+    def __init__(self, controler, project, errors, warnings):
         # Keep reference of the controler and project
         self.Controler = controler
         self.Project = project
@@ -94,6 +94,8 @@
         self.Program = []
         self.DatatypeComputed = {}
         self.PouComputed = {}
+        self.Errors = errors
+        self.Warnings = warnings
 
     # Compute value according to type given
     def ComputeValue(self, value, var_type):
@@ -222,7 +224,7 @@
             # Verify that POU type exists
             if pou_type in pouTypeNames:
                 # Create a POU program generator
-                pou_program = PouProgramGenerator(self, pou.getname(), pouTypeNames[pou_type])
+                pou_program = PouProgramGenerator(self, pou.getname(), pouTypeNames[pou_type], self.Errors, self.Warnings)
                 program = pou_program.GenerateProgram(pou)
                 self.Program += program
             else:
@@ -420,7 +422,7 @@
 class PouProgramGenerator:
     
     # Create a new POU program generator
-    def __init__(self, parent, name, type):
+    def __init__(self, parent, name, type, errors, warnings):
         # Keep Reference to the parent generator
         self.ParentGenerator = parent
         self.Name = name
@@ -438,6 +440,8 @@
         self.SFCComputedBlocks = []
         self.ActionNumber = 0
         self.Program = []
+        self.Errors = errors
+        self.Warnings = warnings
     
     def GetBlockType(self, type):
         return self.ParentGenerator.Controler.GetBlockType(type)
@@ -1208,8 +1212,8 @@
         program += [("END_%s\n\n"%self.Type, ())]
         return program
 
-def GenerateCurrentProgram(controler, project):
-    generator = ProgramGenerator(controler, project)
+def GenerateCurrentProgram(controler, project, errors, warnings):
+    generator = ProgramGenerator(controler, project, errors, warnings)
     generator.GenerateProgram()
     return generator.GetGeneratedProgram()
 
--- a/PLCOpenEditor.py	Mon Jan 19 17:07:03 2009 +0100
+++ b/PLCOpenEditor.py	Mon Jan 19 17:08:17 2009 +0100
@@ -883,20 +883,23 @@
         dialog = wx.FileDialog(self, "Choose a file", os.getcwd(), self.Controler.GetProgramFilePath(),  "ST files (*.st)|*.st|All files|*.*", wx.SAVE|wx.CHANGE_DIR)
         if dialog.ShowModal() == wx.ID_OK:
             filepath = dialog.GetPath()
+            message_text = ""
+            header, icon = "Done", wx.ICON_INFORMATION
             if os.path.isdir(os.path.dirname(filepath)):
-                result = self.Controler.GenerateProgram(filepath)
-                if result is not None:
-                    message = wx.MessageDialog(self, "Can't generate program to file %s :\n%s"%(filepath, result), "Error", wx.OK|wx.ICON_ERROR)
-                    message.ShowModal()
-                    message.Destroy()
+                program, errors, warnings = self.Controler.GenerateProgram(filepath)
+                message_text += "".join(["warning: %s\n" for warning in warnings])
+                if len(errors) > 0:
+                    message_text += "".join(["error: %s\n" for warning in warnings])
+                    message_text += "Can't generate program to file %s!"%filepath
+                    header, icon = "Error", wx.ICON_ERROR
                 else:
-                    message = wx.MessageDialog(self, "Program was successfully generated!", "Done", wx.OK|wx.ICON_INFORMATION)
-                    message.ShowModal()
-                    message.Destroy()
+                    message_text += "Program was successfully generated!"
             else:
-                message = wx.MessageDialog(self, "%s is not a valid folder!"%os.path.dirname(filepath), "Error", wx.OK|wx.ICON_ERROR)
-                message.ShowModal()
-                message.Destroy()
+                message_text += "%s is not a valid folder!"%os.path.dirname(filepath)
+                header, icon = "Error", wx.ICON_ERROR
+            message = wx.MessageDialog(self, message_text, header, wx.OK|icon)
+            message.ShowModal()
+            message.Destroy()
         dialog.Destroy()
         event.Skip()
 
--- a/generate_IEC_std.py	Mon Jan 19 17:07:03 2009 +0100
+++ b/generate_IEC_std.py	Mon Jan 19 17:08:17 2009 +0100
@@ -108,14 +108,14 @@
     This tests are defined in search_expression_type.cc 
     """
     return {"ANY" : "",
-    "ANY_BIT" : "if(search_expression_type->is_binary_type(%(paramname)s_type_symbol))",
-    "ANY_NBIT" : "if(search_expression_type->is_nbinary_type(%(paramname)s_type_symbol))",
-    "ANY_NUM" : "if(search_expression_type->is_num_type(%(paramname)s_type_symbol))",
-    "ANY_REAL" : "if(search_expression_type->is_real_type(%(paramname)s_type_symbol))",
-    "ANY_INT" : "if(search_expression_type->is_integer_type(%(paramname)s_type_symbol))"
+    "ANY_BIT" : "if(%(paramname)s_type_symbol == NULL || search_expression_type->is_binary_type(%(paramname)s_type_symbol))",
+    "ANY_NBIT" : "if(%(paramname)s_type_symbol == NULL || search_expression_type->is_nbinary_type(%(paramname)s_type_symbol))",
+    "ANY_NUM" : "if(%(paramname)s_type_symbol == NULL || search_expression_type->is_num_type(%(paramname)s_type_symbol))",
+    "ANY_REAL" : "if(%(paramname)s_type_symbol == NULL || search_expression_type->is_real_type(%(paramname)s_type_symbol))",
+    "ANY_INT" : "if(%(paramname)s_type_symbol == NULL || search_expression_type->is_integer_type(%(paramname)s_type_symbol))"
     }.get(typename,
         #"if (typeid(*last_type_symbol) == typeid(%(typename)s_type_name_c))")%{
-        "if(search_expression_type->is_same_type(&search_constant_type_c::%(typename)s_type_name, last_type_symbol))")%{
+        "if(%(paramname)s_type_symbol == NULL || search_expression_type->is_same_type(&search_constant_type_c::%(typename)s_type_name, last_type_symbol))")%{
                 "paramname" : paramname, "typename": typename.lower()}
 
 def recurse_and_indent(fdecls, indent, do_type_search_only = False, do_il = False):
@@ -151,12 +151,15 @@
     identifier_c param_name("%(input_name)s");
     /* Get the value from a foo(<param_name> = <param_value>) style call */
     symbol_c *%(input_name)s_param_value = function_call_param_iterator.search(&param_name);
+    symbol_c *%(input_name)s_type_symbol = NULL;
     
     /* Get the value from a foo(<param_value>) style call */
     if (%(input_name)s_param_value == NULL)
       %(input_name)s_param_value = function_call_param_iterator.next();
-    symbol_c *%(input_name)s_type_symbol = search_expression_type->get_type(%(input_name)s_param_value);
-    last_type_symbol = last_type_symbol && search_expression_type->is_same_type(%(input_name)s_type_symbol, last_type_symbol) ? search_expression_type->common_type(%(input_name)s_type_symbol, last_type_symbol) : %(input_name)s_type_symbol ;
+    if (%(input_name)s_param_value != NULL) {
+      %(input_name)s_type_symbol = search_expression_type->get_type(%(input_name)s_param_value);
+      last_type_symbol = last_type_symbol && %(input_name)s_type_symbol && search_expression_type->is_same_type(%(input_name)s_type_symbol, last_type_symbol) ? search_expression_type->common_type(%(input_name)s_type_symbol, last_type_symbol) : %(input_name)s_type_symbol ;
+    }
 """%{"input_name":Paramname}
                                 
             for ParamType,NextParamDecl in ParamTypes.iteritems():
@@ -188,13 +191,18 @@
                 res += "function_name = (symbol_c*)(new pragma_c(\"%s\"));\n"%code_gen[1]
             if fdecl["extensible"]:
                 res += """
+if (nb_param < %(min_nb_param)d)
+  nb_param = %(min_nb_param)d;
 char* nb_param_str = new char[10];
-sprintf(nb_param_str, "%d", nb_param);
+sprintf(nb_param_str, "%%d", nb_param);
 ADD_PARAM_LIST((symbol_c*)(new integer_c((const char *)nb_param_str)), (symbol_c*)(new int_type_name_c()), function_param_iterator_c::direction_in)
-"""
+"""%{"min_nb_param" : len(fdecl["inputs"])}
             for paramname,paramtype,unused in fdecl["inputs"]:
-                res += "ADD_PARAM_LIST(%(input_name)s_param_value, %(input_name)s_type_symbol, function_param_iterator_c::direction_in)\n"%{"input_name" : paramname}
-
+                res += """
+if (%(input_name)s_type_symbol == NULL)
+  %(input_name)s_type_symbol = last_type_symbol;
+ADD_PARAM_LIST(%(input_name)s_param_value, %(input_name)s_type_symbol, function_param_iterator_c::direction_in)
+"""%{"input_name" : paramname}
             if fdecl["extensible"]:
                 res += """
 int base_num = %d;
--- a/plcopen/structures.py	Mon Jan 19 17:07:03 2009 +0100
+++ b/plcopen/structures.py	Mon Jan 19 17:08:17 2009 +0100
@@ -51,42 +51,48 @@
         if not generator.ComputedBlocks.get(block, False) and not order:
             generator.ComputedBlocks[block] = True
             vars = []
+            one_input_connected = False
             for i, variable in enumerate(block.inputVariables.getvariable()):
                 input_info = (generator.TagName, "block", block.getlocalId(), "input", i)
                 connections = variable.connectionPointIn.getconnections()
                 if connections is not None:
+                    parameter = variable.getformalParameter()
+                    if parameter != "EN":
+                        one_input_connected = True
                     value = generator.ComputeExpression(body, connections, executionOrderId > 0)
                     if len(output_variables) > 1:
-                        parameter = variable.getformalParameter()
                         vars.append([(parameter, input_info),
                                      (" := ", ())] + generator.ExtractModifier(variable, value, input_info))
                     else:
                         vars.append(generator.ExtractModifier(variable, value, input_info))
-            for i, variable in enumerate(output_variables):
-                parameter = variable.getformalParameter()
-                if variable.getformalParameter() == "":
-                    variable_name = "%s%d"%(type, block.getlocalId())
-                else:
-                    variable_name = "%s%d_%s"%(type, block.getlocalId(), parameter)
-                if generator.Interface[-1][0] != "VAR" or generator.Interface[-1][1] or generator.Interface[-1][2] or generator.Interface[-1][3]:
-                    generator.Interface.append(("VAR", False, False, False, []))
-                if variable.connectionPointOut in generator.ConnectionTypes:
-                    generator.Interface[-1][4].append((generator.ConnectionTypes[variable.connectionPointOut], variable_name, None, None))
-                else:
-                    generator.Interface[-1][4].append(("ANY", variable_name, None, None))
-                if len(output_variables) > 1 and parameter not in ["", "OUT"]:
-                    vars.append([(parameter, (generator.TagName, "block", block.getlocalId(), "output", i)), 
-                                 (" => %s"%variable_name, ())])
-                else:
-                    output_info = (generator.TagName, "block", block.getlocalId(), "output", i)
-                    output_name = variable_name
-            generator.Program += [(generator.CurrentIndent, ()),
-                                  (output_name, output_info),
-                                  (" := ", ()),
-                                  (type, (generator.TagName, "block", block.getlocalId(), "type")),
-                                  ("(", ())]
-            generator.Program += JoinList([(", ", ())], vars)
-            generator.Program += [(");\n", ())]
+            if one_input_connected:
+                for i, variable in enumerate(output_variables):
+                    parameter = variable.getformalParameter()
+                    if variable.getformalParameter() == "":
+                        variable_name = "%s%d"%(type, block.getlocalId())
+                    else:
+                        variable_name = "%s%d_%s"%(type, block.getlocalId(), parameter)
+                    if generator.Interface[-1][0] != "VAR" or generator.Interface[-1][1] or generator.Interface[-1][2] or generator.Interface[-1][3]:
+                        generator.Interface.append(("VAR", False, False, False, []))
+                    if variable.connectionPointOut in generator.ConnectionTypes:
+                        generator.Interface[-1][4].append((generator.ConnectionTypes[variable.connectionPointOut], variable_name, None, None))
+                    else:
+                        generator.Interface[-1][4].append(("ANY", variable_name, None, None))
+                    if len(output_variables) > 1 and parameter not in ["", "OUT"]:
+                        vars.append([(parameter, (generator.TagName, "block", block.getlocalId(), "output", i)), 
+                                     (" => %s"%variable_name, ())])
+                    else:
+                        output_info = (generator.TagName, "block", block.getlocalId(), "output", i)
+                        output_name = variable_name
+                generator.Program += [(generator.CurrentIndent, ()),
+                                      (output_name, output_info),
+                                      (" := ", ()),
+                                      (type, (generator.TagName, "block", block.getlocalId(), "type")),
+                                      ("(", ())]
+                generator.Program += JoinList([(", ", ())], vars)
+                generator.Program += [(");\n", ())]
+            else:
+                generator.Warnings.append("\"%s\" function cancelled in \"%s\" POU: No input connected"%(type, generator.TagName.split("::")[-1]))
         if link:
             connectionPoint = link.getposition()[-1]
         else: