diff scripts/dgen.rb @ 16:19885b43130e

Huge update, the bridge actually works now
author Jacob Carlborg <doob@me.com>
date Sun, 03 Jan 2010 22:06:11 +0100
parents 7ff919f595d5
children
line wrap: on
line diff
--- a/scripts/dgen.rb	Mon Aug 03 15:31:48 2009 +0200
+++ b/scripts/dgen.rb	Sun Jan 03 22:06:11 2010 +0100
@@ -12,6 +12,7 @@
 require "xmlsimple"
 require "optparse"
 require "date"
+require "stringio"
 
 # Extensions to String
 class String	
@@ -323,15 +324,17 @@
 					file << header.function_pointers
 					file << header.c_constants
 					file << header.d_constants
+					file << header.d_constants_static_this unless header.d_constants_static_this.length == 0
 					file << header.enums_gnu if header.needs_type_encoding
 					file << header.enums
 					file << header.structs
 					
-					unless header.d_constants_static_this.length == 0
-						file << "static this ()".nl(false)
-						file << "{".nl(false)
-						file << header.d_constants_static_this
-						file << "}".nl(false).nl(false)
+					# Put the templates/mixins before the classes just to make sure we don't get forward reference errors
+					templates = get_templates(header.name)
+					
+					templates.each do |template, value|
+						file << value.code.nl(false)
+						@templates.delete(template)
 					end
 					
 					classes = get_classes(header.name)
@@ -348,18 +351,12 @@
 						@interfaces.delete(interface)
 					end
 					
-					templates = get_templates(header.name)
-					
-					templates.each do |template, value|
-						file << value.code.nl(false)
-						@templates.delete(template)
-					end
-					
 					file << header.function_wrappers
 					file << header.c_functions							
 				end
 				
 				File.open(bindings_file_path, "w") do |file|
+					file << copyright
 					file << "module "
 					file << mod
 					file << "_bindings;"
@@ -390,15 +387,17 @@
 				file << header.function_pointers
 				file << header.c_constants
 				file << header.d_constants
+				file << header.d_constants_static_this unless header.d_constants_static_this.nil?
 				file << header.enums_gnu if header.needs_type_encoding
 				file << header.enums
 				file << header.structs
 				
-				unless header.d_constants_static_this.nil?
-					file << "static this ()".nl(false)
-					file << "{".nl(false)
-					file << header.d_constants_static_this
-					file << "}".nl(false).nl(false)
+				# Put the templates/mixins before the classes just to make sure we don't get forward reference errors
+				templates = get_templates(header.name)
+				
+				templates.each do |template, value|
+					file << value.code.nl(false)
+					@templates.delete(template)
 				end
 				
 				classes = get_classes(header.name)
@@ -414,13 +413,6 @@
 					file << value.code.nl(false)
 					@interfaces.delete(interface)
 				end
-				
-				templates = get_templates(header.name)
-				
-				templates.each do |template, value|
-					file << value.code.nl(false)
-					@templates.delete(template)
-				end
 
 				file << header.function_wrappers
 				file << header.c_functions	
@@ -548,12 +540,7 @@
 			end			
 			
 			str << "{".nl(false)
-			str << "mixin ObjcWrap".indent.nl
-			
-			templates_for_class(clazz.name).each do |template, value|
-				str << "mixin #{get_identifier("T" + template)}".indent.nl
-			end
-			
+			str << "mixin (ObjcWrap)".indent.nl			
 			str << "\n"
 
 			str << methods(clazz.method, clazz.name)
@@ -567,7 +554,12 @@
 					str << methods(interface.method, interface.name)
 					str << "\n" unless i == protocols.length - 1
 				end
-			end			
+			end
+			
+			# Put the mixins at the end of the class just to make sure we don't get any forward reference errors
+			templates_for_class(clazz.name).each do |template, value|
+				str << "mixin (#{get_identifier("T" + template)})".indent.nl
+			end	
 			
 			str << "}".nl(false)
 			
@@ -633,15 +625,20 @@
 	# Generates the D code for the templates
 	def templates (templates)
 		templates.each do |template|
+			methods = methods(template.method, template.name, true) #unless template["class"] == "NSObject"
+			bindings = bindings(template)		
+			
 			str = StringIO.new
 
-			str << "template "			
+			str << "const "			
 			str << get_identifier("T" + template.name)
