src: cleanup importations
[nit.git] / src / serialization_phase.nit
index c06a74d..25574e7 100644 (file)
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-# Phase generating methods to 
+# Phase generating methods to serialize Nit objects to different formats
 module serialization_phase
 
-import phase
-import parser_util
+private import parser_util
+import modelize
+private import annotation
 
 redef class ToolContext
-       var serialization_phase: Phase = new SerializationPhase(self, null)
+       var serialization_phase_pre_model: Phase = new SerializationPhasePreModel(self, null)
+       var serialization_phase_post_model: Phase = new SerializationPhasePostModel(self,
+               [modelize_class_phase, serialization_phase_pre_model])
+
+       private fun place_holder_type_name: String do return "PlaceHolderTypeWhichShouldNotExist"
 end
 
-# TODO automaticaly add Serializable as a super class
-# TODO Sequences
 # TODO add annotations on attributes (volatile, sensitive or do_not_serialize?)
-private class SerializationPhase
+private class SerializationPhasePreModel
        super Phase
 
        redef fun process_annotated_node(nclassdef, nat)
@@ -41,6 +44,11 @@ private class SerializationPhase
                        return
                end
 
+               # Add `super Serializable`
+               var sc = toolcontext.parse_superclass("Serializable")
+               sc.location = nat.location
+               nclassdef.n_superclasses.add sc
+
                generate_serialization_method(nclassdef)
 
                generate_deserialization_init(nclassdef)
@@ -48,11 +56,14 @@ private class SerializationPhase
 
        redef fun process_nmodule(nmodule)
        do
+               # Clear the cache of constructors to review before adding to it
+               nmodule.inits_to_retype.clear
+
                # collect all classes
                var auto_serializable_nclassdefs = new Array[AStdClassdef]
                for nclassdef in nmodule.n_classdefs do
                        if nclassdef isa AStdClassdef and
-                          not nclassdef.collect_annotations_by_name("auto_serializable").is_empty then
+                          not nclassdef.get_annotations("auto_serializable").is_empty then
                                auto_serializable_nclassdefs.add nclassdef
                        end
                end
@@ -93,20 +104,27 @@ private class SerializationPhase
                code.add "      v.notify_of_creation self"
 
                for attribute in npropdefs do if attribute isa AAttrPropdef then
-                       if attribute.n_type == null then
-                               toolcontext.error(attribute.location, "NOT YET IMPLEMENTED: all attributes of an auto_serialized class definition must define a type.")
-                               continue
+                       var n_type = attribute.n_type
+                       var type_name
+                       if n_type == null then
+                               # Use a place holder, we will replace it with the infered type after the model phases
+                               type_name = toolcontext.place_holder_type_name
+                       else
+                               type_name = n_type.type_name
                        end
                        var name = attribute.name
-                       var type_name = attribute.type_name
+
                        code.add ""
                        code.add "\tvar {name} = v.deserialize_attribute(\"{name}\")"
-                       code.add "\tassert {name} isa {type_name} else print \"Expected attribute '{name}' to be of type '{type_name}'\""
+                       code.add "\tassert {name} isa {type_name} else print \"Unsupported type for attribute '{name}', got '\{{name}.class_name\}' (ex {type_name})\""
                        code.add "\tself.{name} = {name}"
                end
 
                code.add "end"
-               npropdefs.add(toolcontext.parse_propdef(code.join("\n")))
+
+               var npropdef = toolcontext.parse_propdef(code.join("\n")).as(AConcreteInitPropdef)
+               npropdefs.add npropdef
+               nclassdef.parent.as(AModule).inits_to_retype.add npropdef
        end
 
        # Added to the abstract serialization service
@@ -129,13 +147,13 @@ private class SerializationPhase
                        code.add "      redef fun deserialize_class(name)"
                        code.add "      do"
                else
-                       toolcontext.error(deserializer_npropdef.location, "Annotation error: you cannont define Deserializer::deserialize_class in a module where you use \"auto_serializable\".")
+                       toolcontext.error(deserializer_npropdef.location, "Annotation error: you cannot define Deserializer::deserialize_class in a module where you use \"auto_serializable\".")
                        return
                end
 
                for nclassdef in nclassdefs do
                        var name = nclassdef.n_id.text
-                       if not name.has('[') then # FIXME this is a temporary hack
+                       if nclassdef.n_formaldefs.is_empty then
                                code.add "              if name == \"{name}\" then return new {name}.from_deserializer(self)"
                        end
                end
@@ -152,23 +170,75 @@ private class SerializationPhase
        end
 end
 
+private class SerializationPhasePostModel
+       super Phase
+
+       redef fun process_nmodule(nmodule)
+       do
+               for npropdef in nmodule.inits_to_retype do
+                       var v = new PreciseTypeVisitor(npropdef, npropdef.mpropdef.mclassdef, toolcontext)
+                       npropdef.accept_precise_type_visitor v
+               end
+       end
+end
+
+# Visitor on generated constructors to replace the expected type of deserialized attributes
+private class PreciseTypeVisitor
+       super Visitor
+
+       var npropdef: AConcreteInitPropdef
+       var mclassdef: MClassDef
+       var toolcontext: ToolContext
+
+       init(npropdef: AConcreteInitPropdef, mclassdef: MClassDef, toolcontext: ToolContext)
+       do
+               self.npropdef = npropdef
+               self.mclassdef = mclassdef
+               self.toolcontext = toolcontext
+       end
+
+       redef fun visit(n) do n.accept_precise_type_visitor(self)
+end
+
+redef class ANode
+       private fun accept_precise_type_visitor(v: PreciseTypeVisitor) do visit_all(v)
+end
+
+redef class AIsaExpr
+       redef fun accept_precise_type_visitor(v)
+       do
+               if n_type.collect_text != v.toolcontext.place_holder_type_name then return
+
+               var attr_name = "_" + n_expr.collect_text
+               for mattrdef in v.mclassdef.mpropdefs do
+                       if mattrdef isa MAttributeDef and mattrdef.name == attr_name then
+                               var new_ntype = v.toolcontext.parse_something(mattrdef.static_mtype.to_s)
+                               n_type.replace_with new_ntype
+                               break
+                       end
+               end
+       end
+end
+
 redef class AAttrPropdef
        private fun name: String
        do
                if n_id == null then return n_id2.text
                return n_id.text
        end
+end
 
+redef class AType
        private fun type_name: String
        do
-               var name = n_type.n_id.text
+               var name = n_id.text
 
-               if n_type.n_kwnullable != null then name = "nullable {name}"
+               if n_kwnullable != null then name = "nullable {name}"
 
-               var types = n_type.n_types
+               var types = n_types
                if not types.is_empty then
                        var params = new Array[String]
-                       for t in types do params.add(t.n_id.text)
+                       for t in types do params.add(t.type_name)
                        return "{name}[{params.join(", ")}]"
                else return name
        end
@@ -185,6 +255,8 @@ redef class AModule
 
                return null
        end
+
+       private var inits_to_retype = new Array[AConcreteInitPropdef]
 end
 
 redef class AStdClassdef