1 # This file is part of NIT ( http://www.nitlanguage.org ).
3 # Copyright 2013 Jean-Philippe Caissy <jpcaissy@piji.ca>
4 # Copyright 2013 Guillaume Auger <jeho@resist.ca>
5 # Copyright 2014 Alexis Laferrière <alexis.laf@xymus.net>
7 # Licensed under the Apache License, Version 2.0 (the "License");
8 # you may not use this file except in compliance with the License.
9 # You may obtain a copy of the License at
11 # http://www.apache.org/licenses/LICENSE-2.0
13 # Unless required by applicable law or agreed to in writing, software
14 # distributed under the License is distributed on an "AS IS" BASIS,
15 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 # See the License for the specific language governing permissions and
17 # limitations under the License.
19 # Phase generating methods to serialize Nit objects to different formats
20 module serialization_phase
25 redef class ToolContext
26 var serialization_phase
: Phase = new SerializationPhase(self, null)
29 # TODO automaticaly add Serializable as a super class
31 # TODO add annotations on attributes (volatile, sensitive or do_not_serialize?)
32 private class SerializationPhase
35 redef fun process_annotated_node
(nclassdef
, nat
)
37 # Skip if we are not interested
38 if nat
.n_atid
.n_id
.text
!= "auto_serializable" then return
39 if not nclassdef
isa AStdClassdef then
40 toolcontext
.error
(nclassdef
.location
, "Syntax error: only a concrete class can be automatically serialized.")
44 generate_serialization_method
(nclassdef
)
46 generate_deserialization_init
(nclassdef
)
49 redef fun process_nmodule
(nmodule
)
52 var auto_serializable_nclassdefs
= new Array[AStdClassdef]
53 for nclassdef
in nmodule
.n_classdefs
do
54 if nclassdef
isa AStdClassdef and
55 not nclassdef
.collect_annotations_by_name
("auto_serializable").is_empty
then
56 auto_serializable_nclassdefs
.add nclassdef
60 if not auto_serializable_nclassdefs
.is_empty
then
61 generate_deserialization_method
(nmodule
, auto_serializable_nclassdefs
)
65 private fun generate_serialization_method
(nclassdef
: AClassdef)
67 var npropdefs
= nclassdef
.n_propdefs
69 var code
= new Array[String]
70 code
.add
"redef fun core_serialize_to(v)"
74 for attribute
in npropdefs
do if attribute
isa AAttrPropdef then
75 var name
= attribute
.name
76 code
.add
" v.serialize_attribute(\"{name}\
", {name})"
81 # Create method Node and add it to the AST
82 npropdefs
.push
(toolcontext
.parse_propdef
(code
.join
("\n")))
85 # Add a constructor to the automated nclassdef
86 private fun generate_deserialization_init
(nclassdef
: AClassdef)
88 var npropdefs
= nclassdef
.n_propdefs
90 var code
= new Array[String]
91 code
.add
"init from_deserializer(v: Deserializer)"
93 code
.add
" v.notify_of_creation self"
95 for attribute
in npropdefs
do if attribute
isa AAttrPropdef then
96 if attribute
.n_type
== null then
97 toolcontext
.error
(attribute
.location
, "NOT YET IMPLEMENTED: all attributes of an auto_serialized class definition must define a type.")
100 var name
= attribute
.name
101 var type_name
= attribute
.type_name
103 code
.add
"\tvar {name} = v.deserialize_attribute(\"{name}\
")"
104 code
.add
"\tassert {name} isa {type_name} else print \"Expected attribute
'{name}' to be of
type '{type_name}'\
""
105 code
.add
"\tself.{name} = {name}"
109 npropdefs
.add
(toolcontext
.parse_propdef
(code
.join
("\n")))
112 # Added to the abstract serialization service
113 private fun generate_deserialization_method
(nmodule
: AModule, nclassdefs
: Array[AStdClassdef])
115 var code
= new Array[String]
117 var deserializer_nclassdef
= nmodule
.deserializer_nclassdef
118 var deserializer_npropdef
119 if deserializer_nclassdef
== null then
121 code
.add
"redef class Deserializer"
122 deserializer_npropdef
= null
124 deserializer_npropdef
= deserializer_nclassdef
.deserializer_npropdef
127 if deserializer_npropdef
== null then
128 # create the property
129 code
.add
" redef fun deserialize_class(name)"
132 toolcontext
.error
(deserializer_npropdef
.location
, "Annotation error: you cannont define Deserializer::deserialize_class in a module where you use \"auto_serializable\
".")
136 for nclassdef
in nclassdefs
do
137 var name
= nclassdef
.n_id
.text
138 if not name
.has
('[') then # FIXME this is a temporary hack
139 code
.add
" if name == \"{name}\
" then return new {name}.from_deserializer(self)"
143 code
.add
" return super"
146 if deserializer_nclassdef
== null then
148 nmodule
.n_classdefs
.add toolcontext
.parse_classdef
(code
.join
("\n"))
150 deserializer_nclassdef
.n_propdefs
.add
(toolcontext
.parse_propdef
(code
.join
("\n")))
155 redef class AAttrPropdef
156 private fun name
: String
158 if n_id
== null then return n_id2
.text
162 private fun type_name
: String
164 var name
= n_type
.n_id
.text
166 if n_type
.n_kwnullable
!= null then name
= "nullable {name}"
168 var types
= n_type
.n_types
169 if not types
.is_empty
then
170 var params
= new Array[String]
171 for t
in types
do params
.add
(t
.n_id
.text
)
172 return "{name}[{params.join(", ")}]"
178 private fun deserializer_nclassdef
: nullable AStdClassdef
180 for nclassdef
in n_classdefs
do
181 if nclassdef
isa AStdClassdef and nclassdef
.n_id
.text
== "Deserialization" then
190 redef class AStdClassdef
191 private fun deserializer_npropdef
: nullable AMethPropdef
193 for npropdef
in n_propdefs
do if npropdef
isa AMethPropdef then
194 var id
= npropdef
.n_methid
195 if id
isa AIdMethid and id
.n_id
.text
== "deserialize_class" then