More optimization attemps in type handling
authorEdouard Tisserant
Sun, 04 Aug 2013 22:55:12 +0900
changeset 1283 f3cfe1ff917e
parent 1282 f427352f9727
child 1284 abf63a310532
More optimization attemps in type handling
PLCControler.py
plcopen/plcopen.py
plcopen/structures.py
--- a/PLCControler.py	Fri Aug 02 08:58:09 2013 +0900
+++ b/PLCControler.py	Sun Aug 04 22:55:12 2013 +0900
@@ -210,7 +210,8 @@
         self.NextCompiledProject = None
         self.CurrentCompiledProject = None
         self.ConfNodeTypes = []
-        self.ProgramFilePath = ""
+        self.TotalTypesDict = StdBlckDct.copy()
+        self.TotalTypes = StdBlckLst[:]
         
     def GetQualifierTypes(self):
         return plcopen.QualifierList
@@ -1534,25 +1535,34 @@
     # Function that add a new confnode to the confnode list
     def AddConfNodeTypesList(self, typeslist):
         self.ConfNodeTypes.extend(typeslist)
+        addedcat = [{"name": _("%s POUs") % confnodetypes["name"],
+                     "list": confnodetypes["types"].GetCustomBlockTypes()}
+                     for confnodetypes in typeslist]
+        self.TotalTypes.extend(addedcat)
+        for cat in addedcat:
+            for desc in cat["list"]:
+                BlkLst = self.TotalTypesDict.setdefault(desc["name"],[])
+                BlkLst.append((section["name"], desc))
         
     # Function that clear the confnode list
     def ClearConfNodeTypes(self):
-        for i in xrange(len(self.ConfNodeTypes)):
-            self.ConfNodeTypes.pop(0)
+        self.ConfNodeTypes = []
+        self.TotalTypesDict = StdBlckDct.copy()
+        self.TotalTypes = StdBlckLst[:]
 
     def GetConfNodeBlockTypes(self):
         return [{"name": _("%s POUs") % confnodetypes["name"],
                  "list": confnodetypes["types"].GetCustomBlockTypes()}
                 for confnodetypes in self.ConfNodeTypes]
         
-    def GetConfNodeDataTypes(self, exclude = "", only_locatables = False):
+    def GetConfNodeDataTypes(self, exclude = None, only_locatables = False):
         return [{"name": _("%s Data Types") % confnodetypes["name"],
                  "list": [datatype["name"] for datatype in confnodetypes["types"].GetCustomDataTypes(exclude, only_locatables)]}
                 for confnodetypes in self.ConfNodeTypes]
     
-    def GetConfNodeDataType(self, type):
+    def GetConfNodeDataType(self, typename):
         for confnodetype in self.ConfNodeTypes:
-            datatype = confnodetype["types"].getdataType(type)
+            datatype = confnodetype["types"].getdataType(typename)
             if datatype is not None:
                 return datatype
         return None
@@ -1592,61 +1602,59 @@
         return global_vars
 
     # Function that returns the block definition associated to the block type given
-    def GetBlockType(self, type, inputs = None, debug = False):
+    def GetBlockType(self, typename, inputs = None, debug = False):
         result_blocktype = None
-        for category in BlockTypes + self.GetConfNodeBlockTypes():
-            for blocktype in category["list"]:
-                if blocktype["name"] == type:
-                    if inputs is not None and inputs != "undefined":
-                        block_inputs = tuple([var_type for name, var_type, modifier in blocktype["inputs"]])
-                        if reduce(lambda x, y: x and y, map(lambda x: x[0] == "ANY" or self.IsOfType(*x), zip(inputs, block_inputs)), True):
-                            return blocktype
+        for sectioname, blocktype in self.TotalTypesDict.get(typename,[]):
+            if inputs is not None and inputs != "undefined":
+                block_inputs = tuple([var_type for name, var_type, modifier in blocktype["inputs"]])
+                if reduce(lambda x, y: x and y, map(lambda x: x[0] == "ANY" or self.IsOfType(*x), zip(inputs, block_inputs)), True):
+                    return blocktype
+            else:
+                if result_blocktype is not None:
+                    if inputs == "undefined":
+                        return None
                     else:
