dia r4316 - in trunk: . plug-ins/python



Author: hans
Date: Mon Mar  9 23:19:30 2009
New Revision: 4316
URL: http://svn.gnome.org/viewvc/dia?rev=4316&view=rev

Log:
2009-03-09  Hans Breuer  <hans breuer org>

	* plug-ins/python/codegen.py : PascalRenderer by Johann Glaser and
	some adjustments to (Cxx/Py/Java)Renderer to almost get on par
	(now really commited)


Modified:
   trunk/ChangeLog
   trunk/plug-ins/python/codegen.py

Modified: trunk/plug-ins/python/codegen.py
==============================================================================
--- trunk/plug-ins/python/codegen.py	(original)
+++ trunk/plug-ins/python/codegen.py	Mon Mar  9 23:19:30 2009
@@ -20,6 +20,7 @@
 class Klass :
 	def __init__ (self, name) :
 		self.name = name
+		# use a list to preserve the order		
 		self.attributes = []
 		# a list, as java/c++ support multiple methods with the same name
 		self.operations = []
@@ -27,8 +28,8 @@
 		self.parents = []
 		self.templates = []
 		self.inheritance_type = ""
-	def AddAttribute(self, name, type, visibility, value) :
-		self.attributes.append ((name, (type, visibility, value)))
+	def AddAttribute(self, name, type, visibility, value, comment) :
+		self.attributes.append ((name, (type, visibility, value, comment)))
 	def AddOperation(self, name, type, visibility, params, inheritance_type, comment, class_scope) :
 		self.operations.append((name,(type, visibility, params, inheritance_type, comment, class_scope)))
 	def SetComment(self, s) :
@@ -70,13 +71,15 @@
 						params = []
 						for par in op[8] :
 							# par : again fixed placement, see objects/UML/umlparameter.c:umlparameter_props
-							params.append((par[0], par[1]))
+							# (name, type, value, comment, kind)
+							params.append((par[0], par[1], par[2], par[3], par[4]))
 						k.AddOperation (op[0], op[1], op[4], params, op[5], op[2], op[7])
 					#print o.properties["attributes"].value
 					for attr in o.properties["attributes"].value :
 						# see objects/UML/umlattributes.c:umlattribute_props
 						#print "\t", attr[0], attr[1], attr[4]
-						k.AddAttribute(attr[0], attr[1], attr[4], attr[2])
+						# name, type, value, comment, visibility, abstract, class_scope
+						k.AddAttribute(attr[0], attr[1], attr[4], attr[2], attr[3])
 					self.klasses[o.properties["name"].value] = k
 					#Connections
 				elif o.type.name == "UML - Association" :
@@ -123,13 +126,16 @@
 				f.write ("class %s :\n" % (sk,))
 			else:
 				f.write ("class %s (%s) :\n" % (sk,", ".join(parents)))
+			k = self.klasses[sk]
+			if len(k.comment) > 0 :
+				f.write ("\t'''" + k.comment + "'''\n")
 			f.write ("\tdef __init__(self) :\n")
-			for sa, attr in self.klasses[sk].attributes :
+			for sa, attr in k.attributes :
 				value = attr[2] == "" and "None" or attr[2]
 				f.write("\t\tself.%s = %s # %s\n" % (sa, value, attr[0]))
 			else :
 				f.write("\t\tpass\n")
-			for so, op in self.klasses[sk].operations :
+			for so, op in k.operations :
 				# we only need the parameter names
 				pars = "self"
 				for p in op[2] :
@@ -149,14 +155,20 @@
 		f.write("/* generated by dia/codegen.py */\n")
 		# declaration
 		for sk in self.klasses.keys() :
-			f.write ("class %s \n{\n" % (sk,))
 			k = self.klasses[sk]
+			if len(k.comment) > 0 :
+				f.write ("/*" + k.comment + "*/\n")
+			if len(k.parents) > 0 :
+				f.write ("class %s : %s \n{\n" % (sk, ", ".join(k.parents)))
+			else :
+				f.write ("class %s \n{\n" % (sk,))
 			# first sort by visibility
 			ops = [[], [], [], []]
 			for so, (t, v, p, i, c, s) in k.operations :
 				ops[v].append((t,so,p))
 			vars = [[], [], [], []]
-			for sa, (t, vi, va) in k.attributes :
+			for sa, (t, vi, va, vc) in k.attributes :
+				#TODO: use 'va'=value 'vc'=comment 
 				vars[vi].append((t, sa))
 			visibilities = ("public:", "private:", "protected:", "/* implementation: */")
 			for v in [0,2,1,3] :
@@ -190,6 +202,183 @@
 		f.close()
 		ObjRenderer.end_render(self)
 
