diff scripts/dgen.rb @ 11:07194b026fa4

Added bindings to a couple of frameworks, new license + some other things
author Jacob Carlborg <doob@me.com>
date Sat, 01 Aug 2009 15:03:28 +0200
parents 27e00625790b
children 4f583f7e242e
line wrap: on
line diff
--- a/scripts/dgen.rb	Thu Jul 09 23:25:18 2009 +0200
+++ b/scripts/dgen.rb	Sat Aug 01 15:03:28 2009 +0200
@@ -182,13 +182,15 @@
 
 # This Struct represents a C/Objective-C header
 HeaderFile = Struct.new(:name, :framework, :cftypes, :constants, :c_constants, :d_constants, :d_constants_static_this, :defines, 
-			  			:enums, :functions, :c_functions, :function_pointers, :function_wrappers, :imports, :path, :structs, :typedefs) do
+			  			:enums, :enums_gnu, :needs_type_encoding, :functions, :c_functions, :function_pointers, :function_wrappers, :imports, :path, :structs, :typedefs) do
 	def initialize
 		self.name = ""
 		self.cftypes = []
 		self.constants = []
 		self.defines = []
 		self.enums = []
+		self.enums_gnu = []
+		self.needs_type_encoding = false
 		self.framework = ""
 		self.functions = []
 		self.c_functions = []
@@ -225,12 +227,19 @@
 		@c_functions = []
 		@headers = []
 		@package = "dstep"
+		@needs_bridge = false
 	end	
 	
 	# Generates the D code from the xml metadata
 	def generate_code
 		@files.each do |dstep_file|
 			xml = XmlSimple.xml_in(dstep_file)
+			
+			@needs_bridge = !xml.protocol.nil? || !xml.category.nil? || !xml["class"].nil?
+			
+			interfaces(xml.protocol) unless xml.protocol.nil?
+			templates(xml.category) unless xml.category.nil?
+			classes(xml["class"]) unless xml["class"].nil?
 
 			unless xml.framework.nil?
 				frameworks = xml.framework
@@ -246,12 +255,12 @@
 						header.c_constants = c_constants unless file.constant.nil?
 						header.d_constants = d_constants unless file.constant.nil?
 						header.d_constants_static_this = d_constants_static_this unless file.constant.nil?
-						header.enums = enums(file.enum) unless file.enum.nil?
+						header.enums, header.enums_gnu, header.needs_type_encoding = enums(file.enum, header.name) unless file.enum.nil?
 						header.functions = functions(file.function) unless file.function.nil?
 						header.c_functions = c_functions unless file.function.nil?
 						header.function_pointers = function_pointers(file.functionPointer) unless file.functionPointer.nil?
 						header.function_wrappers = function_wrappers unless file.function.nil?
-						header.imports = imports(file.import, file.name, framework.name) unless file.import.nil?
+						header.imports = imports(header, file.import, file.name, framework.name) unless file.import.nil?
 						header.structs = structs(file.struct) unless file.struct.nil?
 
 						header.typedefs = typedefs(file.typedef) unless file.typedef.nil?
@@ -273,29 +282,26 @@
 					header.c_constants = c_constants unless file.constant.nil?
 					header.d_constants = d_constants unless file.constant.nil?
 					header.d_constants_static_this = d_constants_static_this unless file.constant.nil?
-					header.enums = enums(file.enum) unless file.enum.nil?
+					header.enums, header.enums_gnu, header.needs_type_encoding = enums(file.enum) unless file.enum.nil?
 					header.functions = functions(file.function) unless file.function.nil?
 					header.function_pointers = function_pointers(file.functionPointer) unless file.functionPointer.nil?
 					header.c_functions = c_functions unless file.function.nil?
 					header.function_wrappers = function_wrappers unless file.function.nil?
-					header.imports = imports(file.import, file.name) unless file.import.nil?
+					header.imports = imports(header, file.import, file.name) unless file.import.nil?
 					header.structs = structs(file.struct) unless file.struct.nil?
 					header.typedefs = typedefs(file.typedef) unless file.typedef.nil?
 
 					@headers << header
 				end
-			end
-			
-			interfaces(xml.protocol) unless xml.protocol.nil?
-			templates(xml.category) unless xml.category.nil?
-			classes(xml["class"]) unless xml["class"].nil?						
+			end					
 		end
 	end
 	
 	# Outputs the generate D code
 	def output_code
 		@frameworks.each do |framework|