-                        if result_blocktype is not None:
-                            if inputs == "undefined":
-                                return None
-                            else:
-                                result_blocktype["inputs"] = [(i[0], "ANY", i[2]) for i in result_blocktype["inputs"]]
-                                result_blocktype["outputs"] = [(o[0], "ANY", o[2]) for o in result_blocktype["outputs"]]
-                                return result_blocktype
-                        result_blocktype = blocktype.copy()
+                        result_blocktype["inputs"] = [(i[0], "ANY", i[2]) for i in result_blocktype["inputs"]]
+                        result_blocktype["outputs"] = [(o[0], "ANY", o[2]) for o in result_blocktype["outputs"]]
+                        return result_blocktype
+                result_blocktype = blocktype.copy()
         if result_blocktype is not None:
             return result_blocktype
         project = self.GetProject(debug)
         if project is not None:
-            return project.GetCustomBlockType(type, inputs)
+            return project.GetCustomBlockType(typename, inputs)
         return None
 
     # Return Block types checking for recursion
     def GetBlockTypes(self, tagname = "", debug = False):
-        type = None
+        typename = None
         words = tagname.split("::")
-        if self.Project:
-            name = ""
+        name = None
+        project = self.GetProject(debug)
+        if project is not None:
+            blocktypes = []
             if words[0] in ["P","T","A"]:
                 name = words[1]
-                type = self.GetPouType(name, debug)
-        if type == "function":
-            blocktypes = []
-            for category in BlockTypes + self.GetConfNodeBlockTypes():
-                cat = {"name" : category["name"], "list" : []}
-                for block in category["list"]:
-                    if block["type"] == "function":
-                        cat["list"].append(block)
-                if len(cat["list"]) > 0:
-                    blocktypes.append(cat)
-        else:
-            blocktypes = [category for category in BlockTypes + self.GetConfNodeBlockTypes()]
-        project = self.GetProject(debug)
-        if project is not None:
-            blocktypes.append({"name" : USER_DEFINED_POUS, "list": project.GetCustomBlockTypes(name, type == "function" or words[0] == "T")})
-        return blocktypes
+                typename = self.GetPouType(name, debug)
+                if typename == "function":
+                    for category in self.TotalTypes:
+                        cat = {"name" : category["name"], "list" : []}
+                        for block in category["list"]:
+                            if block["type"] == "function":
+                                cat["list"].append(block)
+                        if len(cat["list"]) > 0:
+                            blocktypes.append(cat)
+                    blocktypes.append({"name" : USER_DEFINED_POUS, 
+                        "list": project.GetCustomBlockTypes(name, 
+                            typename == "function" or words[0] == "T")})
+                    return blocktypes
+        return self.TotalTypes
 
     # Return Function Block types checking for recursion
     def GetFunctionBlockTypes(self, tagname = "", debug = False):
         blocktypes = []
-        for category in BlockTypes + self.GetConfNodeBlockTypes():
-            for block in category["list"]:
+        for blocks in self.TotalTypesDict.itervalues():
+            for sectioname,block in blocks:
                 if block["type"] == "functionBlock":
                     blocktypes.append(block["name"])
         project = self.GetProject(debug)
@@ -1661,7 +1669,7 @@
     # Return Block types checking for recursion
     def GetBlockResource(self, debug = False):
         blocktypes = []
-        for category in BlockTypes[:-1]:
+        for category in StdBlckLst[:-1]:
             for blocktype in category["list"]:
                 if blocktype["type"] == "program":
                     blocktypes.append(blocktype["name"])
@@ -1677,8 +1685,8 @@
         else:
             datatypes = []
         project = self.GetProject(debug)