+# #############################################################################
+# PascalRenderer: export Dia UML diagram to Object Pascal (Free Pascal, Delphi)
+#
+# Please follow some "drawing guidelines" and "naming conventions" so that the
+# exporter can do its job.
+#  - Use "UML - Generalization" arrows for class inheritance.
+#  - Use "UML - Realizes" arrows when implementing an interface.
+#  - Set a class to be "abstract" to denote it is an interface definition.
+#  - Set Inheritance Type to "abstract" for 'virtual; abstract;' methods, set
+#    it to "virtual" for 'virtual;' methods.
+#  - Array fields are automatically recognized. If the name ends with "[]"
+#    an 'Array of' is used. If the name uses a number with "[1234]", an
+#    'Array[0..1233] of' is used. If the name uses a constant with
+#    "[MaxEntries]" an 'Array[0..MaxEntries-1] of' is written.
+#  - To inherit from classes which are not drawn (e.g. LCL/VCL classes),
+#    name then class with the parent class in paranthesis (e.g. 
+#    "TMainWin(TForm)"
+#
+# Features
+#  - Inheriting from one class and implementing multiple interfaces is
+#    supported.
+#  - Comments for classes, attributes and operations are supported. They are
+#    put in the line before the method declaration with a '///' style comment
+#    (Doxygen-like).
+#  - Method parameter directions are supported (-> 'Var', 'Out').
+#  - Method parameter default values are supported.
+#  - 'Function' and 'Procedure' are automatically recognized by whether a
+#    return type exists or not.
+#  - order of classes is alphabetically
+#  - the order of attributes and operations is preserved
+#  - Prints a list of forward declarations of all classes at the beginning
+#    to avoid declaration order problems.
+#
+# TODO:
+#  - Automatically use the keyword "override" instead of "virtual" in
+#    descendant classes.
+#  - Automatically define 'Properties'. Unfortunately the UML standard
+#    doesn't support this and so the Dia dialog has no option to specify
+#    this. So a "code" has to be used.
+#  - Mark/recognize Constructors and Destructors
+#  - Write comments for method parameters (e.g. by using a big doxygen
+#    comment '(** ... *)' before the method)
+#  - Use "Packages" to split the classes in separate 'Unit's.
+#  - Beautify and comment the export code. Using arrays with "magic number
+#    indexes" for certain fields is bad and tedious to work with.
+#  - Support defining global constants.
+#  - Support defining global types (especially for enums, arrays,
+#    records, ...).
+#  - Apply some sanity checks to the UML diagram:
+#     - multiple inheritance is forbidded
+#     - if implementing an interface, all required methods must be
+#       implemented; alternative: just put all methods there, so the UML
+#       drawer doesn't have to write them twice
+#     - visibility for all methods of an interfaces must be "public"
+#     - don't write the visibility specifier 'public' for interfaces
+#     - no "Attributes" for interface definitions, but properties are
+#       allowed
+#     - default values for method parameters must be the last parameters
+
+class PascalRenderer(ObjRenderer) :
+	def __init__(self) :
+		ObjRenderer.__init__(self)
+	def end_render(self) :
+		f = open(self.filename, "w")
+		f.write("/* generated by dia/codegen.py */\n")
+		f.write("Type\n")
+		# classes
+		class_names = self.klasses.keys()
+		class_names.sort()
+		# forward declarations of all classes
+		for sk in class_names :
+			k = self.klasses[sk]
+			# class declaration
+			if k.inheritance_type == "abstract" :
+				f.write ("  %s = interface;\n" % (sk))
+			else :
+				f.write ("  %s = class;\n" % (sk))
+		f.write("\n");
+		# class declarations
+		for sk in class_names :
+			k = self.klasses[sk]
+			# comment
+			if len(k.comment) > 0 :
+				f.write("  /// %s\n" % (k.comment))
+			# class declaration
+			if k.inheritance_type == "abstract" :
+				f.write ("  %s = interface" % (sk))
+			else :
+				f.write ("  %s = class %s" % (sk, k.inheritance_type))
+			# inherited classes / implemented interfaces
+			p = []
+			if k.parents :
+				p.append(k.parents[0])
+			if k.templates :
+				p.append(",".join(k.templates))
+			if len(p) > 0 :
+				f.write("(%s)" % ",".join(p))
+			f.write ("\n")
+			# first sort by visibility
+			ops = [[], [], [], [], [], []]
+			for op_name, (op_type, op_visibility, op_params, op_inheritance, op_comment, op_class_scope) in k.operations :
+				ops[op_visibility].append((op_type, op_name, op_params, op_comment, op_inheritance))
+			vars = [[], [], [], []]
+			for var_name, (var_type, var_visibility, var_value, var_comment) in k.attributes :   # name, type, visibility, value, comment
+				vars[var_visibility].append((var_type, var_name, var_value, var_comment))
+			visibilities = ("public", "private", "protected", "/* implementation */")
+			for v in [1,2,0,3] :
+				if len(ops[v]) == 0 and len(vars[v]) == 0 :
+					continue
+				# visibility prefix
+				f.write ("  %s\n" % visibilities[v])
+				# variables
+				for var in vars[v] :
+					# comment
+					if len(var[3]) > 0 :
+						f.write ("    /// %s\n" % var[3])
+					if var[1].endswith("]") :
+						# array; check if this is dynamic or with defined size
+						i = var[1].find("[")
+						varname = var[1]
+						arraysize = varname[i+1:-1]
+						varname = varname[:i]
+						if len(arraysize) > 0 :
+							# array with defined size
+							if arraysize.find("..") > 0 :
+								f.write("    %s : Array[%s] of %s;\n" % (varname, arraysize, var[0]))
+							elif arraysize.isdigit() :
+								arraysize = int(arraysize)-1
+								f.write("    %s : Array[0..%d] of %s;\n" % (varname, arraysize, var[0]))
+							else :
+								f.write("    %s : Array[0..%s-1] of %s;\n" % (varname, arraysize, var[0]))
+						else :
+							# dynamic size
+							f.write("    %s : Array of %s;\n" % (varname, var[0]))
+					else :
+						# normal variable
+						f.write("    %s : %s;\n" % (var[1], var[0]))
+				# operations
+				for op in ops[v] :
+					if len(op[3]) > 0 :
+						f.write ("    /// %s\n" % op[3])
+					if len(op[0]) == 0 :
+						f.write ("    Procedure %s" % op[1])
+					else :
+						f.write ("    Function %s" % op[1])
+					if len(op[2]) > 0 :
+						f.write ("(")
+						i = 0
+						m = len(op[2]) - 1
+						for p in op[2] :
+							if p[4] == 2 :
+								f.write ("Out ")
+							elif p[4] == 3 :
+								f.write ("Var ")
+							f.write ("%s:%s" % (p[0], p[1]))
+							if len(p[2]) > 0 :
+								f.write (":=%s" % p[2])
+							if i != m :
+								f.write(";")
+							i = i + 1
+						f.write (")")
+					if len(op[0]) == 0 :
+						f.write(";")
+					else :
+						f.write (" : %s;" % op[0])
+					# inheritance type
+					if op[4] == 0 :
+						f.write (" virtual; abstract;");
+					elif op[4] == 1 :
+						f.write (" virtual;");
+					f.write ("\n")
+			f.write ("  End;\n\n")
+		# implementation
+		# ...
+		f.close()
+		ObjRenderer.end_render(self)
+
 class JavaRenderer(ObjRenderer) :
 	def __init__(self) :
 		ObjRenderer.__init__(self)