-			framework_path = framework_path = "#{@out_dir}/#{@package}/#{get_identifier(get_framework_name(framework.name.downcase))}"
+			framework_path = framework_path = "#{@out_dir}/#{@package}/#{get_identifier(get_framework_name(framework.name.downcase))}" unless sub_framework?(framework.name.downcase)
+			framework_path = framework_path = "#{@out_dir}/#{@package}/#{get_identifier(get_parent_framework_name(framework.name.downcase))}/#{get_identifier(get_framework_name(framework.name.downcase))}" if sub_framework?(framework.name.downcase)
 			
 			FileUtils.mkdir_p(framework_path) unless File.exist?(framework_path)
 			
@@ -303,13 +309,13 @@
 				file_path = "#{framework_path}/#{get_identifier(header.name)}"
 				bindings_file_path = file_path + "_bindings.d"
 				file_path << ".d"
-				mod = "#{@package}.#{get_identifier(get_framework_name(framework.name.downcase))}.#{get_identifier(header.name)}"
+				mod = "#{@package}.#{get_identifier(get_framework_name(framework.name.downcase))}.#{get_identifier(header.name)}" unless sub_framework?(framework.name.downcase)
+				mod = "#{@package}.#{get_identifier(get_parent_framework_name(framework.name.downcase))}.#{get_identifier(get_framework_name(framework.name.downcase))}.#{get_identifier(header.name)}" if sub_framework?(framework.name.downcase)
 				
 				File.open(file_path, "w") do |file|
 					file << copyright
 					file << "module #{mod};"
 					file << header.imports
-					file << "\n" if header.d_constants.nil? || header.function_wrappers.nil?
 					file << "import bindings = #{mod}_bindings".nl.nl(false) unless header.d_constants.nil? || header.function_wrappers.nil?
 					file << header.defines
 					file << header.typedefs
@@ -317,6 +323,7 @@
 					file << header.function_pointers
 					file << header.c_constants
 					file << header.d_constants
+					file << header.enums_gnu if header.needs_type_encoding
 					file << header.enums
 					file << header.structs
 					
@@ -376,7 +383,6 @@
 				file << copyright
 				file << "module #{mod};"
 				file << header.imports
-				file << "\n" if header.d_constants.nil? || header.function_wrappers.nil?
 				file << "import bindings = #{mod}_bindings".nl.nl(false) unless header.d_constants.nil? || header.function_wrappers.nil?
 				file << header.defines
 				file << header.typedefs
@@ -384,6 +390,7 @@
 				file << header.function_pointers
 				file << header.c_constants
 				file << header.d_constants
+				file << header.enums_gnu if header.needs_type_encoding
 				file << header.enums
 				file << header.structs
 				
@@ -754,42 +761,108 @@
 	end	
 	
 	# Generates the D code for the enums
-	def enums (enums)
+	def enums (enums, header_name)
 		return "" if enums.length == 0
 		
 		str = StringIO.new
+		str_gnu = StringIO.new
+		consts = []
 		
 		enums.each do |enum|
+			localConsts = []
+			str_gnu2 = StringIO.new
 			str << "enum"
-								
+			needs_type_encoding = false
+					
 			if enum.name.length == 0
 				str << "\n{".nl(false)
 				
-				enum.member.each_with_index do |member, i|
-					str << get_identifier(member["name"]).indent
-					str << " = " if member.value.length > 0
-					str << member.value
-					str << ",".nl(false) unless i == enum.member.length - 1
-				end				
+				needs_type_encoding, localConsts = enum_helper(enum, str, str_gnu2, header_name)			
 			else
 				str << " "
 				str << get_identifier(enum["name"]).nl(false)
 				str << "{".nl(false)
 				