-			str << " ()".nl(false)
-			str << "{".nl(false)
-			str << interface_methods(template.method, template.name) if template["class"] == "NSObject"
-			str << methods(template.method, template.name) unless template["class"] == "NSObject"
-			str << "}".nl(false)
+			str << " = `".nl(false)
+			str << "".nl(false)
+			#str << interface_methods(template.method, template.name) if template["class"] == "NSObject"
+
+			str << methods.nl(false)
+			str << bindings.nl(false)
+			str << "`".nl
 
 			@templates[template.name] ||= {}
 			@templates[template.name].code = str.string
@@ -652,6 +649,23 @@
 		end
 	end
 	
+	def bindings (template)
+		str = StringIO.new
+		
+		template.method.each do |method|
+			static = method.classMethod == "true"
+			
+			str << "mixin ObjcBindMethod!(".indent unless static
+			str << "mixin ObjcBindClassMethod!(".indent if static 
+			str << get_method_name(method.selector)
+			str << ', "'
+			str << method.selector
+			str << '")'.nl
+		end
+		
+		str.string	
+	end
+	
 	# Generates the D code for the constants/globals
 	def constants (constants)
 		return "" if constants.length == 0
@@ -722,20 +736,23 @@
 			
 		str = StringIO.new
 		
+		str << "private\n{\n"
+		
 		@d_constants.each do |constant|
 			# Deep copy constant
 			c = constant.dup
 			c.name = c.name.dup
 			c.type = c.type.dup
 			
-			str << "const " if constant.const
-			str << get_identifier(constant.type)
+			#str << "const " if constant.const
+			str << get_identifier(constant.type).indent
 			str << " "			
-			str << get_identifier(constant.name).nl
+			str << get_identifier(constant.name)
+			str << "_".nl
 			@d_constants_static_this << c
 		end
 		
-		str << "\n"
+		str << "}\n\n"
 		@d_constants.clear
 		str.string
 	end
@@ -747,13 +764,34 @@
 		str = StringIO.new
 		
 		@d_constants_static_this.each do |constant|
-			str << constant.name.indent
-			str << " = new "
-			str << get_identifier(constant.type)
-			str << "("
-			str << "bindings."
-			str << get_identifier(constant.name)
+			# str << constant.name.indent
+			# str << " = new "
+			# str << get_identifier(constant.type)
+			# str << "("
+			# str << "bindings."
+			# str << get_identifier(constant.name)
+			# str << ")".nl
+			
+			str << constant.type
+			str << " "
+			str << constant.name
+			str << " ()".nl(false)
+			str << "{".nl(false)
+			str << "if (".indent
+			str << constant.name + "_"
+			str << ")".nl(false)
+			str << "return ".indent(2)
+			str << constant.name
+			str << "_".nl
+			str << "\n"
+			str << "return ".indent
+			str << constant.name
+			str << "_ = new "
+			str << constant.type
+			str << "(bindings."
+			str << constant.name
 			str << ")".nl
+			str << "}\n\n"
 		end
 		
 		@d_constants_static_this.clear
@@ -906,7 +944,7 @@
 		else
 			return_type = get_type(original_type, function.returnValue[0].type64, function.returnValue[0].declaredType)
 			args(function.arg, variadic) unless function.arg.nil?
-		end
+		end	
 		
 		str << "static " if static
 		str << return_type
@@ -999,7 +1037,7 @@
 	def functions_helper (function, wrapper_needed)
 		str = StringIO.new
 		
-		str << ("private " + build_function(function)).indent if wrapper_needed
+		str << ("package " + build_function(function)).indent if wrapper_needed
 		str << build_function(function).indent unless wrapper_needed
 
 		str.string
@@ -1074,7 +1112,7 @@
 		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
+			str << "import dstep.objc.objc".nl
 		end
 		
 		str << "\n\n"
@@ -1086,32 +1124,77 @@
 	end
 	
 	# Generates the D code for the methods
-	def methods (methods, class_name)
+	def methods (methods, class_name, template = false)
 		return "" if methods.length == 0
 		
 		str = StringIO.new
 		
-		methods.each do |method|				
+		methods.each do |method|
+			next if method.selector.length >= 5 && get_method_name(method.selector)[0 ... 5] == "alloc" # skip alloc
+			
+			name = get_method_name(method.selector)
 			return_type = get_type(method.returnValue[0].type, method.returnValue[0].type64, method.returnValue[0].declaredType)
