frontend: introduce `parse_annotations` phase
[nit.git] / src / frontend / parse_annotations.nit
1 # This file is part of NIT ( http://www.nitlanguage.org ).
2 #
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
6 #
7 # http://www.apache.org/licenses/LICENSE-2.0
8 #
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
14
15 # Simple annotation parsing
16 #
17 # This phase collects all the annotations found on AModuleDecl, AClassdef and
18 # APropdef and stores them in the related MEntity.
19 #
20 # Once the phase has been applied, annotations names are available in
21 # `AnnotatedMEntity::annotations`.
22 # One can then ask to the mentity if it holds the annnotation in its source code.
23 #
24 # Example:
25 # ~~~nitish
26 # fun is_annotated_with_foo(mentity: AnnotatedMEntity): Bool do
27 # return mentity.has_annotation("foo")
28 # end
29 # ~~~
30 #
31 # Note that only the names of the annotations are stored, if one wants to access
32 # the annotations arguments, the traditional annotations framework is recommanded.
33 module parse_annotations
34
35 import phase
36 import modelize_class
37 import modelize_property
38 private import annotation
39
40 redef class ToolContext
41 # Parse the annotations on modules, classdefs and propdefs
42 var parse_annotations_phase: Phase = new ParseAnnotationsPhase(self,
43 [modelize_class_phase, modelize_property_phase])
44 end
45
46 # Parse annotations from modules, classdefs and propdefs
47 #
48 # Found annotations names are stored in `AnnotatedMEntity::annotations`.
49 private class ParseAnnotationsPhase
50 super Phase
51
52 # Lookup for `nmodule` annotations
53 redef fun process_nmodule(nmodule) do
54 var mmodule = nmodule.mmodule
55 if mmodule == null then return
56
57 var nmoduledecl = nmodule.n_moduledecl
58 if nmoduledecl == null then return
59
60 var nannots = nmoduledecl.n_annotations
61 if nannots == null then return
62
63 for nannot in nannots.n_items do
64 mmodule.annotations.add nannot.n_atid.n_id.text
65 end
66 end
67
68 # Lookup for `nclassdef` annotations
69 redef fun process_nclassdef(nclassdef) do
70 var mclassdef = nclassdef.mclassdef
71 if mclassdef == null then return
72
73 for npropdef in nclassdef.n_propdefs do
74 if not npropdef isa AAnnotPropdef then continue
75 mclassdef.annotations.add npropdef.n_atid.n_id.text
76 end
77 end
78
79 # Lookup for `npropdef` annotations
80 redef fun process_npropdef(npropdef) do
81 var mpropdef = npropdef.mpropdef
82 if mpropdef == null then return
83
84 var nannots = npropdef.n_annotations
85 if nannots == null then return
86
87 for nannot in nannots.n_items do
88 mpropdef.annotations.add nannot.n_atid.n_id.text
89 end
90 end
91 end
92
93 # A MEntity that can hold annotations from it's source code
94 #
95 # We do not introduce these services in MEntity to avoid semantics confusion.
96 # At this stage, the annotation concept is only relevant to source code related
97 # mentities such as MModules, MClassDefs and MPropdefs.
98 abstract class AnnotatedMEntity
99
100 # Names of the annotations found on `self` declaration
101 var annotations: Set[String] = new HashSet[String]
102
103 # Does `self` contains `annotation` in its declaration?
104 fun has_annotation(annotation: String): Bool do return annotations.has(annotation)
105 end
106
107 redef class MModule
108 super AnnotatedMEntity
109 end
110
111 redef class MClassDef
112 super AnnotatedMEntity
113 end
114
115 redef class MPropDef
116 super AnnotatedMEntity
117 end