Handle common special cases before doing the effective method invocation

This methods handle the == and != methods and the case of the null receiver. Note: a { is open in the generated C, that enclose and protect the effective method invocation. Client must not forget to close the } after them.

The value returned is the result of the common special cases. If not null, client must compile it with the result of their own effective method invocation.

If before_send can shortcut the whole message sending, a dummy if(0){ is generated to cancel the effective method invocation that will follow

TODO: find a better approach

Property definitions

nitc $ JavaCompilerVisitor :: before_send
	# Handle common special cases before doing the effective method invocation
	# This methods handle the `==` and `!=` methods and the case of the null receiver.
	# Note: a { is open in the generated C, that enclose and protect the effective method invocation.
	# Client must not forget to close the } after them.
	#
	# The value returned is the result of the common special cases.
	# If not null, client must compile it with the result of their own effective method invocation.
	#
	# If `before_send` can shortcut the whole message sending, a dummy `if(0){`
	# is generated to cancel the effective method invocation that will follow
	# TODO: find a better approach
	private fun before_send(res: nullable RuntimeVariable, mmethod: MMethodDef, arguments: Array[RuntimeVariable]) do
		var bool_type = compiler.mainmodule.bool_type
		var recv = arguments.first
		var consider_null = mmethod.name == "==" or mmethod.name == "!=" or mmethod.name == "is_same_instance"
		if recv.mcasttype isa MNullableType or recv.mcasttype isa MNullType then
			add("if ({recv} == null || {recv}.is_null()) \{")
			if mmethod.name == "==" or mmethod.name == "is_same_instance" then
				if res == null then res = new_var(bool_type)
				var arg = arguments[1]
				if arg.mcasttype isa MNullableType then
					add("{res} = ({arg} == null || {arg}.is_null());")
				else if arg.mcasttype isa MNullType then
					add("{res} = true; /* is null */")
				else
					add("{res} = false; /* {arg.inspect} cannot be null */")
				end
			else if mmethod.name == "!=" then
				if res == null then res = new_var(bool_type)
				# res = self.new_var(bool_type)
				var arg = arguments[1]
				if arg.mcasttype isa MNullableType then
					add("{res} = ({arg} != null && !{arg}.is_null());")
				else if arg.mcasttype isa MNullType then
					add("{res} = false; /* is null */")
				else
					add("{res} = true; /* {arg.inspect} cannot be null */")
				end
			else
				add_abort("Receiver is null")
				ret(null_instance)
			end
			add("\} else \{")
		else
			add "\{"
			add "/* recv ({recv}) cannot be null since it's a {recv.mcasttype}"
		end
		if consider_null then
			var arg = arguments[1]
			if arg.mcasttype isa MNullType then
				if res == null then res = new_var(bool_type)
				if mmethod.name == "!=" then
					add("{res} = true; /* arg is null and recv is not */")
				else # `==` and `is_same_instance`
					add("{res} = false; /* arg is null but recv is not */")
				end
				add("\}") # closes the null case
				add("if (false) \{") # what follow is useless, Javac will drop it
			end
		end
	end
src/compiler/java_compiler.nit:576,2--636,4