+			
+			if name.length >= 4 && name[0 ... 4] == "init" && name != "initialize"
+				if template
+					return_type = "typeof(this)"
+				else
+					return_type = class_name 
+				end
+				
+				method["returnValue"][0]["declaredType"] = return_type
+			end
+			
 			variadic = method.variadic == "true"
 			static = method.classMethod == "true"
 			
 			index = 0
 			declaration = build_function(method, true, static)[0 ... -2].indent.nl(false)
 			index = declaration.index_of(" ") if static
-			index = declaration.index_of(" ", index)
-			name = get_method_name(method.selector)
+			index = declaration.index_of(" ", index)		
 			
 			str << (declaration[0 .. index] + name + declaration[index .. -1]).gsub(/ +/, " ")
 			str << "{".indent.nl(false)
 			
+			has_ref = false
+			
+			method.arg.each_with_index do |arg, i|
+				if arg.declaredType =~ /NSError\*\*/ || arg.declaredType =~ /NSDictionary\*\*/
+					has_ref = true
+					str << "id __arg#{i};\n".indent(2)
+				end
+			end if method.arg
+			
+			if has_ref
+				str << "\n"
+				
+				method.arg.each_with_index do |arg, i|
+					if arg.declaredType =~ /NSError\*\*/ || arg.declaredType =~ /NSDictionary\*\*/
+						str << "if (#{arg.name})\n".indent(2)
+						str <<  "__arg#{i} = #{arg.name}.objcObject".indent(3).nl.nl(false)
+					end
+				end if method.arg
+			end
+			
 			if static
-				str << "return invokeObjcSelfClass!(".indent(2)
-				str << return_type
+				if has_ref
+					str << "#{return_type} result = ".indent(2) unless return_type == "void"
+					str << "".indent(2) if return_type == "void"
+					str << "invokeObjcSelf!("
+					str << return_type
+				else
+					str << "return invokeObjcSelfClass!(".indent(2)
+					str << return_type
+				end
 			else
 				if return_type == class_name
 					str << "id result = invokeObjcSelf!(".indent(2)
 					str << "id"
+				elsif has_ref
+					str << "#{return_type} result = ".indent(2) unless return_type == "void"
+					str << "".indent(2) if return_type == "void"
+					str << "invokeObjcSelf!("
+					str << return_type
 				else
 					str << "return invokeObjcSelf!(".indent(2)
 					str << return_type
@@ -1124,7 +1207,12 @@
 			
 			method.arg.each do |arg|
 				str << ", "
-				str << get_type(arg.type, arg.type, arg.declaredType)
+				
+				if arg.declaredType =~ /NSError\*\*/ || arg.declaredType =~ /NSDictionary\*\*/
+					str << "id*"
+				else
+					str << get_type(arg.type, arg.type, arg.declaredType)
+				end
 			end unless method.arg.nil?
 			
 			unless method.arg.nil?
@@ -1133,39 +1221,65 @@
 			end
 			
 			method.arg.each_with_index do |arg, i|
-				str << get_identifier(arg.name)
+				if arg.declaredType =~ /NSError\*\*/ || arg.declaredType =~ /NSDictionary\*\*/
+					str << "&__arg#{i}"
+				else
+					str << get_identifier(arg.name)
+				end
+				
 				str << ", " unless i == method.arg.length - 1
 			end unless method.arg.nil?			
 			
 			str << ")".nl
-			str << "return result is this.objcObject ? this : (result !is null ? new #{return_type}(result) : null)".indent(2).nl if return_type == class_name && !static
+			
+			if has_ref
+				str << "\n"
+				
+				method.arg.each_with_index do |arg, i|
+					if arg.declaredType =~ /NSError\*\*/ || arg.declaredType =~ /NSDictionary\*\*/
+						str << "if (__arg#{i})\n".indent(2)
+						argType = get_type(arg.type, arg.type64, arg.declaredType)
+						argType = argType[4 .. -1] # cut off "ref "
+						str << "#{arg.name} = new #{argType}(__arg#{i})".indent(3).nl
+					end
+				end				
+				
+				unless return_type == "void" || return_type == class_name || return_type == "typeof(this)" 
+					str << "\n"
+					str << "return result".indent(2).nl 
+				end
+			end
+			
+			if (return_type == class_name || return_type == "typeof(this)") && !static
+				str << "\n"
+				str << "return result is this.objcObject ? this : (result !is null ? new #{return_type}(result) : null)".indent(2).nl
+			end
+			
 			str << "}".indent.nl(false).nl(false)
 			
 			if name.length >= 4 && name[0 ... 4] == "init" && name != "initialize"
 				str << ("this" + declaration[index .. -1]).gsub(/ +/, " ").indent
 				str << "{".indent.nl(false)
