--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Injects model for the classes annotated with "is actor" so
+# that the later generated code can be properly used for compilation
+module actors_injection_phase
+
+import modelize_class
+intrude import modelize_property
+import parser_util
+
+redef class ModelBuilder
+ redef fun build_a_mclass(nmodule, nclassdef)
+ do
+ super
+
+ # Catch the wanted annotation
+ var at = nclassdef.get_single_annotation("actor", self)
+ if at == null then return
+
+ # Get context information
+ var mod = nmodule.mmodule
+ if mod == null then return
+ var mclass = nclassdef.mclass
+ if mclass == null then return
+ if mclass.intro_mmodule != mod then
+ error(at, "`actor` can only be used at introductions.")
+ return
+ end
+
+ var l = at.location
+
+ var injected_name = "Proxy"
+
+ # Create the actor class
+ var actor_class = new MClass(mod, injected_name + mclass.name, l, null, concrete_kind, public_visibility)
+ var actor_class_definition = new MClassDef(mod, actor_class.mclass_type, l)
+ actor_class_definition.set_supertypes([mod.object_type])
+ var proxy_classes = mclass.model.get_mclasses_by_name("Proxy")
+ assert proxy_classes != null
+ var proxy_class = proxy_classes.first
+ actor_class_definition.supertypes.add(proxy_class.mclass_type)
+
+ # Register it
+ mclass.actor = actor_class
+ end
+
+ redef fun build_properties(nclassdef)
+ do
+ if nclassdef.build_properties_is_done then return
+ super
+
+ # Get context information
+ var mclass = nclassdef.mclass
+ if mclass == null then return
+ var mclass_def = nclassdef.mclassdef
+ if mclass_def == null then return
+
+ var actor_mclass = mclass.actor
+ if actor_mclass == null then return
+ var actor_mclass_def = actor_mclass.mclassdefs.first
+
+ # Adds an `async` attribute in the worker class which is the actor class
+ if mclass_def.is_intro then
+ var async = new MMethod(mclass_def, "async", mclass.location, public_visibility)
+ var async_def = new MMethodDef(mclass_def, async, mclass.location)
+ async_def.msignature = new MSignature(new Array[MParameter], actor_mclass.mclass_type)
+ async_def.is_abstract = true
+ end
+
+ # For each introduced property
+ for method in mclass_def.mpropdefs do
+ if not method isa MMethodDef then continue
+ if not method.is_intro then continue
+ if method.name == "async" then continue
+
+ # Create a proxied method
+ var actor_method = new MMethod(actor_mclass_def, method.name, actor_mclass.location, method.mproperty.visibility)
+ var actor_method_def = new MMethodDef(actor_mclass_def, actor_method, actor_mclass.location)
+
+ # Get the signature of the method ( replacing the return value with a Future if there is one)
+ var signature = method.msignature
+ if signature != null then
+ var parameters = signature.mparameters
+ var s_return_type = signature.return_mtype
+ if s_return_type != null then
+ var future_mclasses = mclass_def.model.get_mclasses_by_name("Future")
+ assert future_mclasses != null
+ var future_mclass = future_mclasses.first
+ var return_type = future_mclass.get_mtype([s_return_type])
+ actor_method_def.msignature = new MSignature(parameters, return_type)
+ else
+ actor_method_def.msignature = new MSignature(parameters, null)
+ end
+ end
+ actor_method_def.is_abstract = true
+ end
+ end
+end
+
+redef class MClass
+ # Adding the actor class to a class annotated with "is actor"
+ var actor: nullable MClass = null
+end