-				enum["member"].each_with_index do |member, i|
-					str << get_identifier(member["name"]).indent
-					str << " = " if member.value.length > 0
+				needs_type_encoding, localConsts = enum_helper(enum, str, str_gnu2, header_name)
+			end			
+			
+			str << "\n}".nl(false).nl(false)
+			
+			# if needs_type_encoding
+			# 	str_gnu << "// This is needed otherwise the enums will fail compiling with gdc\n"
+			# 	str_gnu << "version (GNU)\n{\n"
+			# 	str_gnu << "private\n".indent
+			# 	str_gnu << "{\n".indent
+			# 	str_gnu << str_gnu2.string				
+			# 	str_gnu << "\n"
+			# 	str_gnu << "}".indent
+			# 	str_gnu << "\n}".nl(false).nl(false)
+			# end
+			
+			consts << localConsts 
+		end
+		
+		consts.flatten!
+		
+		if @needs_type_encoding && consts.length > 0
+			str_gnu << "// This is needed otherwise the enums will fail compiling with gdc\n"
+			str_gnu << "version (GNU)\n{\n"
+			str_gnu << "private\n".indent
+			str_gnu << "{\n".indent
+			
+			consts.each do |const|
+				str_gnu << "const __".indent(2)
+				str_gnu << const.name
+				str_gnu << ' = getOSType!("'
+				str_gnu << const.value
+				str_gnu << '")'.nl
+			end
+			
+			str_gnu << "}".indent
+			str_gnu << "\n}".nl(false).nl(false)
+		end
+		
+		needs_type_encoding = @needs_type_encoding
+		@needs_type_encoding = false
+		
+		return str.string, str_gnu.string, needs_type_encoding
+	end
+	
+	def enum_helper (enum, str, str_gnu, header_name)	
+		needs_type_encoding = false
+		consts = []
+			
+		enum.member.each_with_index do |member, i|
+			str << get_identifier(member.name).indent			
+			
+			if member.value.length > 0
+				needs_type_encoding = true if member.value[0, 1] == "'"
+				@needs_type_encoding = true if needs_type_encoding
+				str << " = "	
+				
+				if member.value[0, 1] == "'"					
+					str << 'getOSType!("'
+					str << member.value[1 ... -1]
+					str << '")'
+					
+					consts << { :name => get_identifier(member.name), :value => member.value[1 ... -1] }
+					# str_gnu << "const __".indent(2)
+					# str_gnu << get_identifier(member.name)
+					# str_gnu << " = "					
+					# str_gnu << 'getOSType!("'
+					# str_gnu << member.value[1 ... -1]
+					# str_gnu << '")'.nl
+				else
 					str << member.value
-					str << ",".nl(false) unless i == enum.member.length - 1
 				end
 			end
 			
-			str << "\n}".nl(false).nl(false)
+			str << ",".nl(false) unless i == enum.member.length - 1
 		end
 		
-		str.string
+		return needs_type_encoding, consts
 	end
-	
+		
 	# Generates the D code for the function/method args
 	def args (args, variadic, method = false)
 		return "" if args.nil?
@@ -975,7 +1048,7 @@
 	end
 	
 	# Generates the D code for the imports
-	def imports (imports, filename, framework_name = nil)
+	def imports (header, imports, filename, framework_name = nil)
 		return "" if imports.length == 0
 		
 		str = StringIO.new
@@ -996,13 +1069,19 @@
 			str << splits[-1 .. -1]
 		end
 		
-		str << "import dstep.objc.bridge.Bridge".nl
-		str << "import dstep.objc.objc : id".nl
+		str << "import dstep.objc.bridge.TypeEncoding".nl if header.needs_type_encoding && !@needs_bridge
+		
+		if @needs_bridge
+			str << "import dstep.objc.bridge.Bridge".nl
+			str << "import dstep.objc.bridge.TypeEncoding".nl if header.needs_type_encoding
+			str << "import dstep.objc.objc : id".nl
+		end
 		
 		str << "\n\n"
-		str = str.string.sort.to_s		
+		str = str.string.sort.to_s
+		str << "\n"
 		
-		return "\n\npublic:" << str if filename == framework_name
+		return "\n\npublic:" << str if filename == get_framework_name(framework_name)
 		return str
 	end
 	
@@ -1121,13 +1200,24 @@
 				type = get_type(typedef.type, typedef.type64, typedef.declaredType)
 			end
 			
-			if struct
-				str << typedef.declaredType.gsub("*", "").nl
-				str << "alias "				
-				str << get_identifier(type.name)
-				str << "*" if typedef.declaredType =~ /\*/
-				str << " "
-				str << get_identifier(typedef.name).nl
+			if struct				
+				unless type.name == typedef.name
+					declaredType = typedef.declaredType
+					declaredType = declaredType[7 .. -1] if declaredType.length > 7 && declaredType[0 ... 6] == "struct"
+					
+					unless declaredType == typedef.name
+						str << "alias "
+						str << get_identifier(declaredType)
+						str << " "
+						str << get_identifier(typedef.name).nl
+					end
+					
+					# str << "alias "				
+					# str << get_identifier(type.name)
+					# str << "*" if typedef.declaredType =~ /\*{1}/
+					# str << " "
+					# str << get_identifier(typedef.name).nl
+				end
 			else
 				str << "alias "
 				str << type
@@ -1186,6 +1276,18 @@
 		get_identifier(selector[0 ... i])
 	end
 	
+	def get_matching_close_char (char)
+		case char
+		when "{"; return "}"
+		when "("; return ")"
+		when "["; return "]"
+		else
+			char
+		end
+	end
+	
+	
+	
 	# Gets the D type from the encoded C/Objective-C type
 	# type:: the type
 	# type64:: the type for 64bit targets