-        if project is not None:
-            name = ""
+        name = None
+        if project is not None:
             words = tagname.split("::")
             if words[0] in ["D"]:
                 name = words[1]
--- a/plcopen/plcopen.py	Fri Aug 02 08:58:09 2013 +0900
+++ b/plcopen/plcopen.py	Sun Aug 04 22:55:12 2013 +0900
@@ -26,7 +26,7 @@
 from structures import *
 from types import *
 import os, re
-
+from collections import OrderedDict
 """
 Dictionary that makes the relation between var names in plcopen and displayed values
 """
@@ -177,7 +177,7 @@
     cls.CustomDataTypeRange = {}
     cls.CustomTypeHierarchy = {}
     cls.ElementUsingTree = {}
-    cls.CustomBlockTypes = []
+    cls.CustomBlockTypes = OrderedDict()
     
     def setname(self, name):
         self.contentHeader.setname(name)
@@ -443,7 +443,7 @@
     # Update Block types with user-defined pou added
     def RefreshCustomBlockTypes(self):
         # Reset the tree of user-defined pou cross-use
-        self.CustomBlockTypes = []
+        self.CustomBlockTypes = OrderedDict()
         for pou in self.getpous():
             self.AddCustomBlockType(pou)
     setattr(cls, "RefreshCustomBlockTypes", RefreshCustomBlockTypes)
@@ -497,7 +497,7 @@
                             block_infos["outputs"].append((var.getname(), var_type["name"], "none"))    
         block_infos["usage"] = "\n (%s) => (%s)" % (", ".join(["%s:%s" % (input[1], input[0]) for input in block_infos["inputs"]]),
                                                     ", ".join(["%s:%s" % (output[1], output[0]) for output in block_infos["outputs"]]))
-        self.CustomBlockTypes.append(block_infos)
+        self.CustomBlockTypes[pou_name]=block_infos
     setattr(cls, "AddCustomBlockType", AddCustomBlockType)
 
     def AddElementUsingTreeInstance(self, name, type_infos):
@@ -633,14 +633,14 @@
     setattr(cls, "GetEnumeratedDataTypeValues", GetEnumeratedDataTypeValues)
 
     # Function that returns the block definition associated to the block type given
-    def GetCustomBlockType(self, type, inputs = None):
-        for customblocktype in self.CustomBlockTypes:
+    def GetCustomBlockType(self, typename, inputs = None):
+        customblocktype = self.CustomBlockTypes.get(typename,None)
+        if customblocktype is not None:
             if inputs is not None and inputs != "undefined":
                 customblock_inputs = tuple([var_type for name, var_type, modifier in customblocktype["inputs"]])
-                same_inputs = inputs == customblock_inputs
+                if inputs == customblock_inputs:
+                    return customblocktype
             else:
-                same_inputs = True
-            if customblocktype["name"] == type and same_inputs:
                 return customblocktype
         return None
     setattr(cls, "GetCustomBlockType", GetCustomBlockType)
@@ -648,32 +648,31 @@
     # Return Block types checking for recursion
     def GetCustomBlockTypes(self, exclude = None, onlyfunctions = False):
         if exclude is not None:
