private import annotation
redef class ToolContext
+
+ # Apply the annotation `serialize_as`
+ var serialization_phase_rename: Phase = new SerializationPhaseRename(self, null)
+
# Generate serialization and deserialization methods on `auto_serializable` annotated classes.
- var serialization_phase_pre_model: Phase = new SerializationPhasePreModel(self, null)
+ var serialization_phase_pre_model: Phase = new SerializationPhasePreModel(self,
+ [serialization_phase_rename])
# The second phase of the serialization
var serialization_phase_post_model: Phase = new SerializationPhasePostModel(self,
end
end
-# TODO add annotations on attributes (volatile, sensitive or do_not_serialize?)
+private class SerializationPhaseRename
+ super Phase
+
+ redef fun process_annotated_node(node, nat)
+ do
+ var text = nat.n_atid.n_id.text
+ if text != "serialize_as" then return
+
+ if not node isa AAttrPropdef then
+ toolcontext.error(node.location,
+ "Syntax Error: annotation `{text}` applies only to attributes.")
+ return
+ end
+
+ # Can't use `arg_as_string` because it needs the literal phase
+ var args = nat.n_args
+ if args.length != 1 or not args.first isa AStringFormExpr then
+ toolcontext.error(node.location,
+ "Syntax Error: annotation `{text}` expects a single string literal as argument.")
+ return
+ end
+
+ var t = args.first.collect_text
+ var val = t.substring(1, t.length-2)
+ node.serialize_name = val
+ end
+end
+
private class SerializationPhasePreModel
super Phase
if (per_attribute and not attribute.is_serialize) or
attribute.is_noserialize then continue
- var name = attribute.name
- code.add " v.serialize_attribute(\"{name}\", {name})"
+ code.add " v.serialize_attribute(\"{attribute.serialize_name}\", {attribute.name})"
end
code.add "end"
do
var npropdefs = nclassdef.n_propdefs
+ # Do not insert a `from_deserializer` if it already exists
+ for npropdef in npropdefs do
+ if npropdef isa AMethPropdef then
+ var methid = npropdef.n_methid
+ if methid != null and methid.collect_text == "from_deserializer" then
+ return
+ end
+ end
+ end
+
var code = new Array[String]
code.add """
redef init from_deserializer(v: Deserializer)
var name = attribute.name
code.add """
- var {{{name}}} = v.deserialize_attribute("{{{name}}}")
+ var {{{name}}} = v.deserialize_attribute("{{{attribute.serialize_name}}}")
if not {{{name}}} isa {{{type_name}}} then
# Check if it was a subjectent error
v.errors.add new AttributeTypeError("TODO remove this arg on c_src regen",
- self, "{{{name}}}", {{{name}}}, "{{{type_name}}}")
+ self, "{{{attribute.serialize_name}}}", {{{name}}}, "{{{type_name}}}")
# Clear subjacent error
if v.keep_going == false then return
end
for nclassdef in nclassdefs do
- var name = nclassdef.n_id.text
+ var name = nclassdef.n_qid.n_id.text
if nclassdef.n_formaldefs.is_empty and
nclassdef.n_classkind isa AConcreteClasskind then
end
redef class AAttrPropdef
- private fun name: String
- do
- return n_id2.text
- end
+ private fun name: String do return n_id2.text
+
+ # Name of this attribute in the serialized format
+ private var serialize_name: String = name is lazy
end
redef class AType
private fun type_name: String
do
- var name = n_id.text
+ var name = n_qid.n_id.text
if n_kwnullable != null then name = "nullable {name}"
private fun deserializer_nclassdef: nullable AStdClassdef
do
for nclassdef in n_classdefs do
- if nclassdef isa AStdClassdef and nclassdef.n_id.text == "Deserializer" then
+ if nclassdef isa AStdClassdef and nclassdef.n_qid.n_id.text == "Deserializer" then
return nclassdef
end
end