@@ -1243,9 +1345,15 @@
 				count = $1 if t =~ /(\d+)/				
 				t = $'
 				
-				t64 = type64[1 ... -1]
-				count = $1 if t64 =~ /(\d+)/				
-				t64 = $'
+				t64 = ""
+				
+				unless type64.nil?
+					t64 = type64[1 ... -1]
+					count = $1 if t64 =~ /(\d+)/				
+					t64 = $'
+				else
+					t64 = t
+				end
 				
 				str = get_type(t, t64, declared_type)
 				str << "[#{count}]"
@@ -1255,33 +1363,51 @@
 				resolved_types = []
 				types = $2 if type =~ /\((.+)=(.+)\)/
 				types64 = $2 if type64 =~ /\((.+)=(.+)\)/
+				i = 0
 				
-				for i in types
-					resolved_types << get_type(types[i], types64[i], declared_type)
-				end
+				while i < types.length
+					t = types[i, 1]
+					t64 = types64.nil? ? t : types64[i, 1]
+					
+					index = t =~ /(\(|\[|\{)/
+					
+					unless index.nil?
+						x = types.index(get_matching_close_char($1), index)
+						t = types[index .. x]
+						t64 = types64.nil? ? t : types64[index .. x]
+						i += x - index
+					end
+						
+					resolved_types << get_type(t, t64, declared_type)
+					i += 1			
+				end unless types.nil?
 				
-				return get_identifier(resolved_types)
-			when "^"	
-				if type == "^@"
-					return get_identifier(get_type(type[1 .. -1], type64[1 .. -1], declared_type).dup + "*")
-				elsif type.length > 2 && type[0 ... 2] == "^^"
-					return get_identifier(get_type(type[2 .. -1], type64[2 .. -1], declared_type).dup + "**")
-				elsif type == "^?" # assuming function pointer
-					tmp = cfp_to_dfp(type)
-					return get_identifier(tmp) unless tmp.nil?
-				end
+				get_identifier(resolved_types)
+			when "^"
+				t = type[1 .. -1]
+				t64 = type64.nil? ? t : type64[1 .. -1]
+				get_identifier(get_type(t, t64, declared_type).dup + "*")
 				
-				if !type.nil? && !type64.nil?
-					t = get_type(type[1 .. -1], type64[1 .. -1], declared_type).dup
-					
-					return get_identifier(t) if t =~ /\*/
-					return get_identifier(t + "*") if t !~ /\*/
-				elsif !type.nil?
-					t = get_type(type[1 .. -1], type64, declared_type).dup << "*"
-					
-					return get_identifier(t) if t =~ /\*/
-					return get_identifier(t + "*") if t !~ /\*/
-				end			
+				# if type == "^@"
+				# 	return get_identifier(get_type(type[1 .. -1], type64[1 .. -1], declared_type).dup + "*")
+				# elsif type.length > 2 && type[0 ... 2] == "^^"
+				# 	return get_identifier(get_type(type[2 .. -1], type64[2 .. -1], declared_type).dup + "**")
+				# elsif type == "^?" # assuming function pointer
+				# 	tmp = cfp_to_dfp(type)
+				# 	return get_identifier(tmp) unless tmp.nil?
+				# end
+				# 
+				# if !type.nil? && !type64.nil?
+				# 	t = get_type(type[1 .. -1], type64[1 .. -1], declared_type).dup
+				# 	
+				# 	return get_identifier(t) if t =~ /\*/
+				# 	return get_identifier(t + "*") if t !~ /\*/
+				# elsif !type.nil?
+				# 	t = get_type(type[1 .. -1], type64, declared_type).dup << "*"
+				# 	
+				# 	return get_identifier(t) if t =~ /\*/
+				# 	return get_identifier(t + "*") if t !~ /\*/
+				# end			
 			when "{"
 				return get_identifier(declared_type)
 			end
@@ -1521,6 +1647,22 @@
 		x = framework.rindex("/", i)
 		framework[x + 1 ... i]
 	end
+	
+	def sub_framework? (framework)
+		i = framework.index("framework")
+		return false if i.nil?
+		!framework.index("framework", i + 1).nil?
+	end
+	
+	def get_parent_framework_name (framework)
+		return get_framework_name(framework) unless sub_framework?(framework)
+		i = framework.index(".framework")
+		return framework if i.nil?
+		str = framework[0 ... i]
+		x = str.rindex("/")
+		return str if x.nil?
+		str[x + 1 .. -1]
+	end	
 end
 
 # Prints the message to stderr, exits