From: Jean Privat Date: Tue, 17 Oct 2017 20:09:25 +0000 (-0400) Subject: Merge: markdown: merge MDProcessor and MDEmitter X-Git-Url: http://nitlanguage.org?hp=b83f8333293d5c46ef535dcdc9449dda78221f0b Merge: markdown: merge MDProcessor and MDEmitter The emitter was unecessary. Also done some cleaning. Pull-Request: #2563 --- diff --git a/lib/config.nit b/lib/config.nit index 83566a6..eb2bdba 100644 --- a/lib/config.nit +++ b/lib/config.nit @@ -93,7 +93,7 @@ # # The `IniConfig` class extends `Config` to add an easy way to link your # configuration to an ini file. - +# # ~~~ # class MyIniConfig # super IniConfig diff --git a/lib/markdown/markdown.nit b/lib/markdown/markdown.nit index 1a84b0e..b29372f 100644 --- a/lib/markdown/markdown.nit +++ b/lib/markdown/markdown.nit @@ -1120,6 +1120,12 @@ class MDBlock text.append "\n" line = line.next end + var block = first_block + while block != null do + text.append block.text + text.append "\n" + block = block.next + end return text.write_to_string end end diff --git a/lib/nlp/README.md b/lib/nlp/README.md index c7196c4..9c718a9 100644 --- a/lib/nlp/README.md +++ b/lib/nlp/README.md @@ -61,14 +61,6 @@ For ease of use, this wrapper introduce a Nit model to handle CoreNLP XML result [[doc: nlp::NLPProcessor::process_file]] [[doc: nlp::NLPProcessor::process_files]] -## Vector Space Model - -[[doc: NLPVector]] - -[[doc: vector]] - -[[doc: nlp::NLPVector::cosine_similarity]] - ## NitNLP binary The `nitnlp` binary is given as an example of NitNLP client. diff --git a/lib/nlp/nlp.nit b/lib/nlp/nlp.nit index 4dd7cc9..0e4dba3 100644 --- a/lib/nlp/nlp.nit +++ b/lib/nlp/nlp.nit @@ -23,17 +23,17 @@ import vsm redef class NLPDocument # `NLPVector` representing `self`. - var vector: NLPVector is lazy do - var vector = new NLPVector + var vector: Vector is lazy do + var vector = new Vector for sentence in sentences do for token in sentence.tokens do if not keep_pos_token(token) then continue var lemma = token.lemma if lemma_black_list.has(lemma) then continue if not vector.has_key(lemma) then - vector[lemma] = 1 + vector[lemma] = 1.0 else - vector[lemma] += 1 + vector[lemma] += 1.0 end end end diff --git a/lib/nlp/vsm.nit b/lib/nlp/vsm.nit deleted file mode 100644 index 7fe0a84..0000000 --- a/lib/nlp/vsm.nit +++ /dev/null @@ -1,92 +0,0 @@ -# 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. - -# NLPVector Space Model. -# -# The Vector Space Model (VSM) is used to compare natural language texts. -# Texts are translated to multidimensionnal vectors then compared by cosine -# similarity. -module vsm - -import counter - -# A multi-dimensional vector. -class NLPVector - super Counter[String] - - # Cosine similarity of `self` and `other`. - # - # Gives the proximity in the range `[0.0 .. 1.0]` where 0.0 means that the - # two vectors are orthogonal and 1.0 means that they are identical. - # - # ~~~ - # var v1 = new NLPVector - # v1["x"] = 1 - # v1["y"] = 2 - # v1["z"] = 3 - # - # var v2 = new NLPVector - # v2["x"] = 1 - # v2["y"] = 2 - # v2["z"] = 3 - # - # var v3 = new NLPVector - # v3["a"] = 1 - # v3["b"] = 2 - # v3["c"] = 3 - # - # print v1.cosine_similarity(v2) - # #assert v1.cosine_similarity(v2) == 1.0 - # print v1.cosine_similarity(v3) - # assert v1.cosine_similarity(v3) == 0.0 - # ~~~ - fun cosine_similarity(other: SELF): Float do - # Collect terms - var terms = new HashSet[String] - for k in self.keys do terms.add k - for k in other.keys do terms.add k - - # Get dot product of two verctors - var dot = 0 - for term in terms do - dot += self.get_or_default(term, 0) * other.get_or_default(term, 0) - end - - return dot.to_f / (self.norm * other.norm) - end - - # The norm of the vector. - # - # `||x|| = (x1 ** 2 ... + xn ** 2).sqrt` - # - # ~~~ - # var v = new NLPVector - # v["x"] = 1 - # v["y"] = 1 - # v["z"] = 1 - # v["t"] = 1 - # assert v.norm.is_approx(2.0, 0.001) - # - # v["x"] = 1 - # v["y"] = 2 - # v["z"] = 3 - # v["t"] = 0 - # assert v.norm.is_approx(3.742, 0.001) - # ~~~ - fun norm: Float do - var sum = 0 - for v in self.values do sum += v ** 2 - return sum.to_f.sqrt - end -end diff --git a/lib/vsm/README.md b/lib/vsm/README.md new file mode 100644 index 0000000..ea50132 --- /dev/null +++ b/lib/vsm/README.md @@ -0,0 +1,103 @@ +# Vector Space Model + +Vector Space Model (VSM) is an algebraic model for representing text documents +(and any objects, in general) as vectors of identifiers, such as, for example, +index terms. + +It is used in information filtering, information retrieval, indexing and +relevancy rankings. + +The `vsm` package provides the following features: +* Vector comparison with cosine similarity. +* Vector indexing and matching with tf * idf. +* File indexing and matching to free text queries. + +## Vectors + +With VSM, documents are represented by a n-dimensions vector. +Each dimension represent an attribute of the document or object. + +For text document, the count of each term found in the document if often used to +build vectors. + +### Creating a vector + +~~~ +var vector = new Vector +vector["term1"] = 2.0 +vector["term2"] = 1.0 +assert vector["term1"] == 2.0 +assert vector["term2"] == 1.0 +assert vector.norm.is_approx(2.236, 0.001) +~~~ + +### Comparing vectors + +~~~ +var v1 = new Vector +v1["term1"] = 1.0 +v1["term2"] = 2.0 + +var v2 = new Vector +v2["term2"] = 1.0 +v2["term3"] = 3.0 + +var query = new Vector +query["term2"] = 1.0 + +var s1 = query.cosine_similarity(v1) +var s2 = query.cosine_similarity(v2) +assert s1 > s2 +~~~ + +## VSMIndex + +VSMIndex is a Document index based on VSM. + +Using VSMIndex you can index documents associated with their vector. +Documents can then be matched to query vectors. + +This represents a minimalistic search engine. + +~~~ +var index = new VSMIndex + +var d1 = new Document("Doc 1", "/uri/1", v1) +index.index_document(d1) + +var d2 = new Document("Doc 2", "/uri/2", v2) +index.index_document(d2) + +assert index.documents.length == 2 + +query = new Vector +query["term1"] = 1.0 + +var matches = index.match_vector(query) +assert matches.first.document == d1 +~~~ + +## StringIndex + +The StringIndex provides usefull services to index and match strings. + +~~~ +index = new StringIndex + +d1 = index.index_string("Doc 1", "/uri/1", "this is a sample") +d2 = index.index_string("Doc 2", "/uri/2", "this and this is another example") +assert index.documents.length == 2 + +matches = index.match_string("this sample") +assert matches.first.document == d1 +~~~ + +## FileIndex + +The FileIndex is a StringIndex able to index and retrieve files. + +~~~nit +index = new FileIndex + +index.index_files(["/path/to/doc/1", "/path/to/doc/2"]) +~~~ diff --git a/lib/vsm/examples/example_vsm.nit b/lib/vsm/examples/example_vsm.nit new file mode 100644 index 0000000..5f1192b --- /dev/null +++ b/lib/vsm/examples/example_vsm.nit @@ -0,0 +1,65 @@ +# 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 using a `FileIndex` +# +# This example shows of to index files from the system and retrieve them +# with text queries. +module example_vsm + +import vsm +import config + +redef class Config + + # --whitelist-exts + var opt_white_exts = new OptionArray("Allowed file extensions (default is [])", + "-w", "--whitelist-exts") + + # --blacklist-exts + var opt_black_exts = new OptionArray("Allowed file extensions (default is [])", + "-b", "--blacklist-exts") + + redef init do + opts.add_option(opt_white_exts, opt_black_exts) + end +end + +var config = new Config +config.tool_description = "usage: example_vsm " +config.parse_options(args) + +if args.length < 1 then + config.usage + exit 1 +end + +var index = new FileIndex +index.whitelist_exts = config.opt_white_exts.value +index.blacklist_exts = config.opt_black_exts.value + +print "Building index..." +index.index_files(args, true) +print "Indexed {index.documents.length} documents" + +loop + print "\nEnter query:" + printn "> " + var input = sys.stdin.read_line + var matches = index.match_string(input) + printn "" + for match in matches do + print match + end +end diff --git a/lib/vsm/vsm.nit b/lib/vsm/vsm.nit new file mode 100644 index 0000000..41d5152 --- /dev/null +++ b/lib/vsm/vsm.nit @@ -0,0 +1,374 @@ +# 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. + +# Vector Space Model +# +# Vector Space Model (VSM) is an algebraic model for representing text documents +# (and any objects, in general) as vectors of identifiers, such as, for example, +# index terms. +# +# It is used in information filtering, information retrieval, indexing and +# relevancy rankings. +module vsm + +import counter + +# A n-dimensions vector +# +# *n-dimensions* vectors are used to represent a text document or an object. +class Vector + super HashMap[nullable Object, Float] + + # Cosine similarity of `self` and `other`. + # + # Gives the proximity in the range `[0.0 .. 1.0]` where 0.0 means that the + # two vectors are orthogonal and 1.0 means that they are identical. + # + # ~~~ + # var v1 = new Vector + # v1["x"] = 1.0 + # v1["y"] = 2.0 + # v1["z"] = 3.0 + # + # var v2 = new Vector + # v2["x"] = 1.0 + # v2["y"] = 2.0 + # v2["z"] = 3.0 + # + # var v3 = new Vector + # v3["a"] = 1.0 + # v3["b"] = 2.0 + # v3["c"] = 3.0 + # + # print v1.cosine_similarity(v2) + # assert v1.cosine_similarity(v2) == 1.0 + # print v1.cosine_similarity(v3) + # assert v1.cosine_similarity(v3) == 0.0 + # ~~~ + fun cosine_similarity(other: SELF): Float do + # Collect terms + var terms = new HashSet[nullable Object] + for k in self.keys do terms.add k + for k in other.keys do terms.add k + + # Get dot product of two vectors + var dot = 0.0 + for term in terms do + dot += self.get_or_default(term, 0.0) * other.get_or_default(term, 0.0) + end + var cos = dot.to_f / (self.norm * other.norm) + if cos.is_nan then return 0.0 + return cos + end + + # The norm of the vector. + # + # `||x|| = (x1 ** 2 ... + xn ** 2).sqrt` + # + # ~~~ + # var v = new Vector + # v["x"] = 1.0 + # v["y"] = 1.0 + # v["z"] = 1.0 + # v["t"] = 1.0 + # assert v.norm.is_approx(2.0, 0.001) + # + # v["x"] = 1.0 + # v["y"] = 2.0 + # v["z"] = 3.0 + # v["t"] = 0.0 + # assert v.norm.is_approx(3.742, 0.001) + # ~~~ + fun norm: Float do + var sum = 0.0 + for v in self.values do sum += v.pow(2.0) + return sum.to_f.sqrt + end + + redef fun to_s do + return "[{join(", ", ":")}]" + end +end + +# A Document index based on VSM +# +# Using VSMIndex you can index documents associated with their vector. +# Documents can then be matched to query vectors. +class VSMIndex + + # Documents index + # + # TODO use a more efficient representation. + var documents = new HashSet[Document] + + # Count for all terms in all indexed documents + # + # Used to compute the `inverse_doc_frequency`. + var terms_doc_count = new Vector + + # Inverse document frequency + # + # The inverse document frequency is a measure of how much information a term + # provides, that is, whether the term is common or rare across all documents. + var inverse_doc_frequency = new Vector + + # Used to sort matches + # + # See `IndexMatch`. + var sorter = new IndexMatchSorter + + # Match `query` vector to all index document vectors + # + # Returns an `IndexMatch` for each indexed document. + # Results are ordered by descending similarity. + fun match_vector(query: Vector): Array[IndexMatch] do + var matches = new Array[IndexMatch] + for doc in documents do + var sim = query.cosine_similarity(doc.tfidf) + if sim == 0.0 then continue + matches.add new IndexMatch(doc, sim) + end + sorter.sort(matches) + return matches + end + + # Index a document + # + # With each new document, the `inverse_doc_frequency` must be updated. + # By default, the method `update_index` is called after each call to + # `index_document`. + # + # When processing batch documents, use `auto_update = false` to disable + # the auto update of the index. + fun index_document(doc: Document, auto_update: nullable Bool) do + for term, count in doc.terms_count do + if not terms_doc_count.has_key(term) then + terms_doc_count[term] = 1.0 + else + terms_doc_count[term] += 1.0 + end + end + documents.add doc + if auto_update == null or auto_update then update_index + end + + # Update the index + # + # Recompute the `inverse_doc_frequency` values. + # Must be called manually after indexing new document with the option + # `auto_update = false`. + fun update_index do + for doc in documents do + for term, ccount in doc.terms_count do + inverse_doc_frequency[term] = (documents.length.to_f / terms_doc_count[term]).log + end + end + for doc in documents do + for term, freq in doc.terms_frequency do + doc.tfidf[term] = freq * inverse_doc_frequency[term] + end + end + end +end + +# A VSM index to store strings +class StringIndex + super VSMIndex + + # Index a new Document from `title`, `uri` and string `string`. + # + # Return the Document created. + # + # See `index_document`. + fun index_string(title, uri, string: String, auto_update: nullable Bool): Document do + var vector = parse_string(string) + var doc = new Document(title, uri, vector) + index_document(doc, auto_update) + return doc + end + + # Match the `query` string against all indexed documents + # + # See `match_vector`. + fun match_string(query: String): Array[IndexMatch] do + var vector = parse_string(query) + return match_vector(vector) + end + + # Parse the `string` as a Vector + # + # Returns a vector containing the terms of `string`. + fun parse_string(string: String): Vector do + var reader = new StringReader(string) + var vector = new Vector + loop + var token = reader.read_word + if token == "" then break + + if not vector.has_key(token) then + vector[token] = 1.0 + else + vector[token] += 1.0 + end + end + return vector + end +end + +# A VSMIndex to index files +class FileIndex + super StringIndex + + # Index a file from its `path`. + # + # Return the created document or null if `path` is not accepted by `accept_file`. + # + # See `index_document`. + fun index_file(path: String, auto_update: nullable Bool): nullable Document do + if not accept_file(path) then return null + var vector = parse_file(path) + var doc = new Document(path, path, vector) + index_document(doc, auto_update) + return doc + end + + # Index multiple files + # + # The recursive method `index_dir` will be called for each directory found + # in `paths`. + # + # See `index_file` + fun index_files(paths: Collection[String], auto_update: nullable Bool) do + for path in paths do + if path.to_path.is_dir then + index_dir(path, false) + else + index_file(path, false) + end + end + if auto_update != null and auto_update then update_index + end + + # Index all files in `dir` recursively + # + # See `index_file`. + fun index_dir(dir: String, auto_update: nullable Bool) do + if not dir.to_path.is_dir then return + for file in dir.files do + var path = dir / file + if path.to_path.is_dir then + index_dir(path, false) + else + index_file(path, false) + end + end + if auto_update != null and auto_update then update_index + end + + # Is `path` accepted depending on `whitelist_exts` and `blacklist_exts`? + fun accept_file(path: String): Bool do + var ext = path.file_extension + if ext != null then + ext = ext.to_lower + if blacklist_exts.has(ext) then return false + if whitelist_exts.not_empty and not whitelist_exts.has(ext) then return false + end + return whitelist_exts.is_empty + end + + # Parse the `file` content as a Vector + # + # See `parse_string`. + fun parse_file(file: String): Vector do + return parse_string(file.to_path.read_all) + end + + # File extensions white list + # + # If not empty, only files with these extensions will be indexed. + # + # If an extension is in both `whitelist_exts` and `blacklist_exts`, the + # blacklist will prevail and the file will be ignored. + var whitelist_exts = new Array[String] is writable + + # File extensions black list + # + # Files with these extensions will not be indexed. + var blacklist_exts = new Array[String] is writable +end + +# A Document to add in a VSMIndex +class Document + + # Document title + var title: String + + # Document URI + var uri: String + + # Count of all terms found in the document + # + # Used to compute the document `terms_frequency`. + var terms_count: Vector + + # Frequency of each term found in the document + # + # Used to match the document against the `VSMIndex::inverse_doc_frequency`. + var terms_frequency: Vector is lazy do + var all_terms = 0.0 + for t, c in terms_count do all_terms += c + + var vector = new Vector + for t, c in terms_count do + vector[t] = c / all_terms + end + return vector + end + + # Term frequency–Inverse document frequency for each term + # + # A high weight in tf–idf is reached by a high term frequency + # (in the given document) and a low document frequency of the term in the + # whole collection of documents + var tfidf = new Vector + + redef fun to_s do return "{title}" +end + +# A match to a `request` in an `Index` +class IndexMatch + super Comparable + + # Document matching the `request_vector` + var document: Document + + # Similarity between the `request` and the `doc`. + # + # Result is in the range 0.0 .. 1.1 where 0.0 means no similarity and 1.0 + # means perfect similarity. + var similarity: Float + + redef fun to_s do return "{document} ({similarity})" +end + +# Sort matches by similarity +class IndexMatchSorter + super DefaultComparator + + redef type COMPARED: IndexMatch + + redef fun compare(a, b) do + return b.similarity <=> a.similarity + end +end diff --git a/src/model/model.nit b/src/model/model.nit index 47900c5..dc9b978 100644 --- a/src/model/model.nit +++ b/src/model/model.nit @@ -2377,6 +2377,29 @@ class MMethod # A specific method that is safe to call on null. # Currently, only `==`, `!=` and `is_same_instance` are safe fun is_null_safe: Bool do return name == "==" or name == "!=" or name == "is_same_instance" + + # Is this method a getter (auto or not)? + # + # See `getter_for`. + fun is_getter: Bool do return getter_for != null + + # The attribute this getter is for + # + # Return `null` is this method is not a getter. + var getter_for: nullable MAttribute = null is writable + + # Is this method a setter (auto or not)? + # + # See `setter_for`. + fun is_setter: Bool do return setter_for != null + + # The attribute this setter is for + # + # Return `null` is this method is not a setter. + var setter_for: nullable MAttribute = null is writable + + # Is this method a getter or a setter? + fun is_accessor: Bool do return is_getter or is_setter end # A global attribute @@ -2385,6 +2408,21 @@ class MAttribute redef type MPROPDEF: MAttributeDef + # Does this attribute have a getter (auto or not)? + # + # See `getter`. + fun has_getter: Bool do return getter != null + + # The getter of this attribute (if any) + var getter: nullable MProperty = null is writable + + # Does this attribute have a setter (auto or not)? + # + # See `setter`. + fun has_setter: Bool do return setter != null + + # The setter of this attribute (if any) + var setter: nullable MProperty = null is writable end # A global virtual type @@ -2420,7 +2458,7 @@ abstract class MPropDef # The associated global property var mproperty: MPROPERTY - redef var location: Location + redef var location redef fun visibility do return mproperty.visibility diff --git a/src/model/model_collect.nit b/src/model/model_collect.nit index bfe5fdf..627f982 100644 --- a/src/model/model_collect.nit +++ b/src/model/model_collect.nit @@ -14,17 +14,33 @@ # See the License for the specific language governing permissions and # limitations under the License. -# Collect things from a `Model`. +# Collect things from a `ModelView` +# +# This module introduce several usefull methods to list and count things from a +# ModelView. +# +# First setup you view from a Model: +# +# ~~~nitih +# var view = new ModelView(model) +# ~~~ +# +# Then ask question using the view: +# +# ~~~nitish +# print number of parents for `{my_class}` +# print my_class.collect_parents(view).count +# ~~~ # # **Warning** # # `model_collect` offers a flattened view of the model without considering any # main module. # For this reason, `model_collect` lists all the definitions reachable from all -# modules +# modules. # # This is usefull for tools that need a global view of a model like `nitdoc`, -# `nitx` or `nituml`. +# `nitx`, `nitmetrics` or `nituml`. # It should not be used for compiling stuffs like computing VFT, where the listed # entities could not be reachable depending on the modules really imported. module model_collect @@ -33,20 +49,18 @@ import model_views redef class MEntity - # FIXME used to bypass RTA limitation on type resolution. + # FIXME used to bypass RTA limitation on type resolution type MENTITY: SELF - # Collect modifier keywords like `redef`, `private` etc. - fun collect_modifiers: Array[String] do - return new Array[String] - end + # Collect modifier keywords like `redef`, `private` etc + fun collect_modifiers: Array[String] do return new Array[String] - # Collect `self` linearization anchored on `mainmodule`. + # Collect `self` linearization anchored on `mainmodule` fun collect_linearization(mainmodule: MModule): nullable Array[MEntity] do return null end - # Collect `self` ancestors (direct and indirect). + # Collect `self` ancestors (direct and indirect) # # The concept of ancestor is abstract at this stage. fun collect_ancestors(view: ModelView): Set[MENTITY] do @@ -57,24 +71,23 @@ redef class MEntity while todo.not_empty do var mentity = todo.pop if mentity == self or done.has(mentity) then continue - print "{mentity} == {self}" done.add mentity todo.add_all mentity.collect_parents(view) end return done end - # Collect `self` parents (direct ancestors). + # Collect `self` parents (direct ancestors) # # The concept of parent is abstract at this stage. fun collect_parents(view: ModelView): Set[MENTITY] is abstract - # Collect `self` children (direct descendants). + # Collect `self` children (direct descendants) # # The concept of child is abstract at this stage. fun collect_children(view: ModelView): Set[MENTITY] is abstract - # Collect `self` descendants (direct and direct). + # Collect `self` descendants (direct and direct) # # The concept of descendant is abstract at this stage. fun collect_descendants(view: ModelView): Set[MENTITY] do @@ -91,18 +104,18 @@ redef class MEntity return done end - # Build a poset representing `self` in it's own hierarchy. + # Build a poset representing `self` in it's own hierarchy # # The notion of hierarchy depends on the type of MEntity. # # Here a recap: - # * MPackage: package dependencies - # * MGroup: group dependencies - # * MModule: modules imports - # * MClass: class inheritance (all classdefs flattened) - # * MClassDef: classdef inheritance - # * MProperty: property definitions graph (all propdefs flattened) - # * MPropDef: property definitions graph + # * `MPackage`: package dependencies + # * `MGroup`: group dependencies + # * `MModule`: modules imports + # * `MClass`: class inheritance (all classdefs flattened) + # * `MClassDef`: classdef inheritance + # * `MProperty`: property definitions graph (all propdefs flattened) + # * `MPropDef`: property definitions graph fun hierarchy_poset(view: ModelView): POSet[MENTITY] do var done = new HashSet[MENTITY] var mentities = new Array[MENTITY] @@ -126,14 +139,51 @@ redef class MEntity end end -redef class MPackage - redef fun collect_modifiers do - var res = super - res.add "package" +redef class Model + + # Collect all MPackages in `self` + fun collect_mpackages(view: ModelView): HashSet[MPackage] do + var res = new HashSet[MPackage] + for mpackage in mpackages do + if not view.accept_mentity(mpackage) then continue + res.add(mpackage) + end + return res + end + + # Collect all MModules in `self` + fun collect_mmodules(view: ModelView): HashSet[MModule] do + var res = new HashSet[MModule] + for mpackage in collect_mpackages(view) do + res.add_all mpackage.collect_all_mmodules(view) + end + return res + end + + # Collect all MClasses introduced in `self` + fun collect_intro_mclasses(view: ModelView): HashSet[MClass] do + var res = new HashSet[MClass] + for mpackage in collect_mpackages(view) do + res.add_all mpackage.collect_intro_mclasses(view) + end + return res + end + + # Collect all MProperties introduced in `self` + fun collect_intro_mproperties(view: ModelView): HashSet[MProperty] do + var res = new HashSet[MProperty] + for mpackage in collect_mpackages(view) do + res.add_all mpackage.collect_intro_mproperties(view) + end return res end +end + +redef class MPackage + + redef fun collect_modifiers do return super + ["package"] - # `MPackage` parents are its direct dependencies. + # Collect all packages directly imported by `self` redef fun collect_parents(view) do var res = new HashSet[MENTITY] for mgroup in mgroups do @@ -146,7 +196,7 @@ redef class MPackage return res end - # `MPackage` children are packages that directly depends on `self`. + # Collect all packages that directly depends on `self` redef fun collect_children(view) do var res = new HashSet[MENTITY] for mpackage in view.mpackages do @@ -155,27 +205,139 @@ redef class MPackage return res end - # `MModules` contained in `self`. + # Collect all groups contained in `self` + fun collect_all_mgroups(view: ModelView): HashSet[MGroup] do + var res = new HashSet[MGroup] + for mgroup in mgroups do + if not view.accept_mentity(mgroup) then continue + res.add(mgroup) + end + return res + end + + # Collect only groups contained in `self.root` + fun collect_mgroups(view: ModelView): HashSet[MGroup] do + var res = new HashSet[MGroup] + var root = self.root + if root == null then return res + res.add_all root.collect_mgroups(view) + return res + end + + # Collect all modules contained in `self` + fun collect_all_mmodules(view: ModelView): HashSet[MModule] do + var res = new HashSet[MModule] + for mgroup in collect_mgroups(view) do + res.add_all mgroup.collect_mmodules(view) + end + return res + end + + # Collect only modules contained in `self.root` fun collect_mmodules(view: ModelView): HashSet[MModule] do var res = new HashSet[MModule] + var root = self.root + if root == null then return res + res.add_all root.collect_mmodules(view) + return res + end + + # Collect all classes introduced in `self` + fun collect_intro_mclasses(view: ModelView): HashSet[MClass] do + var res = new HashSet[MClass] for mgroup in mgroups do - for mmodule in mgroup.mmodules do - if not view.accept_mentity(mmodule) then continue - res.add(mmodule) + for mmodule in collect_all_mmodules(view) do + res.add_all mmodule.collect_intro_mclasses(view) end end return res end -end -redef class MGroup - redef fun collect_modifiers do - var res = super - res.add "group" + # Collect all classes redefined or refined in `self` + fun collect_redef_mclasses(view: ModelView): Set[MClass] do + var res = new HashSet[MClass] + for mgroup in mgroups do + for mmodule in collect_all_mmodules(view) do + res.add_all mmodule.collect_redef_mclasses(view) + end + end return res end - # `MGroup` parents are its direct dependencies. + # Collect all properties introduced in `self` + fun collect_intro_mproperties(view: ModelView): HashSet[MProperty] do + var res = new HashSet[MProperty] + for mgroup in mgroups do + for mmodule in collect_all_mmodules(view) do + res.add_all mmodule.collect_intro_mproperties(view) + end + end + return res + end + + # Collect all properties redefined in `self` + fun collect_redef_mproperties(view: ModelView): HashSet[MProperty] do + var res = new HashSet[MProperty] + for mgroup in mgroups do + for mmodule in collect_all_mmodules(view) do + res.add_all mmodule.collect_redef_mproperties(view) + end + end + return res + end + + # Collect all attributes introduced in `self` + fun collect_intro_attributes(view: ModelView): Set[MAttribute] do + var res = new HashSet[MAttribute] + for mgroup in mgroups do + for mmodule in collect_all_mmodules(view) do + res.add_all mmodule.collect_intro_attributes(view) + end + end + return res + end + + # Collect all inits introduced in `self` + fun collect_intro_inits(view: ModelView): Set[MMethod] do + var res = new HashSet[MMethod] + for mgroup in mgroups do + for mmodule in collect_all_mmodules(view) do + res.add_all mmodule.collect_intro_inits(view) + end + end + return res + end + + # Collect all methods introduced in `self` excluding inits + # + # See `collect_intro_inits`. + fun collect_intro_methods(view: ModelView): Set[MMethod] do + var res = new HashSet[MMethod] + for mgroup in mgroups do + for mmodule in collect_all_mmodules(view) do + res.add_all mmodule.collect_intro_methods(view) + end + end + return res + end + + # Collect all virtual types introduced in `self` + fun collect_intro_vts(view: ModelView): Set[MVirtualTypeProp] do + var res = new HashSet[MVirtualTypeProp] + for mgroup in mgroups do + for mmodule in collect_all_mmodules(view) do + res.add_all mmodule.collect_intro_vts(view) + end + end + return res + end +end + +redef class MGroup + + redef fun collect_modifiers do return super + ["group"] + + # Collect all groups directly import by `self` redef fun collect_parents(view) do var res = new HashSet[MENTITY] for mmodule in mmodules do @@ -189,7 +351,7 @@ redef class MGroup return res end - # `MGroup` children are mgroups that directly depends on `self`. + # Collect all group that directly import `self` redef fun collect_children(view) do var res = new HashSet[MENTITY] for mgroup in view.mgroups do @@ -198,17 +360,33 @@ redef class MGroup end return res end -end -redef class MModule + # Collect all groups contained in `self` + fun collect_mgroups(view: ModelView): HashSet[MENTITY] do + var res = new HashSet[MENTITY] + for mgroup in in_nesting.direct_smallers do + if not view.accept_mentity(mgroup) then continue + res.add(mgroup) + end + return res + end - redef fun collect_modifiers do - var res = super - res.add "module" + # Collect all modules contained in `self` + fun collect_mmodules(view: ModelView): HashSet[MModule] do + var res = new HashSet[MModule] + for mmodule in mmodules do + if not view.accept_mentity(mmodule) then continue + res.add(mmodule) + end return res end +end + +redef class MModule - # `MModule` ancestors are all its transitive imports. + redef fun collect_modifiers do return super + ["module"] + + # Collect all module ancestors of `self` (direct and transitive imports) redef fun collect_ancestors(view) do var res = new HashSet[MENTITY] for mentity in in_importation.greaters do @@ -219,7 +397,7 @@ redef class MModule return res end - # `MModule` parents are all its direct imports. + # Collect all modules directly imported by `self` redef fun collect_parents(view) do var res = new HashSet[MENTITY] for mentity in in_importation.direct_greaters do @@ -230,7 +408,7 @@ redef class MModule return res end - # `MModule` children are modules that directly import `self`. + # Collect all modules that directly import `self` redef fun collect_children(view) do var res = new HashSet[MENTITY] for mentity in in_importation.direct_smallers do @@ -241,7 +419,7 @@ redef class MModule return res end - # `MModule` children are modules that transitively import `self`. + # Collect all module descendants of `self` (direct and transitive imports) redef fun collect_descendants(view) do var res = new HashSet[MENTITY] for mentity in in_importation.smallers do @@ -252,7 +430,7 @@ redef class MModule return res end - # Collect mclassdefs introduced in `self` with `visibility >= to min_visibility`. + # Collect all class definitions introduced in `self` fun collect_intro_mclassdefs(view: ModelView): Set[MClassDef] do var res = new HashSet[MClassDef] for mclassdef in mclassdefs do @@ -263,7 +441,7 @@ redef class MModule return res end - # Collect mclassdefs redefined in `self` with `visibility >= to min_visibility`. + # Collect all class definitions refined in `self` fun collect_redef_mclassdefs(view: ModelView): Set[MClassDef] do var res = new HashSet[MClassDef] for mclassdef in mclassdefs do @@ -274,7 +452,15 @@ redef class MModule return res end - # Collect mclasses introduced in `self` with `visibility >= to min_visibility`. + # Collect all class definitions introduced and refined in `self` + fun collect_local_mclassdefs(view: ModelView): Set[MClassDef] do + var res = new HashSet[MClassDef] + res.add_all collect_intro_mclassdefs(view) + res.add_all collect_redef_mclassdefs(view) + return res + end + + # Collect all classes introduced in `self` fun collect_intro_mclasses(view: ModelView): Set[MClass] do var res = new HashSet[MClass] for mclass in intro_mclasses do @@ -284,15 +470,90 @@ redef class MModule return res end - # Collect mclasses redefined in `self` with `visibility >= to min_visibility`. + # Collect all classes refined in `self` fun collect_redef_mclasses(view: ModelView): Set[MClass] do var mclasses = new HashSet[MClass] for mclassdef in mclassdefs do - if not view.accept_mentity(mclassdef) then continue + if not view.accept_mentity(mclassdef.mclass) then continue if not mclassdef.is_intro then mclasses.add(mclassdef.mclass) end return mclasses end + + # Collect all classes introduced and refined in `self` + fun collect_local_mclasses(view: ModelView): Set[MClass] do + var res = new HashSet[MClass] + res.add_all collect_intro_mclasses(view) + res.add_all collect_redef_mclasses(view) + return res + end + + # Collect all classes imported from `self` parents + fun collect_imported_mclasses(view: ModelView): Set[MClass] do + var res = new HashSet[MClass] + for parent in collect_parents(view) do + res.add_all parent.collect_intro_mclasses(view) + res.add_all parent.collect_redef_mclasses(view) + res.add_all parent.collect_imported_mclasses(view) + end + return res + end + + # Collect all properties introduced in `self` + fun collect_intro_mproperties(view: ModelView): Set[MProperty] do + var res = new HashSet[MProperty] + for mclass in collect_intro_mclasses(view) do + res.add_all mclass.collect_intro_mproperties(view) + end + return res + end + + # Collect properties redefined in `self` + fun collect_redef_mproperties(view: ModelView): Set[MProperty] do + var res = new HashSet[MProperty] + for mclassdef in mclassdefs do + for mpropdef in mclassdef.collect_redef_mpropdefs(view) do + res.add mpropdef.mproperty + end + end + return res + end + + # Collect attributes introduced in `self` + fun collect_intro_attributes(view: ModelView): Set[MAttribute] do + var res = new HashSet[MAttribute] + for mproperty in collect_intro_mproperties(view) do + if mproperty isa MAttribute then res.add(mproperty) + end + return res + end + + # Collect all inits introduced in `self` + fun collect_intro_inits(view: ModelView): Set[MMethod] do + var res = new HashSet[MMethod] + for mproperty in collect_intro_mproperties(view) do + if mproperty isa MMethod and mproperty.is_init then res.add(mproperty) + end + return res + end + + # Collect methods introduced in `self` (without inits) + fun collect_intro_methods(view: ModelView): Set[MMethod] do + var res = new HashSet[MMethod] + for mproperty in collect_intro_mproperties(view) do + if mproperty isa MMethod and not mproperty.is_init then res.add(mproperty) + end + return res + end + + # Collect virtual types introduced in `self` + fun collect_intro_vts(view: ModelView): Set[MVirtualTypeProp] do + var res = new HashSet[MVirtualTypeProp] + for mproperty in collect_intro_mproperties(view) do + if mproperty isa MVirtualTypeProp then res.add(mproperty) + end + return res + end end redef class MClass @@ -305,7 +566,7 @@ redef class MClass return mclassdefs end - # `MClass` parents are the direct parents of `self`. + # Collect all direct parents of `self` # # This method uses a flattened hierarchy containing all the mclassdefs. redef fun collect_parents(view) do @@ -320,7 +581,7 @@ redef class MClass return res end - # Collect all ancestors of `self` with `visibility >= to min_visibility`. + # Collect all ancestors of `self` redef fun collect_ancestors(view) do var res = new HashSet[MENTITY] for mclassdef in mclassdefs do @@ -332,7 +593,7 @@ redef class MClass return res end - # `MClass` parents are the direct parents of `self`. + # Collect all direct children of `self` # # This method uses a flattened hierarchy containing all the mclassdefs. redef fun collect_children(view) do @@ -347,7 +608,30 @@ redef class MClass return res end - # Collect all mproperties introduced in 'self' with `visibility >= min_visibility`. + # Collect all class definitions of `self` + fun collect_mclassdefs(view: ModelView): Set[MClassDef] do + var res = new HashSet[MClassDef] + for mclassdef in mclassdefs do + if not view.accept_mentity(mclassdef) then continue + res.add mclassdef + end + return res + end + + # Collect all property definitions that are introductions in `self` + fun collect_intro_mpropdefs(view: ModelView): Set[MPropDef] do + var set = new HashSet[MPropDef] + for mclassdef in mclassdefs do + for mpropdef in mclassdef.mpropdefs do + if not mpropdef.is_intro then continue + if not view.accept_mentity(mpropdef) then continue + set.add(mpropdef) + end + end + return set + end + + # Collect all properties introduced in `self` fun collect_intro_mproperties(view: ModelView): Set[MProperty] do var set = new HashSet[MProperty] for mclassdef in mclassdefs do @@ -359,7 +643,20 @@ redef class MClass return set end - # Collect all mproperties redefined in 'self' with `visibility >= min_visibility`. + # Collect all propierty definitions that are redefinition in `self` + fun collect_redef_mpropdefs(view: ModelView): Set[MPropDef] do + var set = new HashSet[MPropDef] + for mclassdef in mclassdefs do + for mpropdef in mclassdef.mpropdefs do + if mpropdef.is_intro then continue + if not view.accept_mentity(mpropdef) then continue + set.add(mpropdef) + end + end + return set + end + + # Collect all properties redefined in `self` fun collect_redef_mproperties(view: ModelView): Set[MProperty] do var set = new HashSet[MProperty] for mclassdef in mclassdefs do @@ -372,7 +669,7 @@ redef class MClass return set end - # Collect mproperties introduced and redefined in 'self' with `visibility >= min_visibility`. + # Collect all properties introduced and redefined in `self` fun collect_local_mproperties(view: ModelView): Set[MProperty] do var set = new HashSet[MProperty] set.add_all collect_intro_mproperties(view) @@ -380,7 +677,7 @@ redef class MClass return set end - # Collect all mproperties inehrited by 'self' with `visibility >= min_visibility`. + # Collect all properties inehrited by `self` fun collect_inherited_mproperties(view: ModelView): Set[MProperty] do var set = new HashSet[MProperty] for parent in collect_parents(view) do @@ -390,9 +687,9 @@ redef class MClass return set end - # Collect all mproperties accessible by 'self' with `visibility >= min_visibility`. + # Collect all properties accessible by `self` # - # This include introduced, redefined, inherited mproperties. + # This include introduced, redefined, inherited properties. fun collect_accessible_mproperties(view: ModelView): Set[MProperty] do var set = new HashSet[MProperty] set.add_all(collect_intro_mproperties(view)) @@ -401,7 +698,7 @@ redef class MClass return set end - # Collect mmethods introduced in 'self' with `visibility >= min_visibility`. + # Collect all methods introduced in `self` fun collect_intro_mmethods(view: ModelView): Set[MMethod] do var res = new HashSet[MMethod] for mproperty in collect_intro_mproperties(view) do @@ -410,7 +707,7 @@ redef class MClass return res end - # Collect mmethods redefined in 'self' with `visibility >= min_visibility`. + # Collect all methods redefined in `self` fun collect_redef_mmethods(view: ModelView): Set[MMethod] do var res = new HashSet[MMethod] for mproperty in collect_redef_mproperties(view) do @@ -419,7 +716,7 @@ redef class MClass return res end - # Collect mmethods introduced and redefined in 'self' with `visibility >= min_visibility`. + # Collect all methods introduced and redefined in `self` fun collect_local_mmethods(view: ModelView): Set[MMethod] do var set = new HashSet[MMethod] set.add_all collect_intro_mmethods(view) @@ -427,7 +724,7 @@ redef class MClass return set end - # Collect mmethods inherited by 'self' if accepted by `view`. + # Collect all methods inherited by `self` fun collect_inherited_mmethods(view: ModelView): Set[MMethod] do var res = new HashSet[MMethod] for mproperty in collect_inherited_mproperties(view) do @@ -436,9 +733,9 @@ redef class MClass return res end - # Collect all mmethods accessible by 'self' with `visibility >= min_visibility`. + # Collect all methods accessible by `self` # - # This include introduced, redefined, inherited mmethods. + # This include introduced, redefined, inherited methods. fun collect_accessible_mmethods(view: ModelView): Set[MMethod] do var set = new HashSet[MMethod] set.add_all(collect_intro_mmethods(view)) @@ -447,7 +744,7 @@ redef class MClass return set end - # Collect mattributes introduced in 'self' with `visibility >= min_visibility`. + # Collect all attributes introduced in `self` fun collect_intro_mattributes(view: ModelView): Set[MAttribute] do var res = new HashSet[MAttribute] for mproperty in collect_intro_mproperties(view) do @@ -456,7 +753,7 @@ redef class MClass return res end - # Collect mattributes redefined in 'self' with `visibility >= min_visibility`. + # Collect all attributes redefined in `self` fun collect_redef_mattributes(view: ModelView): Set[MAttribute] do var res = new HashSet[MAttribute] for mproperty in collect_redef_mproperties(view) do @@ -465,7 +762,7 @@ redef class MClass return res end - # Collect mattributes introduced and redefined in 'self' with `visibility >= min_visibility`. + # Collect all attributes introduced and redefined in `self` fun collect_local_mattributes(view: ModelView): Set[MAttribute] do var set = new HashSet[MAttribute] set.add_all collect_intro_mattributes(view) @@ -473,7 +770,7 @@ redef class MClass return set end - # Collect mattributes inherited by 'self' with `visibility >= min_visibility`. + # Collect all attributes inherited by `self` fun collect_inherited_mattributes(view: ModelView): Set[MAttribute] do var res = new HashSet[MAttribute] for mproperty in collect_inherited_mproperties(view) do @@ -482,7 +779,7 @@ redef class MClass return res end - # Collect all mattributes accessible by 'self' with `visibility >= min_visibility`. + # Collect all attributes accessible by `self` # # This include introduced, redefined, inherited mattributes. fun collect_accessible_mattributes(view: ModelView): Set[MAttribute] do @@ -493,7 +790,7 @@ redef class MClass return set end - # Collect init mmethods introduced in 'self' if accepted by `view`. + # Collect all init methods introduced in `self` fun collect_intro_inits(view: ModelView): Set[MMethod] do var res = new HashSet[MMethod] for mproperty in collect_intro_mmethods(view) do @@ -502,7 +799,7 @@ redef class MClass return res end - # Collect init mmethods redefined in 'self' if accepted by `view`. + # Collect all init methods redefined in `self` fun collect_redef_inits(view: ModelView): Set[MMethod] do var res = new HashSet[MMethod] for mproperty in collect_redef_mmethods(view) do @@ -511,7 +808,7 @@ redef class MClass return res end - # Collect init mmethods introduced and redefined in 'self' if accepted by `view`. + # Collect all init methods introduced and redefined in `self` fun collect_local_inits(view: ModelView): Set[MMethod] do var set = new HashSet[MMethod] set.add_all collect_intro_inits(view) @@ -519,7 +816,7 @@ redef class MClass return set end - # Collect init mmethods inherited by 'self' if accepted by `view`. + # Collect all init methods inherited by `self` fun collect_inherited_inits(view: ModelView): Set[MMethod] do var res = new HashSet[MMethod] for mproperty in collect_inherited_mmethods(view) do @@ -528,7 +825,7 @@ redef class MClass return res end - # Collect all init mmethods accessible by 'self' if accepted by `view`. + # Collect all init methods accessible by `self` # # This include introduced, redefined, inherited inits. fun collect_accessible_inits(view: ModelView): Set[MMethod] do @@ -539,7 +836,42 @@ redef class MClass return set end - # Collect all virtual types accessible by 'self' if accepted by `view`. + # Collect all virtual types introduced in `self` + fun collect_intro_vts(view: ModelView): Set[MVirtualTypeProp] do + var res = new HashSet[MVirtualTypeProp] + for mproperty in collect_intro_mproperties(view) do + if mproperty isa MVirtualTypeProp then res.add(mproperty) + end + return res + end + + # Collect all virtual types redefined in `self` + fun collect_redef_vts(view: ModelView): Set[MVirtualTypeProp] do + var res = new HashSet[MVirtualTypeProp] + for mproperty in collect_intro_mproperties(view) do + if mproperty isa MVirtualTypeProp then res.add(mproperty) + end + return res + end + + # Collect all virtual types introduced or redefined in `self` + fun collect_local_vts(view: ModelView): Set[MVirtualTypeProp] do + var set = new HashSet[MVirtualTypeProp] + set.add_all collect_intro_vts(view) + set.add_all collect_redef_vts(view) + return set + end + + # Collect all virtual types inherited by `self` + fun collect_inherited_vts(view: ModelView): Set[MVirtualTypeProp] do + var res = new HashSet[MVirtualTypeProp] + for mproperty in collect_inherited_mproperties(view) do + if mproperty isa MVirtualTypeProp then res.add(mproperty) + end + return res + end + + # Collect all virtual types accessible by `self` # # This include introduced, redefined, inherited virtual types. fun collect_accessible_vts(view: ModelView): Set[MVirtualTypeProp] do @@ -553,6 +885,17 @@ end redef class MClassDef + redef fun collect_modifiers do + var res = super + if not is_intro then + res.add "redef" + else + res.add mclass.visibility.to_s + end + res.add mclass.kind.to_s + return res + end + redef fun collect_linearization(mainmodule) do var mclassdefs = new Array[MClassDef] for mclassdef in in_hierarchy.as(not null).greaters do @@ -562,7 +905,6 @@ redef class MClassDef return mclassdefs end - # `MClassDef` ancestors are its direct and transitive super classes. redef fun collect_ancestors(view) do var res = new HashSet[MENTITY] var hierarchy = self.in_hierarchy @@ -574,7 +916,6 @@ redef class MClassDef return res end - # `MClassDef` parents are its direct super classes. redef fun collect_parents(view) do var res = new HashSet[MENTITY] var hierarchy = self.in_hierarchy @@ -586,7 +927,6 @@ redef class MClassDef return res end - # `MClassDef` children are its direct subclasses. redef fun collect_children(view) do var res = new HashSet[MENTITY] var hierarchy = self.in_hierarchy @@ -598,7 +938,7 @@ redef class MClassDef return res end - # Collect mpropdefs in 'self' with `visibility >= min_visibility`. + # Collect all property definitions in `self` fun collect_mpropdefs(view: ModelView): Set[MPropDef] do var res = new HashSet[MPropDef] for mpropdef in mpropdefs do @@ -608,7 +948,37 @@ redef class MClassDef return res end - # Collect mpropdefs introduced in 'self' with `visibility >= min_visibility`. + # Collect all attribute definitions in `self` + fun collect_mattributedefs(view: ModelView): Set[MAttributeDef] do + var res = new HashSet[MAttributeDef] + for mpropdef in collect_mpropdefs(view) do + if not mpropdef isa MAttributeDef then continue + res.add mpropdef + end + return res + end + + # Collect all methods definitions in `self` + fun collect_mmethoddefs(view: ModelView): Set[MMethodDef] do + var res = new HashSet[MMethodDef] + for mpropdef in collect_mpropdefs(view) do + if not mpropdef isa MMethodDef then continue + res.add mpropdef + end + return res + end + + # Collect all virtual types definitions in `self` + fun collect_mtypedefs(view: ModelView): Set[MVirtualTypeDef] do + var res = new HashSet[MVirtualTypeDef] + for mpropdef in collect_mpropdefs(view) do + if not mpropdef isa MVirtualTypeDef then continue + res.add mpropdef + end + return res + end + + # Collect all property definitions that are introduction in `self` fun collect_intro_mpropdefs(view: ModelView): Set[MPropDef] do var res = new HashSet[MPropDef] for mpropdef in mpropdefs do @@ -619,7 +989,7 @@ redef class MClassDef return res end - # Collect mpropdefs redefined in 'self' with `visibility >= min_visibility`. + # Collect all property definitions that are redefinition in `self` fun collect_redef_mpropdefs(view: ModelView): Set[MPropDef] do var res = new HashSet[MPropDef] for mpropdef in mpropdefs do @@ -629,17 +999,6 @@ redef class MClassDef end return res end - - redef fun collect_modifiers do - var res = super - if not is_intro then - res.add "redef" - else - res.add mclass.visibility.to_s - end - res.add mclass.kind.to_s - return res - end end redef class MProperty @@ -651,7 +1010,7 @@ redef class MProperty return mpropdefs end - # Collect mpropdefs in 'self' with `visibility >= min_visibility`. + # Collect all property definitions of `self` fun collect_mpropdefs(view: ModelView): Set[MPropDef] do var res = new HashSet[MPropDef] for mpropdef in mpropdefs do @@ -661,9 +1020,7 @@ redef class MProperty return res end - # `MProperty` parents are all direct super definition of `self`. - # - # This method uses a flattened hierarchy containing all the mpropdefs. + # Collect all direct super definitions of `self` redef fun collect_parents(view) do var res = new HashSet[MENTITY] for mpropdef in mpropdefs do @@ -675,9 +1032,7 @@ redef class MProperty return res end - # `MProperty` parents are all direct sub definition of `self`. - # - # This method uses a flattened hierarchy containing all the mpropdefs. + # Collection all definitions that have `self` as a direct super definition redef fun collect_children(view) do var res = new HashSet[MENTITY] for mpropdef in mpropdefs do @@ -691,6 +1046,7 @@ redef class MProperty end redef class MPropDef + redef fun collect_modifiers do var res = super if not is_intro then @@ -730,7 +1086,7 @@ redef class MPropDef return mpropdefs end - # `MPropDef` parents include only the next definition of `self`. + # Collect only the next definition of `self` redef fun collect_parents(view) do var res = new HashSet[MENTITY] var mpropdef = self @@ -741,7 +1097,7 @@ redef class MPropDef return res end - # `MPropdef` children are definitions that directly depends on `self`. + # Collect all children definitions that directly depend on `self` redef fun collect_children(view) do var res = new HashSet[MENTITY] for mpropdef in mproperty.collect_mpropdefs(view) do diff --git a/src/modelize/modelize_property.nit b/src/modelize/modelize_property.nit index 8880ef7..de23d04 100644 --- a/src/modelize/modelize_property.nit +++ b/src/modelize/modelize_property.nit @@ -1206,6 +1206,12 @@ redef class AAttrPropdef end mclassdef.mprop2npropdef[mreadprop] = self + var attr_mpropdef = mpropdef + if attr_mpropdef != null then + mreadprop.getter_for = attr_mpropdef.mproperty + attr_mpropdef.mproperty.getter = mreadprop + end + var mreadpropdef = new MMethodDef(mclassdef, mreadprop, self.location) self.mreadpropdef = mreadpropdef modelbuilder.mpropdef2npropdef[mreadpropdef] = self @@ -1312,6 +1318,11 @@ redef class AAttrPropdef end mclassdef.mprop2npropdef[mwriteprop] = self + if attr_mpropdef != null then + mwriteprop.setter_for = attr_mpropdef.mproperty + attr_mpropdef.mproperty.setter = mwriteprop + end + var mwritepropdef = new MMethodDef(mclassdef, mwriteprop, self.location) self.mwritepropdef = mwritepropdef modelbuilder.mpropdef2npropdef[mwritepropdef] = self diff --git a/src/web/api_model.nit b/src/web/api_model.nit index 328eff9..3d09a83 100644 --- a/src/web/api_model.nit +++ b/src/web/api_model.nit @@ -216,21 +216,21 @@ class APIEntityDefs redef fun get(req, res) do var mentity = mentity_from_uri(req, res) if mentity == null then return - var mentities: Array[MEntity] + var mentities = new Array[MEntity] if mentity isa MPackage then - mentities = mentity.mgroups.to_a + mentities.add_all mentity.collect_mgroups(config.view) + mentities.add_all mentity.collect_mmodules(config.view) else if mentity isa MGroup then - mentities = new Array[MEntity] - mentities.add_all mentity.in_nesting.direct_smallers - mentities.add_all mentity.mmodules + mentities.add_all mentity.collect_mgroups(config.view) + mentities.add_all mentity.collect_mmodules(config.view) else if mentity isa MModule then - mentities = mentity.mclassdefs + mentities.add_all mentity.collect_local_mclassdefs(config.view) else if mentity isa MClass then - mentities = mentity.mclassdefs + mentities.add_all mentity.collect_mclassdefs(config.view) else if mentity isa MClassDef then - mentities = mentity.mpropdefs + mentities.add_all mentity.collect_mpropdefs(config.view) else if mentity isa MProperty then - mentities = mentity.mpropdefs + mentities.add_all mentity.collect_mpropdefs(config.view) else res.api_error(404, "No definition list for mentity `{mentity.full_name}`") return diff --git a/tests/sav/example_vsm.res b/tests/sav/example_vsm.res new file mode 100644 index 0000000..0e44311 --- /dev/null +++ b/tests/sav/example_vsm.res @@ -0,0 +1,4 @@ +usage: example_vsm + -h, --help Show this help message + -w, --whitelist-exts Allowed file extensions (default is []) + -b, --blacklist-exts Allowed file extensions (default is [])