Property definitions

nitc $ ActorPhase :: generate_actor_classes
	fun generate_actor_classes(mclassdef: MClassDef, mmod: MModule) do
		if not mmod.generate_actor_submodule then mmod.generate_actor_submodule = true

		# Get the name of the annotated class
		var classname = mclassdef.name

		# Generate the actor class
		if mclassdef.is_intro then actors.add(
"""
class Actor{{{classname}}}
	super Actor
	redef type E: nullable {{{classname}}}
end
""")
		######## Generate the Messages classes ########

		# Get all the methods definitions
		var propdefs = new Array[MPropDef]
		for propdef in mclassdef.mpropdefs do
			if propdef.is_intro then propdefs.add(propdef)
		end

		var methods = new Array[MMethodDef]
		for p in propdefs do
			if p isa MMethodDef then
				# TODO: find a better way to exclude constructors,
				# getters/setters and the "async" (the actor)
				if p.name.has("=") or p.name.has("async") or p.mproperty.is_init then continue
				methods.add(p)
			end
		end

		# Generate the superclass for all Messages classes (each actor has its own Message super class)
		var msg_class_name = "Message" + classname

		if mclassdef.is_intro then messages.add(
"""
class {{{msg_class_name}}}
	super Message
	redef type E: {{{classname}}}
end
""")
		# Generate every Message class based on the methods of the annotated class
		var proxy_calls = new Array[String]
		for m in methods do
			# Signature of the method
			var signature = m.msignature

			# Name of the method
			var method_name = m.name

			# Attributes of the `Message` class if needed
			# Corresponds to the parameters of the proxied method
			var msg_attributes = new Array[String]

			# Signature of the proxy corresponding method
			var proxy_sign = ""

			# Values for the body of the `invoke` method of the generated Message class
			# Used if the call must return a value
			var return_value = ""
			var return_parenthesis = ""

			# Params to send to `instance` in the `invoke` method
			var params = ""

			# Values for the generated proxy method
			var return_signature = ""
			var return_statement = ""

			if signature != null then
				var proxy_params= new Array[String]

				# Deal with parameters
				var mparameters = signature.mparameters
				if mparameters.length > 0 then
					var parameters = new Array[String]
					proxy_sign += "("
					for p in mparameters do
						var n = p.name
						var t = p.mtype.name
						msg_attributes.add("var " + n + ": " + t)
						proxy_params.add(n + ": " + t)
						parameters.add(n)
					end
					proxy_sign += proxy_params.join(", ") + ")"
					params = "(" + parameters.join(", ") + ")"
				end

				# Deal with the return if any
				var ret_type = signature.return_mtype
				if ret_type != null then
					msg_attributes.add("var ret = new Future[{ret_type.name}]")
					return_value = "ret.set_value("
					return_parenthesis = ")"
					return_signature = ": Future[{ret_type.name}]"
					return_statement = "return msg.ret"
				end
			end

			# Name of the Message class
			var name = classname + "Message" + method_name

			# The effective Message Class
			messages.add(
"""
class {{{name}}}
	super {{{msg_class_name}}}

	{{{msg_attributes.join("\n")}}}

	redef fun invoke(instance) do {{{return_value}}}instance.{{{method_name}}}{{{params}}}{{{return_parenthesis}}}
end
""")


			# The actual proxy call
			proxy_calls.add(
"""
redef fun {{{method_name}}}{{{proxy_sign}}}{{{return_signature}}} do
	var msg = new {{{name}}}{{{params}}}
	actor.mailbox.push(msg)
	{{{return_statement}}}
end
""")
		end

		# At this point, all msg classes should be good
		# All of the functions of the proxy too

		# Let's generate the proxy class then

		var redef_virtual_type = ""
		if mclassdef.is_intro then redef_virtual_type = "redef type E: Actor{classname}"
		proxys.add(
"""
redef class Proxy{{{classname}}}

	{{{redef_virtual_type}}}

	init proxy(base_class: {{{classname}}}) do
		actor = new Actor{{{classname}}}(base_class)
		actor.start
	end

	{{{proxy_calls.join("\n\n")}}}
end
""")

	if mclassdef.is_intro then redef_classes.add(
"""
redef class {{{classname}}}
	var m = new Mutex
	var lazy_proxy: Proxy{{{classname}}} is lazy do return new Proxy{{{classname}}}.proxy(self)

	redef fun async: Proxy{{{classname}}} do
		m.lock
		var p = lazy_proxy
		m.unlock
		return p
	end
end
""")

	end
src/frontend/actors_generation_phase.nit:40,2--204,4