diff -r e5bf78b847e1 -r 7726c8ffda42 plcopen/plcopen.py --- a/plcopen/plcopen.py Fri Jul 18 15:44:37 2008 +0200 +++ b/plcopen/plcopen.py Tue Aug 12 16:28:55 2008 +0200 @@ -23,6 +23,7 @@ #Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA from xmlclass import * +from structures import * from types import * import os, re @@ -63,6 +64,11 @@ cls = PLCOpenClasses.get("project", None) if cls: cls.singleLineAttributes = False + cls.EnumeratedDataTypeValues = {} + cls.CustomDataTypeRange = {} + cls.CustomTypeHierarchy = {} + cls.ElementUsingTree = {} + cls.CustomBlockTypes = [] def setname(self, name): self.contentHeader.setname(name) @@ -143,15 +149,21 @@ setattr(cls, "getdataType", getdataType) def appenddataType(self, name): + if name in self.CustomTypeHierarchy: + raise ValueError, "\"%s\" Data Type already exists !!!"%name self.types.appenddataTypeElement(name) + self.AddCustomDataType(self.getdataType(name)) setattr(cls, "appenddataType", appenddataType) def insertdataType(self, index, datatype): self.types.insertdataTypeElement(index, datatype) + self.AddCustomDataType(datatype) setattr(cls, "insertdataType", insertdataType) def removedataType(self, name): self.types.removedataTypeElement(name) + self.RefreshDataTypeHierarchy() + self.RefreshElementUsingTree() setattr(cls, "removedataType", removedataType) def getpous(self): @@ -164,14 +176,18 @@ def appendpou(self, name, pou_type, body_type): self.types.appendpouElement(name, pou_type, body_type) + self.AddCustomBlockType(self.getpou(name)) setattr(cls, "appendpou", appendpou) def insertpou(self, index, pou): self.types.insertpouElement(index, pou) + self.AddCustomBlockType(pou) setattr(cls, "insertpou", insertpou) def removepou(self, name): self.types.removepouElement(name) + self.RefreshCustomBlockTypes() + self.RefreshElementUsingTree() setattr(cls, "removepou", removepou) def getconfigurations(self): @@ -248,6 +264,275 @@ configuration.updateElementName(old_name, new_name) setattr(cls, "updateElementName", updateElementName) + def RefreshDataTypeHierarchy(self): + self.EnumeratedDataTypeValues = {} + self.CustomDataTypeRange = {} + self.CustomTypeHierarchy = {} + for datatype in self.getdataTypes(): + self.AddCustomDataType(datatype) + setattr(cls, "RefreshDataTypeHierarchy", RefreshDataTypeHierarchy) + + def AddCustomDataType(self, datatype): + name = datatype.getname() + basetype_content = datatype.getbaseType().getcontent() + if basetype_content["value"] is None: + self.CustomTypeHierarchy[name] = basetype_content["name"] + elif basetype_content["name"] in ["string", "wstring"]: + self.CustomTypeHierarchy[name] = basetype_content["name"].upper() + elif basetype_content["name"] == "derived": + self.CustomTypeHierarchy[name] = basetype_content["value"].getname() + elif basetype_content["name"] in ["subrangeSigned", "subrangeUnsigned"]: + range = (basetype_content["value"].range.getlower(), + basetype_content["value"].range.getupper()) + self.CustomDataTypeRange[name] = range + base_type = basetype_content["value"].baseType.getcontent() + if base_type["value"] is None: + self.CustomTypeHierarchy[name] = base_type["name"] + else: + self.CustomTypeHierarchy[name] = base_type["value"].getname() + else: + if basetype_content["name"] == "enum": + values = [] + for value in basetype_content["value"].values.getvalue(): + values.append(value.getname()) + self.EnumeratedDataTypeValues[name] = values + self.CustomTypeHierarchy[name] = "ANY_DERIVED" + setattr(cls, "AddCustomDataType", AddCustomDataType) + + # Update Block types with user-defined pou added + def RefreshCustomBlockTypes(self): + # Reset the tree of user-defined pou cross-use + self.CustomBlockTypes = [] + for pou in self.getpous(): + self.AddCustomBlockType(pou) + setattr(cls, "RefreshCustomBlockTypes", RefreshCustomBlockTypes) + + def AddCustomBlockType(self, pou): + pou_name = pou.getname() + pou_type = pou.getpouType() + if pou_type != "program": + block_infos = {"name" : pou_name, "type" : pou_type, "extensible" : False, + "inputs" : [], "outputs" : [], "comment" : "", + "generate" : generate_block, "initialise" : initialise_block } + if pou.getinterface(): + for type, varlist in pou.getvars(): + if type == "InOut": + for var in varlist.getvariable(): + var_type = var.type.getcontent() + if var_type["name"] == "derived": + block_infos["inputs"].append((var.getname(), var_type["value"].getname(), "none")) + block_infos["outputs"].append((var.getname(), var_type["value"].getname(), "none")) + elif var_type["name"] in ["string", "wstring"]: + block_infos["inputs"].append((var.getname(), var_type["name"].upper(), "none")) + block_infos["outputs"].append((var.getname(), var_type["name"].upper(), "none")) + else: + block_infos["inputs"].append((var.getname(), var_type["name"], "none")) + block_infos["outputs"].append((var.getname(), var_type["name"], "none")) + elif type == "Input": + for var in varlist.getvariable(): + var_type = var.type.getcontent() + if var_type["name"] == "derived": + block_infos["inputs"].append((var.getname(), var_type["value"].getname(), "none")) + elif var_type["name"] in ["string", "wstring"]: + block_infos["inputs"].append((var.getname(), var_type["name"].upper(), "none")) + else: + block_infos["inputs"].append((var.getname(), var_type["name"], "none")) + elif type == "Output": + for var in varlist.getvariable(): + var_type = var.type.getcontent() + if var_type["name"] == "derived": + block_infos["outputs"].append((var.getname(), var_type["value"].getname(), "none")) + elif var_type["name"] in ["string", "wstring"]: + block_infos["outputs"].append((var.getname(), var_type["name"].upper(), "none")) + else: + block_infos["outputs"].append((var.getname(), var_type["name"], "none")) + return_type = pou.interface.getreturnType() + if return_type: + var_type = return_type.getcontent() + if var_type["name"] == "derived": + block_infos["outputs"].append(("", var_type["value"].getname(), "none")) + elif var_type["name"] in ["string", "wstring"]: + block_infos["outputs"].append(("", var_type["name"].upper(), "none")) + else: + block_infos["outputs"].append(("", var_type["name"], "none")) + if pou.getbodyType() in ["FBD","LD","SFC"]: + for instance in pou.getinstances(): + if isinstance(instance, PLCOpenClasses.get("commonObjects_comment", None)): + block_infos["comment"] = instance.getcontentText() + self.CustomBlockTypes.append(block_infos) + setattr(cls, "AddCustomBlockType", AddCustomBlockType) + + def RefreshElementUsingTree(self): + # Reset the tree of user-defined element cross-use + self.ElementUsingTree = {} + pous = self.getpous() + # Reference all the user-defined elementu names and initialize the tree of + # user-defined elemnt cross-use + pounames = [pou.getname() for pou in pous] + for name in pounames: + self.ElementUsingTree[name] = [] + # Analyze each pou + for pou in pous: + name = pou.getname() + if pou.interface: + # Extract variables from every varLists + for type, varlist in pou.getvars(): + for var in varlist.getvariable(): + vartype_content = var.gettype().getcontent() + if vartype_content["name"] == "derived": + typename = vartype_content["value"].getname() + if typename in pounames and name not in self.ElementUsingTree[typename]: + self.ElementUsingTree[typename].append(name) + setattr(cls, "RefreshElementUsingTree", RefreshElementUsingTree) + + def GetParentType(self, type): + if type in self.CustomTypeHierarchy: + return self.CustomTypeHierarchy[type] + elif type in TypeHierarchy: + return TypeHierarchy[type] + return None + setattr(cls, "GetParentType", GetParentType) + + def GetBaseType(self, type): + parent_type = self.GetParentType(type) + if parent_type is not None: + if parent_type.startswith("ANY"): + return type + else: + return self.GetBaseType(parent_type) + return None + setattr(cls, "GetBaseType", GetBaseType) + + def GetSubrangeBaseTypes(self, exclude): + derived = [] + for type in self.CustomTypeHierarchy.keys(): + for base_type in DataTypeRange.keys(): + if self.IsOfType(type, base_type) and not self.IsOfType(type, exclude): + derived.append(type) + break + return DataTypeRange.keys() + derived + setattr(cls, "GetSubrangeBaseTypes", GetSubrangeBaseTypes) + + """ + returns true if the given data type is the same that "reference" meta-type or one of its types. + """ + def IsOfType(self, type, reference): + if reference is None: + return True + elif type == reference: + return True + else: + parent_type = self.GetParentType(type) + if parent_type is not None: + return self.IsOfType(parent_type, reference) + return False + setattr(cls, "IsOfType", IsOfType) + + # Return if pou given by name is used by another pou + def ElementIsUsed(self, name): + if name in self.ElementUsingTree: + return len(self.ElementUsingTree[name]) > 0 + return False + setattr(cls, "ElementIsUsed", ElementIsUsed) + + def DataTypeIsDerived(self, name): + return name in self.CustomTypeHierarchy.values() + setattr(cls, "DataTypeIsDerived", DataTypeIsDerived) + + # Return if pou given by name is directly or undirectly used by the reference pou + def ElementIsUsedBy(self, name, reference): + if name in self.ElementUsingTree: + list = self.ElementUsingTree[name] + # Test if pou is directly used by reference + if reference in list: + return True + else: + # Test if pou is undirectly used by reference, by testing if pous + # that directly use pou is directly or undirectly used by reference + used = False + for element in list: + used |= self.ElementIsUsedBy(element, reference) + return used + return False + setattr(cls, "ElementIsUsedBy", ElementIsUsedBy) + + def GetDataTypeRange(self, type): + if type in self.CustomDataTypeRange: + return self.CustomDataTypeRange[type] + elif type in DataTypeRange: + return DataTypeRange[type] + else: + parent_type = self.GetParentType(type) + if parent_type is not None: + return self.GetDataTypeRange(parent_type) + return None + setattr(cls, "GetDataTypeRange", GetDataTypeRange) + + def GetEnumeratedDataTypeValues(self, type = None): + if type is None: + all_values = [] + for values in self.EnumeratedDataTypeValues.values(): + all_values.extend(values) + return all_values + elif type in self.EnumeratedDataTypeValues: + return self.EnumeratedDataTypeValues(type) + return [] + 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: + if inputs: + customblock_inputs = tuple([var_type for name, var_type, modifier in customblocktype["inputs"]]) + same_inputs = inputs == customblock_inputs + else: + same_inputs = True + if customblocktype["name"] == type and same_inputs: + return customblocktype + return None + setattr(cls, "GetCustomBlockType", GetCustomBlockType) + + # Return Block types checking for recursion + def GetCustomBlockTypes(self, exclude = ""): + pou = self.getpou(exclude) + type = pou.getpouType() + customblocktypes = [] + for customblocktype in self.CustomBlockTypes: + if customblocktype["name"] != exclude and not self.ElementIsUsedBy(exclude, customblocktype["name"]) and not (type == "function" and customblocktype["type"] != "function"): + customblocktypes.append(customblocktype) + return customblocktypes + setattr(cls, "GetCustomBlockTypes", GetCustomBlockTypes) + + # Return Function Block types checking for recursion + def GetCustomFunctionBlockTypes(self, exclude = ""): + pou = self.getpou(exclude) + type = pou.getpouType() + customblocktypes = [] + for customblocktype in self.CustomBlockTypes: + if customblocktype["name"] != exclude and not self.ElementIsUsedBy(exclude, customblocktype["name"]) and not (type == "function" and customblocktype["type"] != "function"): + customblocktypes.appendcustom(customblocktype["name"]) + return customblocktypes + 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 + setattr(cls, "GetCustomBlockResource", GetCustomBlockResource) + + # Return Data Types checking for recursion + def GetCustomDataTypes(self, exclude = ""): + customdatatypes = [] + for customdatatype in self.getdataTypes(): + customdatatype_name = customdatatype.getname() + if customdatatype_name != exclude and not self.ElementIsUsedBy(exclude, customdatatype_name): + customdatatypes.append(customdatatype_name) + return customdatatypes + setattr(cls, "GetCustomDataTypes", GetCustomDataTypes) + cls = PLCOpenClasses.get("project_fileHeader", None) if cls: cls.singleLineAttributes = False @@ -365,15 +650,12 @@ setattr(cls, "getdataTypeElement", getdataTypeElement) def appenddataTypeElement(self, name): - for element in self.dataTypes.getdataType(): - if element.getname() == name: - raise ValueError, "\"%s\" Data Type already exists !!!"%name new_datatype = PLCOpenClasses["dataTypes_dataType"]() new_datatype.setname(name) new_datatype.baseType.setcontent({"name" : "BOOL", "value" : None}) self.dataTypes.appenddataType(new_datatype) setattr(cls, "appenddataTypeElement", appenddataTypeElement) - + def insertdataTypeElement(self, index, dataType): self.dataTypes.insertdataType(index, dataType) setattr(cls, "insertdataTypeElement", insertdataTypeElement)