@@ -200,6 +389,8 @@
 		visibilities = {0:"public", 2:"private", 1:"protected"}
 
 		for name, klass in self.klasses.iteritems() :
+			if len(klass.comment) > 0 :
+				f.write ("/*" + klass.comment + "*/\n")
 			if klass.inheritance_type == "template": classtype = "interface"
 			elif klass.inheritance_type == "abstract": classtype = "abstract class"
 			else: classtype = "class"
@@ -210,7 +401,8 @@
 				f.write (" implements %s" % ", ".join(klass.templates))
 			f.write(" {\n")
 			
-			for attrname, (type, visibility, value) in klass.attributes :
+			for attrname, (type, visibility, value, comment) in klass.attributes :
+				#TODO: use comment
 				if visibility in visibilities:
 					vis = visibilities[visibility]+" "
 				else: vis = ""
@@ -243,7 +435,8 @@
 				# if there are no parameter names, something else should appear
 				pars = []
 				v = ord("a")
-				for name, type in method[2]:
+				for name, type, value, comment, kind in method[2]:
+					#TODO: also use: value, comment, kind
 					if not name:
 						pars.append((type,chr(v)))
 						v += 1
@@ -265,4 +458,5 @@
 # dia-python keeps a reference to the renderer class and uses it on demand
 dia.register_export ("PyDia Code Generation (Python)", "py", PyRenderer())
 dia.register_export ("PyDia Code Generation (C++)", "cxx", CxxRenderer())
+dia.register_export ("PyDia Code Generation (Pascal)", "pas", PascalRenderer())
 dia.register_export ("PyDia Code Generation (Java)", "java", JavaRenderer())



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]