src: new phase check_annotation
authorJean Privat <jean@pryen.org>
Thu, 31 Jul 2014 05:36:47 +0000 (01:36 -0400)
committerJean Privat <jean@pryen.org>
Mon, 4 Aug 2014 16:20:10 +0000 (12:20 -0400)
Signed-off-by: Jean Privat <jean@pryen.org>

src/check_annotation.nit [new file with mode: 0644]
src/frontend.nit

diff --git a/src/check_annotation.nit b/src/check_annotation.nit
new file mode 100644 (file)
index 0000000..38b179f
--- /dev/null
@@ -0,0 +1,112 @@
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# 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.
+
+# Check that annotation present in the AST are either primitive or user-declared
+# There is no verification on the syntax or the semantic of the annotation: just the name is checked
+#
+# Specific phases or tools have to process their annotation and check them correclty.
+module check_annotation
+
+import phase
+import annotation
+
+redef class ToolContext
+       var check_annotation_phase: Phase = new CheckAnnotationPhase(self, null)
+end
+
+private class CheckAnnotationPhase
+       super Phase
+
+       # The map of all declared user annotation
+       # note: lazy because toolcontex is set in the init
+       var declared_annotations = new MModuleMultiData[String](toolcontext.modelbuilder.model) is lazy
+
+       # The current module.
+       var mmodule: nullable MModule = null
+
+       redef fun process_nmodule(nmodule)
+       do
+               # Get the mmodule
+               var mmodule = nmodule.mmodule
+               assert mmodule != null
+               self.mmodule = mmodule
+
+               # If no decl block then quit
+               var nmoduledecl = nmodule.n_moduledecl
+               if nmoduledecl == null then return
+
+               var modelbuilder = toolcontext.modelbuilder
+
+               # Get all the new annotations
+               var annots = nmoduledecl.get_annotations("new_annotation")
+
+               # Add each new annotations in the map
+               for annot in annots do
+                       var name = annot.arg_as_id(modelbuilder)
+                       if name == null then continue
+
+                       declared_annotations[mmodule].add(name)
+                       #annot.debug "add {mmodule}: {name}"
+               end
+       end
+
+       # Raw new-line separated list of primitive annotation
+       # Note: empty-lines will be ignored since there is no annotation named by the empty string.
+       var primtives_annotations_list = """
+new_annotation
+
+fixed
+lazy
+noinit
+readonly
+writable
+cached
+
+pkgconfig
+c_compiler_option
+c_linker_option
+
+platform
+"""
+
+       # Efficient set build from `primtives_annotations_list`
+       var primtives_annotations = new HashSet[String].from(primtives_annotations_list.split("\n"))
+
+       # All user-declared annotations for each mmodule
+       var user_annotations = new HashMap[MModule, HashSet[String]]
+
+       redef fun process_annotated_node(node, nat)
+       do
+               var name = nat.name
+               if primtives_annotations.has(name) then return
+
+               var mmodule = self.mmodule
+               assert mmodule != null
+
+               # Lazily build the full user-list
+               var annots = user_annotations.get_or_null(mmodule)
+               if annots == null then
+                       annots = new HashSet[String]
+                       annots.add_all(declared_annotations.lookup_joined_values(mmodule, private_visibility))
+                       user_annotations[mmodule] = annots
+               end
+               #nat.debug "for {mmodule}: {annots.join(" ")}"
+
+               if annots.has(name) then return
+
+               toolcontext.modelbuilder.warning(nat, "Warning: unknown annotation `{name}`")
+
+               annots.add(name) # to avoid multiple errors on the same name
+       end
+end
index 3d635a3..9b6e84b 100644 (file)
@@ -26,6 +26,7 @@ import auto_super_init
 import div_by_zero
 import cached
 import serialization_phase
+import check_annotation
 
 redef class ToolContext
        # FIXME: there is conflict in linex in nitc, so use this trick to force invocation