--- /dev/null
+# 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.
+
+# Example parsing
+#
+# This module parses example from mentities annotated with `is example`.
+#
+# TODO rank examples
+module parse_examples
+
+import counter
+import typing
+import parse_annotations
+import doc_down
+import model::model_examples
+
+redef class ToolContext
+
+ # Examples parsing phase
+ var examples_phase: Phase = new ExamplesPhase(self,
+ [typing_phase, parse_annotations_phase])
+end
+
+# Parse examples from modules, classdefs and propdefs
+#
+# For each node annotated with `is example` we parse the example and associate
+# it with existing model entities.
+#
+# Association between examples and mentities is based on:
+# `MModule`: Used in `import`
+# `MClassDef`: Used in `super`, redefined class, init or other method called
+# `MPropDef`: Used in `super`, redefined property, called
+private class ExamplesPhase
+ super Phase
+
+ redef fun process_nmodule(nmodule) do
+ var mmodule = nmodule.mmodule
+ if mmodule == null then return
+
+ if not mmodule.has_annotation("example") then return
+
+ process_example(mmodule, nmodule)
+ end
+
+ redef fun process_nclassdef(nclassdef) do
+ var mclassdef = nclassdef.mclassdef
+ if mclassdef == null then return
+
+ if not mclassdef.has_annotation("example") and not mclassdef.mmodule.is_example then return
+
+ process_example(mclassdef, nclassdef)
+ end
+
+ redef fun process_npropdef(npropdef) do
+ var mpropdef = npropdef.mpropdef
+ if mpropdef == null then return
+
+ if not mpropdef.has_annotation("example") and not mpropdef.mclassdef.is_example then return
+
+ process_example(mpropdef, npropdef)
+ end
+
+ # Process an mentity as an MExample
+ #
+ # This method parses the mentity node and link the mentity to possible
+ # examplified entities.
+ fun process_example(example_mentity: MEntity, node: ANode) do
+ var visitor = new ExampleVisitor(toolcontext)
+ visitor.enter_visit(node)
+ var sorted = visitor.counter.sort.reversed
+
+ var example = new MExample(example_mentity)
+ example.node = node
+ for mentity in sorted do
+ example.example_for[mentity] = visitor.counter[mentity]
+ if not mentity.examples.has(example) then mentity.examples.add example
+ end
+ end
+end
+
+redef class MExample
+ # AST node containing the example code
+ var node: nullable ANode = null is writable
+end
+
+# Example parsing
+
+# Visit examples to find what they are an example for.
+private class ExampleVisitor
+ super Visitor
+
+ var counter = new Counter[MEntity]
+
+ # The toolcontext is our entree point to most services
+ var toolcontext: ToolContext
+
+ redef fun visit(node) do
+ node.accept_example_visitor(self)
+ end
+end
+
+redef class ANode
+ private fun accept_example_visitor(v: ExampleVisitor) do visit_all(v)
+end
+
+redef class ANewExpr
+ redef fun accept_example_visitor(v) do
+ var recvtype = self.recvtype
+ if recvtype != null then
+ v.counter.inc recvtype.mclass.intro
+ end
+ visit_all(v)
+ end
+end
+
+redef class AStdImport
+ redef fun accept_example_visitor(v) do
+ var mmodule = self.mmodule
+ if mmodule != null then
+ v.counter.inc mmodule
+
+ var mgroup = mmodule.mgroup
+ if mgroup != null then
+ v.counter.inc mgroup
+ v.counter.inc mgroup.mpackage
+ end
+ end
+ end
+end
+
+redef class AStdClassdef
+ redef fun accept_example_visitor(v) do
+ var mclassdef = self.mclassdef
+ if mclassdef == null then return
+
+ if not mclassdef.is_intro then
+ v.counter.inc mclassdef.mclass.intro
+ end
+ visit_all(v)
+ end
+end
+
+redef class APropdef
+ redef fun accept_example_visitor(v) do
+ var mpropdef = self.mpropdef
+ if mpropdef == null then return
+
+ if not mpropdef.is_intro then
+ v.counter.inc mpropdef.mproperty.intro.mclassdef.mclass
+ v.counter.inc mpropdef.mproperty.intro.mclassdef
+ v.counter.inc mpropdef.mproperty.intro
+ end
+ visit_all(v)
+ end
+end
+
+redef class ASuperPropdef
+ redef fun accept_example_visitor(v) do
+ var mtype = self.n_type.mtype
+ if mtype isa MClassType then
+ v.counter.inc mtype.mclass
+ v.counter.inc mtype.mclass.intro
+ end
+ end
+end
+
+redef class ASendExpr
+ redef fun accept_example_visitor(v) do
+ var callsite = self.callsite
+ if callsite == null then return
+ v.counter.inc callsite.mpropdef
+ v.counter.inc callsite.mpropdef.mproperty
+ v.counter.inc callsite.mpropdef.mclassdef
+ v.counter.inc callsite.mpropdef.mclassdef.mclass
+ end
+end