-            return [customblocktype for customblocktype in self.CustomBlockTypes
+            return [customblocktype for name,customblocktype in self.CustomBlockTypes.iteritems()
                 if (customblocktype["type"] != "program"
-                    and customblocktype["name"] != exclude
-                    and not self.ElementIsUsedBy(exclude, customblocktype["name"])
+                    and name != exclude
+                    and not self.ElementIsUsedBy(exclude, name)
                     and not (onlyfunctions and customblocktype["type"] != "function"))]
-        return [customblocktype for customblocktype in self.CustomBlockTypes
+        return [customblocktype for customblocktype in self.CustomBlockTypes.itervalues()
             if (customblocktype["type"] != "program"
                 and not (onlyfunctions and customblocktype["type"] != "function"))]
     setattr(cls, "GetCustomBlockTypes", GetCustomBlockTypes)
 
     # Return Function Block types checking for recursion
-    def GetCustomFunctionBlockTypes(self, exclude = ""):
-        customblocktypes = []
-        for customblocktype in self.CustomBlockTypes:
-            if customblocktype["type"] == "functionBlock" and customblocktype["name"] != exclude and not self.ElementIsUsedBy(exclude, customblocktype["name"]):
-                customblocktypes.append(customblocktype["name"])
-        return customblocktypes
+    def GetCustomFunctionBlockTypes(self, exclude = None):
+        if exclude is not None:
+            return [customblocktype for name,customblocktype in self.CustomBlockTypes.iteritems()
+                if (customblocktype["type"] == "functionBlock" 
+                    and name != exclude 
+                    and not self.ElementIsUsedBy(exclude, name))]
+        return [customblocktype for customblocktype in self.CustomBlockTypes.itervalues()
+            if customblocktype["type"] == "functionBlock"]
     setattr(cls, "GetCustomFunctionBlockTypes", GetCustomFunctionBlockTypes)
 
     # Return Block types checking for recursion
     def GetCustomBlockResource(self):
-        customblocktypes = []
-        for customblocktype in self.CustomBlockTypes:
-            if customblocktype["type"] == "program":
-                customblocktypes.append(customblocktype["name"])
-        return customblocktypes
+        return [customblocktype for customblocktype in self.CustomBlockTypes.itervalues()
+            if customblocktype["type"] == "program"]
     setattr(cls, "GetCustomBlockResource", GetCustomBlockResource)
 
     # Return Data Types checking for recursion
--- a/plcopen/structures.py	Fri Aug 02 08:58:09 2013 +0900
+++ b/plcopen/structures.py	Sun Aug 04 22:55:12 2013 +0900
@@ -250,7 +250,7 @@
     - The default modifier which can be "none", "negated", "rising" or "falling"
 """
 
-BlockTypes = [{"name" : _("Standard function blocks"), "list":
+StdBlckLst = [{"name" : _("Standard function blocks"), "list":
                [{"name" : "SR", "type" : "functionBlock", "extensible" : False, 
                     "inputs" : [("S1","BOOL","none"),("R","BOOL","none")], 
                     "outputs" : [("Q1","BOOL","none")],
@@ -663,9 +663,12 @@
 
 std_decl = get_standard_funtions(csv_file_to_table(open(os.path.join(os.path.split(__file__)[0],"iec_std.csv"))))#, True)
 
-BlockTypes.extend(std_decl)
-
-for section in BlockTypes: 
+StdBlckLst.extend(std_decl)
+
+# Dictionary to speedup block type fetching by name
+StdBlckDct = {}
+
+for section in StdBlckLst:
     for desc in section["list"]:
         words = desc["comment"].split('"')
         if len(words) > 1:
@@ -676,7 +679,8 @@
             " ) => (" +
             str([ " " + fctdecl[1]+":"+fctdecl[0] for fctdecl in desc["outputs"]]).strip("[]").replace("'",'') +
             " )")
-
+        BlkLst = StdBlckDct.setdefault(desc["name"],[])
+        BlkLst.append((section["name"], desc))
 
 #-------------------------------------------------------------------------------
 #                            Languages Keywords
@@ -687,7 +691,7 @@
 POU_BLOCK_START_KEYWORDS = ["FUNCTION", "FUNCTION_BLOCK", "PROGRAM"]
 POU_BLOCK_END_KEYWORDS = ["END_FUNCTION", "END_FUNCTION_BLOCK", "END_PROGRAM"]
 POU_KEYWORDS = ["EN", "ENO", "F_EDGE", "R_EDGE"] + POU_BLOCK_START_KEYWORDS + POU_BLOCK_END_KEYWORDS
-for category in BlockTypes:
+for category in StdBlckLst:
     for block in category["list"]:
         if block["name"] not in POU_KEYWORDS:
             POU_KEYWORDS.append(block["name"])