-				str << 'objcObject = Bridge.invokeObjcClassMethod!(id, "alloc")(objcClass)'.indent(2).nl
-				str << 'id result = Bridge.invokeObjcMethod!(id, "'.indent(2)
-				str << method.selector
-				str << '"'
-				
-				method.arg.each do |arg|
-					str << ", "
-					str << get_type(arg.type, arg.type, arg.declaredType)
-				end unless method.arg.nil?
+				str << "super(".indent(2)
+				str << typeof(this) if template
+				str << class_name unless template
+				str << ".alloc."
+				str << get_method_name(method.selector)			
 				
-				str << ")(objcObject"
+				unless method.arg.nil?
+					str << "("
+					args = StringIO.new				
+
+					method.arg.each do |arg|
+						args << get_identifier(arg.name)
+						args << ", "
+					end
+					
+					str << args.string[0 ... -2]
+					str << ")"
+				end
 				
-				method.arg.each do |arg|
-					str << ", "
-					str << get_identifier(arg.name)
-				end unless method.arg.nil?
-				
-				str << ")".nl.nl(false)
-				
-				str << "if (result)".indent(2).nl(false)
-				str << "objcObject = ret".indent(3).nl.nl(false)
-				str << "dObject = this".indent(2).nl
+				str << ".objcObject)".nl
 				str << "}".indent.nl(false).nl(false)
 			end
 		end
@@ -1287,6 +1401,7 @@
 			when "NSInteger"; return type
 			when "NSUInteger"; return type
 			when "IMP"; return type;
+			when "size_t"; return type;
 				
 			when "unichar*"
 			when "UniChar*"; return "wchar*"
@@ -1294,6 +1409,7 @@
 			when "CGFloat*"; return type
 			when "NSInteger*"; return type
 			when "NSUInteger*"; return type
+			when "size_t*"; return type;
 				
 			when "unichar**"
 			when "UniChar**"; return "wchar**"
@@ -1301,7 +1417,14 @@
 			when "CGFloat**"; return type
 			when "NSInteger**"; return type
 			when "NSUInteger**"; return type
-			else return nil;
+			when "size_t**"; return type;
+				
+			# special case, asume ref parameter
+			when "NSError**"; return "ref NSError"
+			when "NSDictionary**"; return "ref NSDictionary"
+			when "typeof(this)"; return type
+		else 
+			return nil;
 		end
 	end
 	
@@ -1338,13 +1461,13 @@
 	# get_type("I", "I", "unsigned int")    #=> uint
 	#
 	def get_type (type, type64, declared_type)
+		t = check_declared_type(declared_type)
+		return t unless t.nil?
+		
 		declared_type = "I" + $1 if declared_type =~ /\w+\s*<(.+)>/
 		declared_type.gsub!(/\(|\)/, "")
 				
 		return get_identifier(declared_type) if type.nil? && type64.nil?
-			
-		t = check_declared_type(declared_type)
-		return t unless t.nil?
 		
 		unless type64 == "" || type64.nil?
 			return get_identifier(declared_type) if type != type64
@@ -1424,9 +1547,21 @@
 				
 				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 == "^@"
+					t = type[1 .. -1]
+					t64 = type64.nil? ? t : type64[1 .. -1]
+					get_identifier(get_type(t, t64, "ref " + declared_type).dup)
+				
+				elsif type == "^?"
+					tmp = cfp_to_dfp(type)
+					return get_identifier(tmp) unless tmp.nil?
+				end
+				# t = type[1 .. -1]
+				# t64 = type64.nil? ? t : type64[1 .. -1]
+				# get_identifier(get_type(t, t64, declared_type).dup + "*")
+				
+				
+				
 				
 				# if type == "^@"
 				# 	return get_identifier(get_type(type[1 .. -1], type64[1 .. -1], declared_type).dup + "*")