tests/*.xml
tests/nitunit
+nitunit.xml
+
*.stub.nit.[ch]
.metadata/*
2014 Maxime Leroy <maxime.leroy76@gmail.com>
2014 Johann Dubois <johann.dubois@outlook.com>
2014 Jean-Christophe Beaupré <jcbrinfo@users.noreply.github.com>
+ 2014 Alexandre Blondin Massé <alexandre.blondin.masse@gmail.com>
Licence: BSD 2 (see LICENSE-BSD)
Comment: Use of libraries and resources is basically unrestricted. We hold the copyright
on the compiler and the tools but not on the programs made by the users.
# FIXME : This huge `if` block is only necessary to copy primitive arrays as long as there's no better way to do it
if comment == "#" then
- temp.add(" in \"Java\" `\{\n{comment}\t\trecv.{jmethod_id}({java_params}); \n{comment}\t`\}\n")
+ temp.add(" in \"Java\" `\{\n{comment}\t\trecv.{jmethod_id}({java_params});\n{comment}\t`\}\n")
# Methods with return type
else if return_type != null then
if jreturn_type.is_primitive_array then
temp.add(code_warehouse.param_type_copy(param_to_copy.first, param_to_copy.second, jmethod_id, java_params, true))
# No copy
else
- temp.add(" in \"Java\" `\{\n{comment}\t\treturn {jreturn_type.return_cast} recv.{jmethod_id}({java_params}); \n{comment}\t`\}\n")
+ temp.add(" in \"Java\" `\{\n{comment}\t\treturn {jreturn_type.return_cast} recv.{jmethod_id}({java_params});\n{comment}\t`\}\n")
end
# Methods without return type
else if jreturn_type.is_void then
temp.add(code_warehouse.param_type_copy(param_to_copy.first, param_to_copy.second, jmethod_id, java_params, false))
# No copy
else
- temp.add(" in \"Java\" `\{\n{comment}\t\trecv.{jmethod_id}({java_params}); \n{comment}\t`\}\n")
+ temp.add(" in \"Java\" `\{\n{comment}\t\trecv.{jmethod_id}({java_params});\n{comment}\t`\}\n")
end
# No copy
else
- temp.add(" in \"Java\" `\{\n{comment}\t\trecv.{jmethod_id}({java_params}); \n{comment}\t`\}\n")
+ temp.add(" in \"Java\" `\{\n{comment}\t\trecv.{jmethod_id}({java_params});\n{comment}\t`\}\n")
end
return temp.join("")
# #
# C L A S S H E A D E R #
# #
+
redef class Nclass_header
redef fun accept_visitor(v)
do
NITG=../../bin/nitg
NITG_FLAGS=--dir bin
NEO4J_DIR=/var/lib/neo4j
+OLD_PWD=${PWD}
-.PHONY: bin reset-neo
+.PHONY: bin reset-neo run-tests tests
# Compile the tool.
bin:
mkdir -p bin
- ../../bin/nitg --dir bin src/neo_doxygen.nit
+ $(NITG) $(NITG_FLAGS) src/neo_doxygen.nit
# Reset the local graph.
reset-neo:
sudo -u neo4j "${NEO4J_DIR}/bin/neo4j" stop \
&& sudo -u neo4j rm -rf "${NEO4J_DIR}/data/graph.db" \
&& sudo -u neo4j "${NEO4J_DIR}/bin/neo4j" start
+
+# Regenerate the XML documents in `tests`.
+tests:
+ $(MAKE) -C tests
+
+# Run the tests.
+run-tests:
+ cd ../../tests; \
+ ./tests.sh ../contrib/neo_doxygen/src/tests/neo_doxygen_*.nit ; \
+ cd "${OLD_PWD}"
--- /dev/null
+# neo_doxygen
+
+This project provides a tool to convert a Doxygen XML output into a model in
+Neo4j that is readable by the `nx` tool.
+
+
+## Installation
+
+Ensure that you have a working version of `nitg` in `../../bin` then run `make`
+in the present directory. The executable will be then generated at
+`bin/neo_doxygen`.
+
+
+## Usage
+
+Here is the procedure to generate an HTML documentation of a project using the
+formatting of Nitdoc:
+
+1. First run Doxygen to generate an XML output of the documentation. In order to do
+this, you have to enable the `GENERATE_XML` option. Note that you can disable
+the `XML_PROGRAMLISTING` to speed up the process and save disk space.
+
+ <strong>Important</strong>
+
+ `neo_doxygen` do not read the `index.xml` file to know which file to load. As a
+ result, it may read files let by previous runs of Doxygen. To avoid producing
+ garbage, always clear the destination directory of the XML files before running
+ Doxygen.
+
+ Example: `rm -rf doxygen/xml && doxygen Doxyfile`
+
+2. Use `bin/neo_doxygen` to generate the Neo4j graph. For details, run
+`bin/neo_doxygen --help`.
+
+ <strong>Important</strong>
+
+ `neo_doxygen` do not remove what is already in the graph. So, you have to
+ manualy clear the graph (or at least, the subgraph contaning all the nodes
+ labelled with the specified project name) between each run.
+
+ For an example of how to delete an entire Neo4j database, see
+ `make reset-neo`.
+
+ Example: `make reset-neo && neo_doxygen my_project doxygen/xml`
+
+3. Use the `nx` tool to generate the HTML documentation from the previously
+generated graph.
+
+ Note: `nx` need to be configured before usage. For more details, refer to
+ the documentation of `nx`.
+
+ Example: `nx neo doc my_project`
+
+
+## Shell scripts
+
+The two shell scripts (`gen-one.sh` and `gen-all.sh`) are provided to automate
+the execution of `neo_doxygen` and `nx` for some typical cases and to give a
+starting for the development of similar scripts. In order for them to work,
+each project on which they operate **must** contain the following files:
+
+ * The `.nx_config` configuration file for the `nx` tool, located at the root
+ of the project.
+
+ * The XML documents generated by Doxygen, located in the `doxygen/xml`
+ directory.
+
+Also, they **must** be run with the current working directory set to the present
+directory. `gen-one.sh` handle only one project at a time while `gen-all.sh`
+works on a collection of projects grouped in a directory. For detail about how
+to invoke each script, see the comments in these scripts.
# Also, every project must include the Doxygen XML output in its `doxygen/xml`
# directory.
-NEO_DOXYGEN="${PWD}/bin/neo_doxygen"
-NX="${PWD}/../../bin/nx"
-
for dir in "$2"/*; do
if [ -d "$dir" ]; then
if [ -f "$dir/.nx_config" ]; then
--- /dev/null
+Libraries used by shell scripts.
--- /dev/null
+#! /bin/sh
+
+# 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.
+
+# Functions related to the `sed` utility.
+
+# Replace `$1` by `$2` in the specified files (the rest of the arguments).
+#
+# Replacements are done in place.
+#
+# SETS: `local_1`
+# SETS: `local_2`
+replace() {
+ local_1=`escape_to_bre "$1"`
+ local_2=`escape_to_bre "$2"`
+ shift 2
+ sed -s -i -e s."${local_1}"."${local_2}".g -- "$@"
+ unset local_1
+ unset local_2
+}
+
+# Escape `$1` for inclusion in a POSIX BRE.
+escape_to_bre() {
+ echo "$1" | sed -e 's/\*\|\.\|\^\|\$\|\[\|\\/\\\0/g'
+}
class CompoundDefListener
super EntityDefListener
+ # The defined compound.
var compound: Compound is writable, noinit
+
private var memberdef: MemberDefListener is noinit
private var param_listener: TypeParamListener is noinit
redef fun entity: Entity do return compound
redef fun start_dox_element(local_name: String, atts: Attributes) do
- if ["compoundname", "innerclass", "innernamespace"].has(local_name) then
+ if "compoundname" == local_name then
text.listen_until(dox_uri, local_name)
- if ["innerclass", "innernamespace"].has(local_name) then
- refid = get_required(atts, "refid")
- end
- else if "basecompoundref" == local_name then
- refid = get_optional(atts, "refid", "")
+ else if ["innerclass", "innernamespace", "basecompoundref"].has(local_name) then
prot = get_optional(atts, "prot", "")
- virt = get_optional(atts, "virt", "")
text.listen_until(dox_uri, local_name)
+ if "basecompoundref" == local_name then
+ refid = get_optional(atts, "refid", "")
+ virt = get_optional(atts, "virt", "")
+ else
+ refid = get_required(atts, "refid")
+ end
else if "memberdef" == local_name then
read_member(atts)
- else if local_name == "sectiondef" then
+ else if "sectiondef" == local_name then
member_defaults = section_kinds[get_required(atts, "kind")]
if member_defaults.is_special then
super # TODO
end
redef fun end_dox_element(local_name: String) do
- if local_name == "compoundname" then
+ if "compoundname" == local_name then
compound.full_name = text.to_s
- else if local_name == "innerclass" then
- compound.declare_class(refid, text.to_s)
- else if local_name == "innernamespace" then
+ else if "innerclass" == local_name then
+ compound.declare_class(refid, text.to_s, prot)
+ else if "innernamespace" == local_name then
compound.declare_namespace(refid, text.to_s)
else if "memberdef" == local_name then
if not (memberdef.member isa UnknownMember) then
compound.declare_member(memberdef.member)
end
- else if local_name == "basecompoundref" then
+ else if "basecompoundref" == local_name then
compound.declare_super(refid, text.to_s, prot, virt)
else if "param" == local_name and compound isa ClassCompound then
compound.as(ClassCompound).add_type_parameter(param_listener.parameter)
class DocListener
super TextListener
- var doc: JsonArray = new JsonArray is writable
+ # The read documentation.
+ var doc = new JsonArray is writable
redef fun end_listening do
super
- doc.add(to_s)
+ var line = to_s.trim
+ if not line.is_empty then doc.add(line)
end
end
var content = text_array.last.as(String).r_trim
var link = text.links.first
- var found = false
if link == null and content.has_suffix(suffix) then
content = content.substring(0, content.length - suffix.length).r_trim
# For abstract members, Doxygen put `abstract` at the beginning of the type.
# We assume that Doxygen do not put annotations in the type (it seems to
# be the case).
- member.is_abstract = extract_keyword(type_text, "abstract")
+ if extract_keyword(type_text, "abstract") then
+ member.is_abstract = true
+ end
# TODO final
# TODO void
# TODO Avoid using `RawType` when possible. Only use `RawType` as a fallback.
self.locator = locator
end
+ # The Doxygen’s namespace IRI.
protected fun dox_uri: String do return ""
redef fun start_element(uri: String, local_name: String, qname: String,
# See `ContentHandler.start_element` for the description of the parameters.
protected fun end_dox_element(local_name: String) do end
+ # Get the boolean value of the specified attribute.
+ #
+ # `false` by default.
protected fun get_bool(atts: Attributes, local_name: String): Bool do
return get_optional(atts, local_name, "no") == "yes"
end
class TextListener
super StackableListener
+ # The read text.
protected var buffer: Buffer = new FlatBuffer
+
+ # Is the last read chunk was ignorable white space?
private var sp: Bool = false
redef fun listen_until(uri: String, local_name: String) do
--- /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.
+
+# Add the ability to flush the standard output.
+module flush_stdout
+
+in "C Header" `{
+ #include <stdio.h>
+`}
+
+# Flush the standard output.
+fun flush_stdout in "C" `{
+ fflush(stdout);
+`}
--- /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.
+
+# A storage medium for a graph.
+module graph_store
+
+import neo4j
+import console
+import flush_stdout
+
+# A storage medium for a graph.
+#
+# Provides a way to save a Neo4j graph.
+abstract class GraphStore
+
+ # Escape control sequence to save the cursor position.
+ private var term_save_cursor: String = (new TermSaveCursor).to_s
+
+ # Escape control sequence to rewind to the last saved cursor position.
+ private var term_rewind: String = "{new TermRestoreCursor}{new TermEraseDisplayDown}"
+
+ # Is the storage medium already contains at least one node with the specified label?
+ fun has_node_label(name: String): Bool is abstract
+
+ # Save all specified Neo4j entities.
+ fun save_all(neo_entities: Collection[NeoEntity]) is abstract
+
+ # Prepare the output to show the progress.
+ #
+ # This method must be called before the first call to `show_progress` or
+ # `show_done`.
+ protected fun prepare_display do
+ printn "{term_save_cursor} "
+ flush_stdout
+ end
+
+ # Show the progress, in percentage.
+ #
+ # For use in the implementation of `save_all` only.
+ protected fun show_progress(progress: Int) do
+ printn "{term_rewind} {progress}% "
+ flush_stdout
+ end
+
+ # Show a message to indicate that the task finished with success.
+ #
+ # For use in the implementation of `save_all` only.
+ protected fun show_done do
+ print "{term_rewind} Done."
+ flush_stdout
+ end
+end
+
+# An actual Neo4j database as a storage medium.
+class Neo4jStore
+ super GraphStore
+
+ # How many operations can be executed in one batch?
+ private var batch_max_size = 1000
+
+ # The Neo4j client to use.
+ var client: Neo4jClient
+
+ redef fun has_node_label(name: String): Bool do
+ var query = new CypherQuery.from_string(
+ "match n where \{name\} in labels(n) return count(n)")
+ query.params["name"] = name
+ var data = client.cypher(query).as(JsonObject)["data"]
+ var result = data.as(JsonArray).first.as(JsonArray).first.as(Int)
+ return result > 0
+ end
+
+ redef fun save_all(neo_entities: Collection[NeoEntity]) do
+ var batch = new NeoBatch(client)
+ var len = neo_entities.length
+ var sum = 0
+ var i = 1
+
+ prepare_display
+ for nentity in neo_entities do
+ batch.save_entity(nentity)
+ if i == batch_max_size then
+ do_batch(batch)
+ sum += batch_max_size
+ show_progress(sum * 100 / len)
+ batch = new NeoBatch(client)
+ i = 1
+ else
+ i += 1
+ end
+ end
+ do_batch(batch)
+ show_done
+ end
+
+ # Execute `batch` and check for errors.
+ #
+ # Abort if `batch.execute` returns errors.
+ private fun do_batch(batch: NeoBatch) do
+ var errors = batch.execute
+ if not errors.is_empty then
+ for e in errors do sys.stderr.write("{sys.program_name}: {e}\n")
+ exit(1)
+ end
+ end
+end
class_def["mdoc"] = doc
end
- redef fun declare_super(id: String, name: String, prot: String, virt: String) do
- class_def.declare_super(id, name, prot, virt)
+ redef fun declare_super(id: String, full_name: String, prot: String, virt: String) do
+ class_def.declare_super(id, full_name, prot, virt)
end
redef fun declare_member(member: Member) do
class ClassDef
super CodeBlock
+ # The defined class.
var class_compound: ClassCompound
+
+ # The `model_id` of the base classes.
var supers: SimpleCollection[String] = new Array[String]
- var members: SimpleCollection[Member] = new Array[Member]
+
+ # The set of the introduced/redefined members.
+ #
+ # Includes inner classes.
+ #
+ # To ensure that the `full_name` of each member is correctly set,
+ # `declare_member` or `declare_class` should be used to add each member.
+ #
+ # Note: `declare_class` is defined by the `inner_class` module.
+ var members: SimpleCollection[MemberOrInner] = new Array[MemberOrInner]
init do
super
self["is_intro"] = true
end
- fun declare_super(id: String, name: String, prot: String, virt: String) do
- # TODO prot, virt, name
+ # Declare a base compound (usually, a base class).
+ #
+ # Parameters:
+ #
+ # * `id`: `model_id` of the base compound. May be empty.
+ # * `full_name`: qualified name of the base compound. May be empty.
+ # * `prot`: visibility (proctection) of the relationship.
+ # * `virt`: level of virtuality of the relationship.
+ fun declare_super(id: String, full_name: String, prot: String,
+ virt: String) do
+ # TODO prot, virt, full_name
if "" != id then
supers.add(id)
end
end
+ # Append the specified member.
fun declare_member(member: Member) do
var full_name = self["full_name"]
# Return the number of arguments.
fun arity: Int do return arguments.length
+ # Is the class generic?
fun is_generic: Bool do return arity > 0
redef fun put_in_graph do
module model::graph
import neo4j
+import more_collections
import location
# A Neo4j graph.
class NeoGraph
+ # All the nodes in the graph.
var all_nodes: SimpleCollection[NeoNode] = new Array[NeoNode]
+
+ # All the edges in the graph.
var all_edges: SimpleCollection[NeoEdge] = new Array[NeoEdge]
# Add a relationship between two nodes.
end
end
-# The project’s graph.
+# A project’s graph.
+#
+# Here is the usual steps to build a project graph:
+#
+# <ul>
+# <li>Instantiate `ProjectGraph` by giving the name that will label the project.</li>
+# <li>For each compound:
+# <ul>
+# <li>Instantiate the compound.</li>
+# <li>Provide all the related data.</li>
+# <li>Call the `put_in_graph` method of the compound.</li>
+# </ul></li>
+# <li>Call the `add_global_modules` method of the project’s graph (defined in
+# the `module_compound` module). This permits to take global classes into
+# account correctly.</li>
+# <li>Call the `put_edges` method of the project’s graph.</li>
+# </ul>
class ProjectGraph
super NeoGraph
+ # The project’s name.
+ var project_name: String
+
# The node reperesenting the project.
#
# Once the project’s graph is initialized, this node must not be edited.
- var project: NeoNode = new NeoNode
+ var project = new NeoNode
# Entities by `model_id`.
var by_id: Map[String, Entity] = new HashMap[String, Entity]
+ # Namespaces by `full_name`.
+ var namespaces: Map[String, Namespace] = new HashMap[String, Namespace]
+
+ # For each `ClassCompound` in the graph, the mapping between its `model_id` and its namespace.
+ #
+ # Defaults to the root namespace. An entry is added each time
+ # `Namespace.declare_class` is called.
+ #
+ # Note: In the graph, there is no direct link between a namespace and a
+ # class. It is the role of a module (created internally by a `FileCompound`)
+ # to link a class with its namespace. So, this collection is used by modules
+ # to know which class in a file belong to their related namespace. It is
+ # also used by `FileCompound` to detect classes in the root namespace.
+ var class_to_ns: Map[String, Namespace] is noinit
+
# Initialize a new project graph using the specified project name.
#
# The specified name will label all nodes of the project’s graph.
- init(name: String) do
- project.labels.add(name)
+ init do
+ project.labels.add(project_name)
project.labels.add("MEntity")
project.labels.add("MProject")
- project["name"] = name
+ project["name"] = project_name
all_nodes.add(project)
var root = new RootNamespace(self)
root.put_in_graph
by_id[""] = root
+ class_to_ns = new DefaultMap[String, Namespace](root)
end
# Request to all nodes in the graph to add their related edges.
+ #
+ # Note: For the rare cases where a node need to wait the `put_edges` to add
+ # an implicit node, this method makes sure to call the `put_edges` method
+ # of the newly added nodes only after processing all the nodes that was
+ # already there.
fun put_edges do
+ all_edges.clear
add_edge(project, "ROOT", by_id[""])
for n in all_nodes do
if n isa Entity then
var model_id: String = "" is writable
# Associated documentation.
- var doc: JsonArray = new JsonArray is writable
+ var doc = new JsonArray is writable
init do
- self.labels.add(graph.project["name"].to_s)
+ self.labels.add(graph.project_name)
self.labels.add("MEntity")
end
#
# Also set `name` using `name_separator`.
fun full_name=(full_name: String) do
- var m: nullable Match = full_name.search_last(name_separator)
+ var m = full_name.search_last(name_separator)
self["full_name"] = full_name
if m == null then
# Set the full name using the current name and the specified parent name.
fun parent_name=(parent_name: String) do
- self["full_name"] = parent_name + name_separator + self["name"].as(not null).to_s
+ if parent_name.is_empty then
+ self["full_name"] = name
+ else
+ self["full_name"] = parent_name + name_separator + name
+ end
end
# Set the location of the entity in the source code.
# Declare an inner namespace.
#
+ # Note: Althought Doxygen indicates that the name is optional,
+ # declarations with an empty name are not supported yet, except for the root
+ # namespace. For the root namespace, both arguments are empty.
+ #
# Parameters:
#
# * `id`: `model_id` of the inner namespace. May be empty.
- # * `name`: string identifying the inner namespace. May be empty.
- fun declare_namespace(id: String, name: String) do end
+ # * `full_name`: qualified name of the inner namespace. Use an empty name
+ # for the root namespace.
+ fun declare_namespace(id: String, full_name: String) do end
# Declare an inner class.
#
+ # Note: Althought Doxygen indicates that both arguments are optional,
+ # declarations with an empty ID are not supported yet.
+ #
# Parameters:
#
- # * `id`: `model_id` of the inner class. May be empty.
- # * `name`: string identifying the inner class. May be empty.
- fun declare_class(id: String, name: String) do end
+ # * `id`: `model_id` of the inner class.
+ # * `full_name`: qualified name of the inner class. Ignored in practice.
+ # * `prot`: visibility (proctection).
+ #
+ # TODO: Handle cases where only the `full_name` is available.
+ fun declare_class(id: String, full_name: String, prot: String) do end
# Declare a base compound (usually, a base class).
#
# Parameters:
#
# * `id`: `model_id` of the base compound. May be empty.
- # * `name`: string identifying the base compound. May be empty.
+ # * `full_name`: qualified name of the base compound. May be empty.
# * `prot`: visibility (proctection) of the relationship.
# * `virt`: level of virtuality of the relationship.
- fun declare_super(id: String, name: String, prot: String, virt: String) do end
+ fun declare_super(id: String, full_name: String, prot: String,
+ virt: String) do end
end
# An unrecognized compound.
class Namespace
super Compound
- # Inner namespaces (IDs).
+ # The inner namespaces.
#
# Left empty for the root namespace.
- var inner_namespaces: SimpleCollection[String] = new Array[String]
+ var inner_namespaces: SimpleCollection[NamespaceRef] = new Array[NamespaceRef]
init do
super
self.labels.add("MGroup")
end
- redef fun declare_namespace(id: String, name: String) do
- inner_namespaces.add(id)
+ redef fun declare_namespace(id: String, full_name: String) do
+ inner_namespaces.add new NamespaceRef(id, full_name)
+ end
+
+ redef fun declare_class(id: String, full_name: String, prot: String) do
+ graph.class_to_ns[id] = self
+ end
+
+ redef fun put_in_graph do
+ super
+ var full_name = self["full_name"]
+ if full_name isa String then graph.namespaces[full_name] = self
end
redef fun put_edges do
graph.add_edge(root, "NESTS", self)
end
for ns in inner_namespaces do
- var node = graph.by_id[ns]
+ var node = ns.seek_in(graph)
graph.add_edge(node, "PARENT", self)
graph.add_edge(self, "NESTS", node)
end
end
end
+# A reference to a namespace.
+class NamespaceRef
+ # The `model_id` of the target.
+ #
+ # Empty when unknown or for the root namespace.
+ var model_id: String
+
+ # The `full_name` of the target.
+ #
+ # Empty only for the root namespace.
+ var full_name: String
+
+ # Look for the targeted namespace in the specified graph.
+ fun seek_in(graph: ProjectGraph): Namespace do
+ var ns_compound: Namespace
+
+ if model_id.is_empty and not full_name.is_empty then
+ # ID unspecified. => We have to look by name
+ assert graph.namespaces.has_key(full_name) else
+ sys.stderr.write "Namespace `{full_name}` not found."
+ end
+ ns_compound = graph.namespaces[full_name]
+ else
+ ns_compound = graph.by_id[model_id].as(Namespace)
+ end
+ return ns_compound
+ end
+end
+
# The root namespace of a `ProjectGraph`.
#
# This the only entity in the graph whose `model_id` is really `""`.
--- /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.
+
+# Adds the possibility to define inner classses.
+module model::inner_class
+
+import member
+import class_compound
+
+# An inner class.
+class InnerClass
+ super MemberOrInner
+
+ redef type INTRODUCER_TYPE: InnerClassIntroducer
+
+ # The outer class definition.
+ #
+ # Used to correct the short name of the inner class definition when
+ # `put_edges` is called.
+ #
+ # SEE: The notice concerning `name` in `/src/neo.nit`.
+ var outer: ClassDef
+
+ # The `model_id` of the actual inner class (`ClassCompound`).
+ var inner: String
+
+ init do
+ super
+ self.labels.add("MInnerClassDef")
+ end
+
+ redef fun is_intro do return true
+ redef fun create_introducer do return new InnerClassIntroducer(graph, self)
+ redef fun resolve_introducer do return introducer
+
+ redef fun put_edges do
+ super
+ var inner = graph.by_id[self.inner]
+ assert inner isa ClassCompound
+ var inner_def = inner.class_def
+ # Correct the short name of `inner` to avoid name collisions in a module.
+ inner_def.name = "{outer.name}{ns_separator}{name}"
+ graph.add_edge(self, "NESTS", inner_def)
+ end
+end
+
+# A `MProperty` node for an inner class.
+class InnerClassIntroducer
+ super MemberIntroducer
+
+ # The definition.
+ var def: InnerClass
+
+ init do
+ super
+ self.labels.add("MInnerClass")
+ end
+
+ redef fun put_edges do
+ super
+ var inner = graph.by_id[def.inner]
+ assert inner isa ClassCompound
+ var outer = def.outer.class_compound
+ # Correct the short name of `inner` to avoid name collisions in a module.
+ inner.name = "{outer.name}{ns_separator}{name}"
+ graph.add_edge(self, "NESTS", inner)
+ end
+end
+
+# Implements `declare_class`.
+redef class ClassCompound
+ redef fun declare_class(id, full_name, prot) do
+ class_def.declare_class(id, full_name, prot)
+ end
+end
+
+# Implements `declare_class`.
+redef class ClassDef
+
+ # The set of the defined inner classes.
+ #
+ # All `InnerClass` entities registred here are automatically added to the
+ # graph with the `ClassDef`.
+ #
+ # To ensure that the `full_name` of each `InnerClass` entity is correctly
+ # set and that each inner class will be correctly linked, `declare_class`
+ # should be used to add each inner class.
+ var inner_classes: SimpleCollection[InnerClass] = new Array[InnerClass]
+
+ # Declare an inner class.
+ #
+ # Parameters:
+ #
+ # * `id`: `model_id` of the inner class definition.
+ # * `full_name`: qualified name of the inner class definition.
+ # * `prot`: visibility (proctection).
+ fun declare_class(id: String, full_name: String, prot: String) do
+ var member = new InnerClass(graph, self, id)
+ member.full_name = full_name
+ member.visibility = prot
+ members.add member
+ inner_classes.add member
+ end
+
+ redef fun put_in_graph do
+ super
+ for member in inner_classes do
+ member.put_in_graph
+ end
+ end
+end
class Location
super Jsonable
+ # The file’s path.
var path: nullable String = null is writable
+
+ # The one-based index of the first line.
var line_start: Int = 1 is writable
+
+ # The one-based index of the last line.
var line_end: Int = 1 is writable
+
+ # The one-based column index of the first character.
var column_start: Int = 1 is writable
+
+ # The one-based column index of the last character.
var column_end: Int = 1 is writable
redef fun to_s: String do
import graph
import type_entity
-# A member.
-abstract class Member
+# A member or an inner class.
+abstract class MemberOrInner
super CodeBlock
+ # The type of the introducer.
+ type INTRODUCER_TYPE: MemberIntroducer
+
# The node used to represent the `MProperty` node.
#
# Only defined if `self` is at the root of a reimplementation graph, and
# only once `put_in_graph` is called.
- var introducer: nullable MemberIntroducer = null
-
- # Members that this member redefines/reimplements.
- var reimplemented: SimpleCollection[String] = new Array[String]
+ var introducer: nullable INTRODUCER_TYPE = null
init do
super
self.labels.add("MPropDef")
end
- # Set the static type.
- fun static_type=(static_type: nullable TypeEntity) is abstract
-
- # Get the static type.
- fun static_type: nullable TypeEntity is abstract
-
- # Append the specified parameter to the signature.
- fun add_parameter(parameter: MemberParameter) do end
-
- # Append a member that is reimplemeneted by `self`.
- fun reimplement(parent: String) do
- reimplemented.add(parent)
- end
-
# Does this member introduce the property?
- fun is_intro: Bool do
- return reimplemented.length <= 0
- end
+ fun is_intro: Bool is abstract
redef fun put_in_graph do
super
end
end
+ # Get the visibility.
+ #
+ # Return `""` by default.
+ fun visibility: String do
+ var visibility = self["visibility"]
+ if visibility isa String then return visibility
+ return ""
+ end
+
redef fun name=(name: String) do
super
if introducer != null then
end
end
+ # Create an instance of `MemberIntroducer` that will be linked to `self`.
+ protected fun create_introducer: INTRODUCER_TYPE is abstract
+
+ # Find the nearest reimplementation root.
+ fun resolve_introducer: nullable INTRODUCER_TYPE is abstract
+end
+
+# A member.
+abstract class Member
+ super MemberOrInner
+
+ # Members that this member redefines/reimplements.
+ var reimplemented: SimpleCollection[String] = new Array[String]
+
+ # Set the static type.
+ fun static_type=(static_type: nullable TypeEntity) is abstract
+
+ # Get the static type.
+ fun static_type: nullable TypeEntity is abstract
+
+ # Append the specified parameter to the signature.
+ fun add_parameter(parameter: MemberParameter) do end
+
+ # Append a member that is reimplemeneted by `self`.
+ fun reimplement(parent: String) do
+ reimplemented.add(parent)
+ end
+
+ redef fun is_intro do return reimplemented.length <= 0
+
# Is the member abstract?
fun is_abstract=(is_abstract: Bool) do
self["is_abstract"] = is_abstract
end
- # Create an instance of `MemberIntroducer` that will be linked to `self`.
- protected fun create_introducer: MemberIntroducer is abstract
-
# Find the nearest reimplementation root.
#
# var g = new ProjectGraph("foo")
# m3.reimplement("3")
# m3.put_in_graph
# assert m3.resolve_introducer == null
- fun resolve_introducer: nullable MemberIntroducer do
+ redef fun resolve_introducer do
if introducer == null then
var member_queue = new List[String]
var visited = new HashSet[Member]
redef fun put_edges do end
end
+# A local definition of a method.
class Method
super Member
+ redef type INTRODUCER_TYPE: MethodIntroducer
+
# The method’s signature.
var signature: Signature is noinit, writable
signature.parameters.add(parameter)
end
- redef fun create_introducer: MemberIntroducer do
- return new MethodIntroducer(graph)
- end
+ redef fun create_introducer do return new MethodIntroducer(graph)
redef fun put_in_graph do
super
end
end
+# A local definition of an attribute.
class Attribute
super Member
+ redef type INTRODUCER_TYPE: AttributeIntroducer
+
# The declared type.
redef var static_type: nullable TypeEntity = null is writable
self.labels.add("MAttributeDef")
end
- redef fun create_introducer: MemberIntroducer do
- return new AttributeIntroducer(graph)
- end
+ redef fun create_introducer do return new AttributeIntroducer(graph)
redef fun put_in_graph do
super
self["visibility"] = "public"
end
+ # Set the visibility.
fun visibility=(visibility: String) do
self["visibility"] = visibility
end
+
+ # Get the visibility.
+ #
+ # Return `""` by default.
+ fun visibility: String do
+ var visibility = self["visibility"]
+ if visibility isa String then return visibility
+ return ""
+ end
end
# A `MProperty` node for a method.
import class_compound
import module_compound
import member
+import inner_class
# Creates one modules by inner namespace. The full name of the modules begin
# with the namespace’s full name, and end with the unqualified name of the file,
# without the extension.
+#
+# Note: If a module associated to the root namespace is needed, it is added to
+# the graph only when `put_edges` is called.
class FileCompound
super Compound
super CodeBlock
- # Mapping between inner namespace’s names and corresponding modules.
- private var inner_namespaces: Map[String, Module] = new HashMap[String, Module]
+ # Modules corresponding to the namespaces defined/redefined in the file.
+ private var inner_namespaces = new Array[Module]
+
+ # `model_id` of the classes declared in the file.
+ private var inner_classes = new Array[String]
# The last component of the path, without the extension.
#
if location != null and location.path != null then
full_name = location.path.as(not null)
end
- for m in inner_namespaces.values do m.location = location
+ for m in inner_namespaces do m.location = location
end
redef fun name=(name: String) do
basename = name.substring(0, match.from)
end
# Update the modules’ name.
- for ns, m in inner_namespaces do
- m.full_name = "{ns}{ns_separator}{basename}"
- end
+ for m in inner_namespaces do m.update_name
end
- redef fun declare_namespace(id: String, name: String) do
+ redef fun declare_namespace(id: String, full_name: String) do
var m: Module
- if inner_namespaces.keys.has(name) then
- m = inner_namespaces[name]
- if id != "" then m.parent = id
- else
- m = new Module(graph)
- m.full_name = "{name}{ns_separator}{basename}"
- m.parent = id
- m.location = self["location"].as(nullable Location)
- inner_namespaces[name] = m
+ assert not full_name.is_empty or id.is_empty else
+ sys.stderr.write "Inner mamespace declarations without name are not yet supported (except for the root namespace).\n"
end
+ m = new Module(graph, self, new NamespaceRef(id, full_name))
+ m.location = self["location"].as(nullable Location)
+ inner_namespaces.add m
end
- redef fun declare_class(id: String, name: String) do
- var match = name.search_last(ns_separator)
- var ns_name: String
- var m: Module
-
- if match == null then
- ns_name = ""
- else
- ns_name = name.substring(0, match.from)
- end
- if inner_namespaces.keys.has(ns_name) then
- m = inner_namespaces[ns_name]
- else
- declare_namespace("", ns_name)
- m = inner_namespaces[ns_name]
+ redef fun declare_class(id, full_name, prot) do
+ assert not id.is_empty else
+ sys.stderr.write "Inner class declarations without ID are not yet supported.\n"
end
- m.declare_class(id, name)
+ inner_classes.add id
end
redef fun put_in_graph do
# Do not add `self` to the Neo4j graph...
# ... but add its modules...
- for m in inner_namespaces.values do m.put_in_graph
- # ... and add `self` to the index.
+ for m in inner_namespaces do m.put_in_graph
+ # ... and add `self` to the indexes.
if model_id != "" then graph.by_id[model_id] = self
+ graph.files.add self
+ end
+
+ # If the file contains some classes in the root namespace, add an implicit
+ # module to handle them.
+ #
+ # This method is called by `ProjectGraph.add_global_modules` and assumes
+ # that all the namespaces are already fully set and put in the graph.
+ fun declare_root_namespace do
+ if has_globals then
+ declare_namespace("", "")
+ inner_namespaces.last.put_in_graph
+ end
+ end
+
+ # Does this file contain classes in the root namespace?
+ private fun has_globals: Bool do
+ var root = graph.by_id[""]
+ for c in inner_classes do
+ if graph.class_to_ns[c] == root then return true
+ end
+ return false
end
end
-# A module.
-class Module
+# A `MModule` node.
+#
+# For each file, there is one module by inner namespace.
+private class Module
super Compound
super CodeBlock
- # The `model_id` of the parent namespace.
- var parent: String = "" is writable
+ # The file that declares the module.
+ var file_compound: FileCompound
- # The classes defined in the module.
- var inner_classes: SimpleCollection[String] = new Array[String]
+ # The namespace defined or redefined by the module.
+ var namespace: NamespaceRef
init do
super
self.labels.add("MModule")
+ update_name
end
- redef fun declare_class(id: String, name: String) do
- inner_classes.add(id)
+ # Update the `full_name` and the `name`.
+ #
+ # Update the short name of the module to the `basename` of the file that
+ # declares it.
+ fun update_name do
+ name = file_compound.basename
+ parent_name = namespace.full_name
end
redef fun put_edges do
- graph.add_edge(graph.by_id[parent], "DECLARES", self)
- for c in inner_classes do
- var node = graph.by_id[c].as(ClassCompound)
- graph.add_edge(self, "INTRODUCES", node)
- graph.add_edge(self, "DEFINES", node.class_def)
+ var ns_compound = namespace.seek_in(graph)
+ graph.add_edge(ns_compound, "DECLARES", self)
+
+ for c in file_compound.inner_classes do
+ if graph.class_to_ns[c] != ns_compound then continue
+ var class_compound = graph.by_id[c].as(ClassCompound)
+ graph.add_edge(self, "INTRODUCES", class_compound)
+ graph.add_edge(self, "DEFINES", class_compound.class_def)
end
end
end
+
+# Adds the `add_global_modules` phase to `ProjectGraph`.
+redef class ProjectGraph
+
+ # Project’s source files.
+ var files: SimpleCollection[FileCompound] = new Array[FileCompound]
+
+ # Add the modules that define the root namespace.
+ #
+ # **Must** be called before any call to `put_edges`, and after all the
+ # namespaces are fully set and put in the graph.
+ #
+ # Note: This method is not idempotent so it has to be called only once.
+ fun add_global_modules do
+ for f in files do f.declare_root_namespace
+ end
+end
import model
import doxml
+import graph_store
import console
+import flush_stdout
import opts
# An importation task.
class NeoDoxygenJob
- var client: Neo4jClient
- var model: ProjectGraph is noinit
- # How many operation can be executed in one batch?
- private var batch_max_size = 1000
+ # The storage medium to use.
+ var store: GraphStore
+
+ # The loaded project graph.
+ var model: ProjectGraph is noinit
- private var save_cursor: String = (new TermSaveCursor).to_s
+ # Escape control sequence to save the cursor position.
+ private var term_save_cursor: String = (new TermSaveCursor).to_s
- # Escape control sequence to reset the current line.
- private var reset_line: String = "{new TermRestoreCursor}{new TermEraseDisplayDown}"
+ # Escape control sequence to rewind to the last saved cursor position.
+ private var term_rewind: String = "{new TermRestoreCursor}{new TermEraseDisplayDown}"
# Generate a graph from the specified project model.
#
fun load_project(name: String, dir: String, source: SourceLanguage) do
check_name name
model = new ProjectGraph(name)
- # TODO Let the user select the language.
var reader = new CompoundFileReader(model, source)
# Queue for sub-directories.
var directories = new Array[String]
+ var file_count = 0
- if dir.length > 1 and dir.chars.last == "/" then
- dir = dir.substring(0, dir.length - 1)
+ if dir == "" then
+ printn "Reading the current directory... "
+ else
+ printn "Reading {dir}... "
end
- sys.stdout.write save_cursor
+ flush_stdout
loop
- for f in dir.files do
+ for f in list_files(dir) do
var path = dir/f
if path.file_stat.is_dir then
directories.push(path)
else if f.has_suffix(".xml") and f != "index.xml" then
- print "{reset_line}Reading {path}..."
reader.read(path)
+ file_count += 1
end
end
if directories.length <= 0 then break
dir = directories.pop
end
- print "{reset_line}Reading... Done."
+ model.add_global_modules
+ print "Done."
+ if file_count < 2 then
+ print "{file_count} file read."
+ else
+ print "{file_count} files read."
+ end
+ flush_stdout
+ end
+
+ # List files in a directory.
+ #
+ # This method may be redefined to force the order in which the files
+ # are read by `load_project`.
+ protected fun list_files(dir: String): Collection[String] do
+ return dir.files
end
# Check the project’s name.
sys.stderr.write("{sys.program_name}: The project’s name must not" +
" begin with an upper case letter. Got `{name}`.\n")
end
- var query = new CypherQuery.from_string("match n where \{name\} in labels(n) return count(n)")
- query.params["name"] = name
- var data = client.cypher(query).as(JsonObject)["data"]
- var result = data.as(JsonArray).first.as(JsonArray).first.as(Int)
- assert name_unused: result == 0 else
+ assert name_unused: not store.has_node_label(name) else
sys.stderr.write("{sys.program_name}: The label `{name}` is already" +
" used in the specified graph.\n")
end
# Save the graph.
fun save do
- print "Linking nodes...{save_cursor}"
+ sys.stdout.write "Linking nodes...{term_save_cursor} "
+ flush_stdout
model.put_edges
- print "{reset_line} Done."
+ print "{term_rewind} Done."
var nodes = model.all_nodes
- print "Saving {nodes.length} nodes...{save_cursor}"
- push_all(nodes)
+ sys.stdout.write "Saving {nodes.length} nodes..."
+ store.save_all(nodes)
var edges = model.all_edges
- print "Saving {edges.length} edges...{save_cursor}"
- push_all(edges)
- end
-
- # Save `neo_entities` in the database using batch mode.
- private fun push_all(neo_entities: Collection[NeoEntity]) do
- var batch = new NeoBatch(client)
- var len = neo_entities.length
- var sum = 0
- var i = 1
-
- for nentity in neo_entities do
- batch.save_entity(nentity)
- if i == batch_max_size then
- do_batch(batch)
- sum += batch_max_size
- print("{reset_line} {sum * 100 / len}%")
- batch = new NeoBatch(client)
- i = 1
- else
- i += 1
- end
- end
- do_batch(batch)
- print("{reset_line} Done.")
- end
-
- # Execute `batch` and check for errors.
- #
- # Abort if `batch.execute` returns errors.
- private fun do_batch(batch: NeoBatch) do
- var errors = batch.execute
- if not errors.is_empty then
- for e in errors do sys.stderr.write("{sys.program_name}: {e}\n")
- exit(1)
- end
+ sys.stdout.write "Saving {edges.length} edges..."
+ store.save_all(edges)
end
end
opt_dest.default_value = default_dest
option_context.add_option(opt_dest)
+ opt_help = new OptionBool("Show the help (this page).",
+ "-h", "--help")
+ option_context.add_option(opt_help)
+
var keys = new Array[String].from(sources.keys)
opt_src_lang = new OptionEnum(keys,
"The programming language to assume when processing chunk in the declarations left as-is by Doxygen. Use `any` (the default) to disable any language-specific processing.",
keys.index_of("any"), "--src-lang")
option_context.add_option(opt_src_lang)
-
- opt_help = new OptionBool("Show the help (this page).",
- "-h", "--help")
- option_context.add_option(opt_help)
end
# Start the application.
var dest = opt_dest.value
var project_name = rest[0]
var dir = rest[1]
- var neo = new NeoDoxygenJob(new Neo4jClient(dest or else default_dest))
+ var neo = new NeoDoxygenJob(create_store(dest or else default_dest))
neo.load_project(project_name, dir, source)
neo.save
return 0
end
+ # Create an instance of `GraphStore` for the specified destination.
+ protected fun create_store(dest: String): GraphStore do
+ return new Neo4jStore(new Neo4jClient(dest))
+ end
+
# Show the help.
fun show_help do
option_context.usage
--- /dev/null
+Test scripts for `neo_doxygen`.
+
+The name of each test script is prefixed by `neo_doxygen_` to avoid name
+conflicts in `/tests/sav` and `/tests/out`. The expected output of each script
+is saved as a `*.res` file in `/tests/sav`.
+
+Note: All paths indicated here are relative to the root of the repository.
--- /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.
+
+# A variant of the `neo_doxygen` program that produces a debugging output of the graph instead of saving it.
+#
+# Note: The `--dest` option is ignored.
+module tests::neo_doxygen_dump
+
+import tests
+import neo_doxygen
+
+redef class Sys
+ redef fun program_name do return "%PROGRAM_NAME%"
+end
+
+redef class NeoDoxygenJob
+ redef fun list_files(dir) do
+ var a = super.to_a
+ default_comparator.sort(a)
+ return a
+ end
+end
+
+redef class NeoDoxygenCommand
+ redef fun create_store(url) do return new DebugStore
+end
+
+# Dummy storage medium that write a debugging output to the standard output.
+#
+# For testing purposes only.
+class DebugStore
+ super GraphStore
+
+ redef fun has_node_label(name) do return false
+
+ redef fun save_all(neo_entities) do
+ print ""
+ for n in neo_entities do
+ if n isa NeoEdge then
+ var buffer = new RopeBuffer
+ n.debug buffer
+ print buffer
+ end
+ end
+ print "---===DONE===---"
+ end
+end
--- /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.
+
+import tests
+import model::module_compound
+
+var graph = new ProjectGraph("foo")
+var file = new FileCompound(graph)
+var file_2 = new FileCompound(graph)
+var bar_class = new ClassCompound(graph)
+var baz_class = new ClassCompound(graph)
+var a_ns = new Namespace(graph)
+var b_ns = new Namespace(graph)
+var c_ns = new Namespace(graph)
+var d_ns = new Namespace(graph)
+var buffer = new RopeBuffer
+
+file.full_name = "Bar.java"
+file.model_id = "_Bar_8java"
+file.declare_class("classa_b_bar", "a::b::Bar", "package")
+file.declare_class("classbaz", "Baz", "")
+file.declare_namespace("", "a::b")
+file.put_in_graph
+
+file_2.full_name = "Bar.java"
+file_2.model_id = "_Bar_8java_2"
+file_2.declare_namespace("namespacec", "c")
+file_2.declare_namespace("", "d")
+file_2.put_in_graph
+
+bar_class.model_id = "classa_b_bar"
+bar_class.full_name = "a::b::Bar"
+bar_class.put_in_graph
+
+baz_class.model_id = "classbaz"
+baz_class.full_name = "Baz"
+baz_class.put_in_graph
+
+a_ns.full_name = "a"
+a_ns.declare_namespace("", "a::b")
+a_ns.put_in_graph
+
+b_ns.full_name = "a::b"
+b_ns.declare_class("classa_b_bar", "", "")
+b_ns.put_in_graph
+
+c_ns.model_id = "namespacec"
+c_ns.full_name = "c"
+c_ns.put_in_graph
+
+d_ns.model_id = "namespaced"
+d_ns.full_name = "d"
+d_ns.put_in_graph
+
+print "---===WITHOUT GLOBALS===---"
+graph.put_edges
+graph.debug buffer
+print buffer
+
+print "---===WITH GLOBALS===---"
+buffer.clear
+graph.add_global_modules
+graph.put_edges
+graph.debug buffer
+print buffer
--- /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.
+
+import tests
+
+var graph = new ProjectGraph("foo")
+var buffer = new RopeBuffer
+
+graph.put_edges
+graph.debug buffer
+print buffer
--- /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.
+
+import model::member
+
+# Copied from the documentation of `Member::resolve_introducer`.
+
+var g = new ProjectGraph("foo")
+var m1 = new Attribute(g)
+var m2 = new Attribute(g)
+var m3 = new Attribute(g)
+
+m1.model_id = "1"
+m1.put_in_graph
+m2.reimplement("1")
+m2.put_in_graph
+assert m1.resolve_introducer == m1.introducer
+assert m2.resolve_introducer == m1.introducer
+
+m3.model_id = "3"
+m3.reimplement("3")
+m3.put_in_graph
+assert m3.resolve_introducer == null
--- /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.
+
+# Base module for tests related to `neo_doxygen`.
+module tests::tests
+
+import model::graph
+
+# Adds debugging output to graphs.
+redef class NeoGraph
+
+ # Append the debugging output of all relationships to the specified buffer.
+ fun debug(buffer: Buffer) do
+ buffer.append "# Graph\n"
+ for edge in all_edges do
+ edge.debug buffer
+ end
+ end
+end
+
+# Adds debugging output to relationships.
+redef class NeoEdge
+
+ # Append the debugging output of this relationship to the specified buffer.
+ #
+ # Append the relationship type, the properties, and the debugging output of
+ # both extremities.
+ fun debug(buffer: Buffer) do
+ var rel_type = self.rel_type or else "?"
+ buffer.append "Edge\n"
+ buffer.append "=type={rel_type.length}:{rel_type}\n"
+ buffer.append "=properties=JsonObject({properties.length}):\n"
+ buffer.append properties.to_json
+ buffer.append "\n----\n=from="
+ from.debug buffer
+ buffer.append "----\n=to="
+ to.debug buffer
+ buffer.append "\n"
+ end
+end
+
+# Adds debugging output to nodes.
+redef class NeoNode
+
+ # Append the debugging output of this node to the specified buffer.
+ #
+ # Append the labels and the properties.
+ fun debug(buffer: Buffer) do
+ buffer.append "Node\n"
+ buffer.append "=labels=Array({labels.length}):\n"
+ for lab in labels do buffer.append "{lab.length}:{lab}\n"
+ buffer.append "=properties=JsonObject({properties.length}):\n"
+ buffer.append properties.to_json
+ buffer.append "\n"
+ end
+end
+
+# Adds debugging output to entities.
+redef class Entity
+
+ # Append the debugging output of this entity to the specified buffer.
+ #
+ # Append the `model_id`, the labels and the properties.
+ redef fun debug(buffer: Buffer) do
+ buffer.append "Entity#{model_id.length}:{model_id}\n"
+ buffer.append "=labels=Array({labels.length}):\n"
+ for lab in labels do buffer.append "{lab.length}:{lab}\n"
+ buffer.append "=properties=JsonObject({properties.length}):\n"
+ buffer.append properties.to_json
+ buffer.append "\n"
+ end
+end
--- /dev/null
+/*/xml/* -diff
--- /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.
+
+# All the dummy projects.
+PROJECTS=$(dir $(wildcard ./*/Doxyfile))
+
+.PHONY: xml bootstrap
+
+# Regenerate the XML documents.
+xml: bootstrap
+ for p in $(PROJECTS); do $(MAKE) -C "$$p" xml || exit; done
+
+# Generate the Makefiles in the sub-directories.
+bootstrap:
+ for p in $(PROJECTS); do { \
+ echo '# FILE GENERATED BY ../Makefile'"\n" > "$$p/Makefile" || exit; \
+ cat doxyproject.mk >> "$$p/Makefile" || exit; \
+ } ; done
--- /dev/null
+Data files for tests.
+
+For test scripts, see `../src/tests`. To regenerate the XML documents, run
+`make`.
--- /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.
+
+.PHONY: clean doxygen strip_paths xml
+
+# Regenerate the XML documents.
+xml: strip_paths
+
+clean:
+ rm -rf xml
+
+doxygen: clean
+ doxygen Doxyfile
+
+# Get rid of the absolute paths in the generated files.
+#
+# Doxygen ignores the `STRIP_FROM_PATH` setting when generating a XML output.
+# So, we have to replace the paths manually in order to get reproducible
+# results.
+#
+# WARNING: FOR USE ON TEST DATA ONLY.
+strip_paths: doxygen
+ . ../../sh-lib/more_sed.sh; \
+ replace `readlink -f -- ./src` '%SOURCE_DIRECTORY%' xml/*.xml
--- /dev/null
+# Doxyfile 1.8.8
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project.
+#
+# All text after a double hash (##) is considered a comment and is placed in
+# front of the TAG it is preceding.
+#
+# All text after a single hash (#) is considered a comment and will be ignored.
+# The format is:
+# TAG = value [value, ...]
+# For lists, items can also be appended using:
+# TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (\" \").
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# This tag specifies the encoding used for all characters in the config file
+# that follow. The default is UTF-8 which is also the encoding used for all text
+# before the first occurrence of this tag. Doxygen uses libiconv (or the iconv
+# built into libc) for the transcoding. See http://www.gnu.org/software/libiconv
+# for the list of possible encodings.
+# The default value is: UTF-8.
+
+DOXYFILE_ENCODING = UTF-8
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by
+# double-quotes, unless you are using Doxywizard) that should identify the
+# project for which the documentation is generated. This name is used in the
+# title of most generated pages and in a few other places.
+# The default value is: My Project.
+
+PROJECT_NAME = "Test Project"
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number. This
+# could be handy for archiving the generated documentation or if some version
+# control system is used.
+
+PROJECT_NUMBER =
+
+# Using the PROJECT_BRIEF tag one can provide an optional one line description
+# for a project that appears at the top of each page and should give viewer a
+# quick idea about the purpose of the project. Keep the description short.
+
+PROJECT_BRIEF =
+
+# With the PROJECT_LOGO tag one can specify a logo or an icon that is included
+# in the documentation. The maximum height of the logo should not exceed 55
+# pixels and the maximum width should not exceed 200 pixels. Doxygen will copy
+# the logo to the output directory.
+
+PROJECT_LOGO =
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path
+# into which the generated documentation will be written. If a relative path is
+# entered, it will be relative to the location where doxygen was started. If
+# left blank the current directory will be used.
+
+OUTPUT_DIRECTORY =
+
+# If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub-
+# directories (in 2 levels) under the output directory of each output format and
+# will distribute the generated files over these directories. Enabling this
+# option can be useful when feeding doxygen a huge amount of source files, where
+# putting all generated files in the same directory would otherwise causes
+# performance problems for the file system.
+# The default value is: NO.
+
+CREATE_SUBDIRS = NO
+
+# If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII
+# characters to appear in the names of generated files. If set to NO, non-ASCII
+# characters will be escaped, for example _xE3_x81_x84 will be used for Unicode
+# U+3044.
+# The default value is: NO.
+
+ALLOW_UNICODE_NAMES = NO
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all
+# documentation generated by doxygen is written. Doxygen will use this
+# information to generate all constant output in the proper language.
+# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese,
+# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States),
+# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian,
+# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages),
+# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian,
+# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian,
+# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish,
+# Ukrainian and Vietnamese.
+# The default value is: English.
+
+OUTPUT_LANGUAGE = English
+
+# If the BRIEF_MEMBER_DESC tag is set to YES, doxygen will include brief member
+# descriptions after the members that are listed in the file and class
+# documentation (similar to Javadoc). Set to NO to disable this.
+# The default value is: YES.
+
+BRIEF_MEMBER_DESC = YES
+
+# If the REPEAT_BRIEF tag is set to YES, doxygen will prepend the brief
+# description of a member or function before the detailed description
+#
+# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
+# brief descriptions will be completely suppressed.
+# The default value is: YES.
+
+REPEAT_BRIEF = YES
+
+# This tag implements a quasi-intelligent brief description abbreviator that is
+# used to form the text in various listings. Each string in this list, if found
+# as the leading text of the brief description, will be stripped from the text
+# and the result, after processing the whole list, is used as the annotated
+# text. Otherwise, the brief description is used as-is. If left blank, the
+# following values are used ($name is automatically replaced with the name of
+# the entity):The $name class, The $name widget, The $name file, is, provides,
+# specifies, contains, represents, a, an and the.
+
+ABBREVIATE_BRIEF = "The $name class" \
+ "The $name widget" \
+ "The $name file" \
+ is \
+ provides \
+ specifies \
+ contains \
+ represents \
+ a \
+ an \
+ the
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
+# doxygen will generate a detailed section even if there is only a brief
+# description.
+# The default value is: NO.
+
+ALWAYS_DETAILED_SEC = NO
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
+# inherited members of a class in the documentation of that class as if those
+# members were ordinary class members. Constructors, destructors and assignment
+# operators of the base classes will not be shown.
+# The default value is: NO.
+
+INLINE_INHERITED_MEMB = NO
+
+# If the FULL_PATH_NAMES tag is set to YES, doxygen will prepend the full path
+# before files name in the file list and in the header files. If set to NO the
+# shortest path that makes the file name unique will be used
+# The default value is: YES.
+
+FULL_PATH_NAMES = YES
+
+# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path.
+# Stripping is only done if one of the specified strings matches the left-hand
+# part of the path. The tag can be used to show relative paths in the file list.
+# If left blank the directory from which doxygen is run is used as the path to
+# strip.
+#
+# Note that you can specify absolute paths here, but also relative paths, which
+# will be relative from the directory where doxygen is started.
+# This tag requires that the tag FULL_PATH_NAMES is set to YES.
+
+STRIP_FROM_PATH =
+
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the
+# path mentioned in the documentation of a class, which tells the reader which
+# header file to include in order to use a class. If left blank only the name of
+# the header file containing the class definition is used. Otherwise one should
+# specify the list of include paths that are normally passed to the compiler
+# using the -I flag.
+
+STRIP_FROM_INC_PATH =
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but
+# less readable) file names. This can be useful is your file systems doesn't
+# support long names like on DOS, Mac, or CD-ROM.
+# The default value is: NO.
+
+SHORT_NAMES = NO
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the
+# first line (until the first dot) of a Javadoc-style comment as the brief
+# description. If set to NO, the Javadoc-style will behave just like regular Qt-
+# style comments (thus requiring an explicit @brief command for a brief
+# description.)
+# The default value is: NO.
+
+JAVADOC_AUTOBRIEF = NO
+
+# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first
+# line (until the first dot) of a Qt-style comment as the brief description. If
+# set to NO, the Qt-style will behave just like regular Qt-style comments (thus
+# requiring an explicit \brief command for a brief description.)
+# The default value is: NO.
+
+QT_AUTOBRIEF = NO
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a
+# multi-line C++ special comment block (i.e. a block of //! or /// comments) as
+# a brief description. This used to be the default behavior. The new default is
+# to treat a multi-line C++ comment block as a detailed description. Set this
+# tag to YES if you prefer the old behavior instead.
+#
+# Note that setting this tag to YES also means that rational rose comments are
+# not recognized any more.
+# The default value is: NO.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the
+# documentation from any documented member that it re-implements.
+# The default value is: YES.
+
+INHERIT_DOCS = YES
+
+# If the SEPARATE_MEMBER_PAGES tag is set to YES then doxygen will produce a new
+# page for each member. If set to NO, the documentation of a member will be part
+# of the file/class/namespace that contains it.
+# The default value is: NO.
+
+SEPARATE_MEMBER_PAGES = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen
+# uses this value to replace tabs by spaces in code fragments.
+# Minimum value: 1, maximum value: 16, default value: 4.
+
+TAB_SIZE = 4
+
+# This tag can be used to specify a number of aliases that act as commands in
+# the documentation. An alias has the form:
+# name=value
+# For example adding
+# "sideeffect=@par Side Effects:\n"
+# will allow you to put the command \sideeffect (or @sideeffect) in the
+# documentation, which will result in a user-defined paragraph with heading
+# "Side Effects:". You can put \n's in the value part of an alias to insert
+# newlines.
+
+ALIASES =
+
+# This tag can be used to specify a number of word-keyword mappings (TCL only).
+# A mapping has the form "name=value". For example adding "class=itcl::class"
+# will allow you to use the command class in the itcl::class meaning.
+
+TCL_SUBST =
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources
+# only. Doxygen will then generate output that is more tailored for C. For
+# instance, some of the names that are used will be different. The list of all
+# members will be omitted, etc.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_FOR_C = NO
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or
+# Python sources only. Doxygen will then generate output that is more tailored
+# for that language. For instance, namespaces will be presented as packages,
+# qualified scopes will look different, etc.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_JAVA = YES
+
+# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran
+# sources. Doxygen will then generate output that is tailored for Fortran.
+# The default value is: NO.
+
+OPTIMIZE_FOR_FORTRAN = NO
+
+# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL
+# sources. Doxygen will then generate output that is tailored for VHDL.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_VHDL = NO
+
+# Doxygen selects the parser to use depending on the extension of the files it
+# parses. With this tag you can assign which parser to use for a given
+# extension. Doxygen has a built-in mapping, but you can override or extend it
+# using this tag. The format is ext=language, where ext is a file extension, and
+# language is one of the parsers supported by doxygen: IDL, Java, Javascript,
+# C#, C, C++, D, PHP, Objective-C, Python, Fortran (fixed format Fortran:
+# FortranFixed, free formatted Fortran: FortranFree, unknown formatted Fortran:
+# Fortran. In the later case the parser tries to guess whether the code is fixed
+# or free formatted code, this is the default for Fortran type files), VHDL. For
+# instance to make doxygen treat .inc files as Fortran files (default is PHP),
+# and .f files as C (default is Fortran), use: inc=Fortran f=C.
+#
+# Note: For files without extension you can use no_extension as a placeholder.
+#
+# Note that for custom extensions you also need to set FILE_PATTERNS otherwise
+# the files are not read by doxygen.
+
+EXTENSION_MAPPING =
+
+# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments
+# according to the Markdown format, which allows for more readable
+# documentation. See http://daringfireball.net/projects/markdown/ for details.
+# The output of markdown processing is further processed by doxygen, so you can
+# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in
+# case of backward compatibilities issues.
+# The default value is: YES.
+
+MARKDOWN_SUPPORT = YES
+
+# When enabled doxygen tries to link words that correspond to documented
+# classes, or namespaces to their corresponding documentation. Such a link can
+# be prevented in individual cases by putting a % sign in front of the word or
+# globally by setting AUTOLINK_SUPPORT to NO.
+# The default value is: YES.
+
+AUTOLINK_SUPPORT = YES
+
+# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
+# to include (a tag file for) the STL sources as input, then you should set this
+# tag to YES in order to let doxygen match functions declarations and
+# definitions whose arguments contain STL classes (e.g. func(std::string);
+# versus func(std::string) {}). This also make the inheritance and collaboration
+# diagrams that involve STL classes more complete and accurate.
+# The default value is: NO.
+
+BUILTIN_STL_SUPPORT = NO
+
+# If you use Microsoft's C++/CLI language, you should set this option to YES to
+# enable parsing support.
+# The default value is: NO.
+
+CPP_CLI_SUPPORT = NO
+
+# Set the SIP_SUPPORT tag to YES if your project consists of sip (see:
+# http://www.riverbankcomputing.co.uk/software/sip/intro) sources only. Doxygen
+# will parse them like normal C++ but will assume all classes use public instead
+# of private inheritance when no explicit protection keyword is present.
+# The default value is: NO.
+
+SIP_SUPPORT = NO
+
+# For Microsoft's IDL there are propget and propput attributes to indicate
+# getter and setter methods for a property. Setting this option to YES will make
+# doxygen to replace the get and set methods by a property in the documentation.
+# This will only work if the methods are indeed getting or setting a simple
+# type. If this is not the case, or you want to show the methods anyway, you
+# should set this option to NO.
+# The default value is: YES.
+
+IDL_PROPERTY_SUPPORT = YES
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
+# tag is set to YES then doxygen will reuse the documentation of the first
+# member in the group (if any) for the other members of the group. By default
+# all members of a group must be documented explicitly.
+# The default value is: NO.
+
+DISTRIBUTE_GROUP_DOC = NO
+
+# Set the SUBGROUPING tag to YES to allow class member groups of the same type
+# (for instance a group of public functions) to be put as a subgroup of that
+# type (e.g. under the Public Functions section). Set it to NO to prevent
+# subgrouping. Alternatively, this can be done per class using the
+# \nosubgrouping command.
+# The default value is: YES.
+
+SUBGROUPING = YES
+
+# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions
+# are shown inside the group in which they are included (e.g. using \ingroup)
+# instead of on a separate page (for HTML and Man pages) or section (for LaTeX
+# and RTF).
+#
+# Note that this feature does not work in combination with
+# SEPARATE_MEMBER_PAGES.
+# The default value is: NO.
+
+INLINE_GROUPED_CLASSES = NO
+
+# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions
+# with only public data fields or simple typedef fields will be shown inline in
+# the documentation of the scope in which they are defined (i.e. file,
+# namespace, or group documentation), provided this scope is documented. If set
+# to NO, structs, classes, and unions are shown on a separate page (for HTML and
+# Man pages) or section (for LaTeX and RTF).
+# The default value is: NO.
+
+INLINE_SIMPLE_STRUCTS = NO
+
+# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or
+# enum is documented as struct, union, or enum with the name of the typedef. So
+# typedef struct TypeS {} TypeT, will appear in the documentation as a struct
+# with name TypeT. When disabled the typedef will appear as a member of a file,
+# namespace, or class. And the struct will be named TypeS. This can typically be
+# useful for C code in case the coding convention dictates that all compound
+# types are typedef'ed and only the typedef is referenced, never the tag name.
+# The default value is: NO.
+
+TYPEDEF_HIDES_STRUCT = NO
+
+# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This
+# cache is used to resolve symbols given their name and scope. Since this can be
+# an expensive process and often the same symbol appears multiple times in the
+# code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small
+# doxygen will become slower. If the cache is too large, memory is wasted. The
+# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range
+# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536
+# symbols. At the end of a run doxygen will report the cache usage and suggest
+# the optimal cache size from a speed point of view.
+# Minimum value: 0, maximum value: 9, default value: 0.
+
+LOOKUP_CACHE_SIZE = 0
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# If the EXTRACT_ALL tag is set to YES, doxygen will assume all entities in
+# documentation are documented, even if no documentation was available. Private
+# class members and static file members will be hidden unless the
+# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES.
+# Note: This will also disable the warnings about undocumented members that are
+# normally produced when WARNINGS is set to YES.
+# The default value is: NO.
+
+EXTRACT_ALL = NO
+
+# If the EXTRACT_PRIVATE tag is set to YES, all private members of a class will
+# be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PRIVATE = NO
+
+# If the EXTRACT_PACKAGE tag is set to YES, all members with package or internal
+# scope will be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PACKAGE = NO
+
+# If the EXTRACT_STATIC tag is set to YES, all static members of a file will be
+# included in the documentation.
+# The default value is: NO.
+
+EXTRACT_STATIC = NO
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES, classes (and structs) defined
+# locally in source files will be included in the documentation. If set to NO,
+# only classes defined in header files are included. Does not have any effect
+# for Java sources.
+# The default value is: YES.
+
+EXTRACT_LOCAL_CLASSES = YES
+
+# This flag is only useful for Objective-C code. If set to YES, local methods,
+# which are defined in the implementation section but not in the interface are
+# included in the documentation. If set to NO, only methods in the interface are
+# included.
+# The default value is: NO.
+
+EXTRACT_LOCAL_METHODS = NO
+
+# If this flag is set to YES, the members of anonymous namespaces will be
+# extracted and appear in the documentation as a namespace called
+# 'anonymous_namespace{file}', where file will be replaced with the base name of
+# the file that contains the anonymous namespace. By default anonymous namespace
+# are hidden.
+# The default value is: NO.
+
+EXTRACT_ANON_NSPACES = NO
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all
+# undocumented members inside documented classes or files. If set to NO these
+# members will be included in the various overviews, but no documentation
+# section is generated. This option has no effect if EXTRACT_ALL is enabled.
+# The default value is: NO.
+
+HIDE_UNDOC_MEMBERS = NO
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all
+# undocumented classes that are normally visible in the class hierarchy. If set
+# to NO, these classes will be included in the various overviews. This option
+# has no effect if EXTRACT_ALL is enabled.
+# The default value is: NO.
+
+HIDE_UNDOC_CLASSES = NO
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend
+# (class|struct|union) declarations. If set to NO, these declarations will be
+# included in the documentation.
+# The default value is: NO.
+
+HIDE_FRIEND_COMPOUNDS = NO
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any
+# documentation blocks found inside the body of a function. If set to NO, these
+# blocks will be appended to the function's detailed documentation block.
+# The default value is: NO.
+
+HIDE_IN_BODY_DOCS = NO
+
+# The INTERNAL_DOCS tag determines if documentation that is typed after a
+# \internal command is included. If the tag is set to NO then the documentation
+# will be excluded. Set it to YES to include the internal documentation.
+# The default value is: NO.
+
+INTERNAL_DOCS = NO
+
+# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file
+# names in lower-case letters. If set to YES, upper-case letters are also
+# allowed. This is useful if you have classes or files whose names only differ
+# in case and if your file system supports case sensitive file names. Windows
+# and Mac users are advised to set this option to NO.
+# The default value is: system dependent.
+
+CASE_SENSE_NAMES = NO
+
+# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with
+# their full class and namespace scopes in the documentation. If set to YES, the
+# scope will be hidden.
+# The default value is: NO.
+
+HIDE_SCOPE_NAMES = NO
+
+# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of
+# the files that are included by a file in the documentation of that file.
+# The default value is: YES.
+
+SHOW_INCLUDE_FILES = YES
+
+# If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each
+# grouped member an include statement to the documentation, telling the reader
+# which file to include in order to use the member.
+# The default value is: NO.
+
+SHOW_GROUPED_MEMB_INC = NO
+
+# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include
+# files with double quotes in the documentation rather than with sharp brackets.
+# The default value is: NO.
+
+FORCE_LOCAL_INCLUDES = NO
+
+# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the
+# documentation for inline members.
+# The default value is: YES.
+
+INLINE_INFO = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the
+# (detailed) documentation of file and class members alphabetically by member
+# name. If set to NO, the members will appear in declaration order.
+# The default value is: YES.
+
+SORT_MEMBER_DOCS = YES
+
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief
+# descriptions of file, namespace and class members alphabetically by member
+# name. If set to NO, the members will appear in declaration order. Note that
+# this will also influence the order of the classes in the class list.
+# The default value is: NO.
+
+SORT_BRIEF_DOCS = NO
+
+# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the
+# (brief and detailed) documentation of class members so that constructors and
+# destructors are listed first. If set to NO the constructors will appear in the
+# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS.
+# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief
+# member documentation.
+# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting
+# detailed member documentation.
+# The default value is: NO.
+
+SORT_MEMBERS_CTORS_1ST = NO
+
+# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy
+# of group names into alphabetical order. If set to NO the group names will
+# appear in their defined order.
+# The default value is: NO.
+
+SORT_GROUP_NAMES = NO
+
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by
+# fully-qualified names, including namespaces. If set to NO, the class list will
+# be sorted only by class name, not including the namespace part.
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
+# Note: This option applies only to the class list, not to the alphabetical
+# list.
+# The default value is: NO.
+
+SORT_BY_SCOPE_NAME = NO
+
+# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper
+# type resolution of all parameters of a function it will reject a match between
+# the prototype and the implementation of a member function even if there is
+# only one candidate or it is obvious which candidate to choose by doing a
+# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still
+# accept a match between prototype and implementation in such cases.
+# The default value is: NO.
+
+STRICT_PROTO_MATCHING = NO
+
+# The GENERATE_TODOLIST tag can be used to enable (YES) or disable (NO) the todo
+# list. This list is created by putting \todo commands in the documentation.
+# The default value is: YES.
+
+GENERATE_TODOLIST = YES
+
+# The GENERATE_TESTLIST tag can be used to enable (YES) or disable (NO) the test
+# list. This list is created by putting \test commands in the documentation.
+# The default value is: YES.
+
+GENERATE_TESTLIST = YES
+
+# The GENERATE_BUGLIST tag can be used to enable (YES) or disable (NO) the bug
+# list. This list is created by putting \bug commands in the documentation.
+# The default value is: YES.
+
+GENERATE_BUGLIST = YES
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or disable (NO)
+# the deprecated list. This list is created by putting \deprecated commands in
+# the documentation.
+# The default value is: YES.
+
+GENERATE_DEPRECATEDLIST= YES
+
+# The ENABLED_SECTIONS tag can be used to enable conditional documentation
+# sections, marked by \if <section_label> ... \endif and \cond <section_label>
+# ... \endcond blocks.
+
+ENABLED_SECTIONS =
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the
+# initial value of a variable or macro / define can have for it to appear in the
+# documentation. If the initializer consists of more lines than specified here
+# it will be hidden. Use a value of 0 to hide initializers completely. The
+# appearance of the value of individual variables and macros / defines can be
+# controlled using \showinitializer or \hideinitializer command in the
+# documentation regardless of this setting.
+# Minimum value: 0, maximum value: 10000, default value: 30.
+
+MAX_INITIALIZER_LINES = 30
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at
+# the bottom of the documentation of classes and structs. If set to YES, the
+# list will mention the files that were used to generate the documentation.
+# The default value is: YES.
+
+SHOW_USED_FILES = YES
+
+# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This
+# will remove the Files entry from the Quick Index and from the Folder Tree View
+# (if specified).
+# The default value is: YES.
+
+SHOW_FILES = YES
+
+# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces
+# page. This will remove the Namespaces entry from the Quick Index and from the
+# Folder Tree View (if specified).
+# The default value is: YES.
+
+SHOW_NAMESPACES = YES
+
+# The FILE_VERSION_FILTER tag can be used to specify a program or script that
+# doxygen should invoke to get the current version for each file (typically from
+# the version control system). Doxygen will invoke the program by executing (via
+# popen()) the command command input-file, where command is the value of the
+# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided
+# by doxygen. Whatever the program writes to standard output is used as the file
+# version. For an example see the documentation.
+
+FILE_VERSION_FILTER =
+
+# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed
+# by doxygen. The layout file controls the global structure of the generated
+# output files in an output format independent way. To create the layout file
+# that represents doxygen's defaults, run doxygen with the -l option. You can
+# optionally specify a file name after the option, if omitted DoxygenLayout.xml
+# will be used as the name of the layout file.
+#
+# Note that if you run doxygen from a directory containing a file called
+# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE
+# tag is left empty.
+
+LAYOUT_FILE =
+
+# The CITE_BIB_FILES tag can be used to specify one or more bib files containing
+# the reference definitions. This must be a list of .bib files. The .bib
+# extension is automatically appended if omitted. This requires the bibtex tool
+# to be installed. See also http://en.wikipedia.org/wiki/BibTeX for more info.
+# For LaTeX the style of the bibliography can be controlled using
+# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the
+# search path. See also \cite for info how to create references.
+
+CITE_BIB_FILES =
+
+#---------------------------------------------------------------------------
+# Configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated to
+# standard output by doxygen. If QUIET is set to YES this implies that the
+# messages are off.
+# The default value is: NO.
+
+QUIET = NO
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are
+# generated to standard error (stderr) by doxygen. If WARNINGS is set to YES
+# this implies that the warnings are on.
+#
+# Tip: Turn warnings on while writing the documentation.
+# The default value is: YES.
+
+WARNINGS = YES
+
+# If the WARN_IF_UNDOCUMENTED tag is set to YES then doxygen will generate
+# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag
+# will automatically be disabled.
+# The default value is: YES.
+
+WARN_IF_UNDOCUMENTED = YES
+
+# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for
+# potential errors in the documentation, such as not documenting some parameters
+# in a documented function, or documenting parameters that don't exist or using
+# markup commands wrongly.
+# The default value is: YES.
+
+WARN_IF_DOC_ERROR = YES
+
+# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that
+# are documented, but have no documentation for their parameters or return
+# value. If set to NO, doxygen will only warn about wrong or incomplete
+# parameter documentation, but not about the absence of documentation.
+# The default value is: NO.
+
+WARN_NO_PARAMDOC = NO
+
+# The WARN_FORMAT tag determines the format of the warning messages that doxygen
+# can produce. The string should contain the $file, $line, and $text tags, which
+# will be replaced by the file and line number from which the warning originated
+# and the warning text. Optionally the format may contain $version, which will
+# be replaced by the version of the file (if it could be obtained via
+# FILE_VERSION_FILTER)
+# The default value is: $file:$line: $text.
+
+WARN_FORMAT = "$file:$line: $text"
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning and error
+# messages should be written. If left blank the output is written to standard
+# error (stderr).
+
+WARN_LOGFILE =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag is used to specify the files and/or directories that contain
+# documented source files. You may enter file names like myfile.cpp or
+# directories like /usr/src/myproject. Separate the files or directories with
+# spaces.
+# Note: If this tag is empty the current directory is searched.
+
+INPUT = src
+
+# This tag can be used to specify the character encoding of the source files
+# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
+# libiconv (or the iconv built into libc) for the transcoding. See the libiconv
+# documentation (see: http://www.gnu.org/software/libiconv) for the list of
+# possible encodings.
+# The default value is: UTF-8.
+
+INPUT_ENCODING = UTF-8
+
+# If the value of the INPUT tag contains directories, you can use the
+# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and
+# *.h) to filter out the source-files in the directories. If left blank the
+# following patterns are tested:*.c, *.cc, *.cxx, *.cpp, *.c++, *.java, *.ii,
+# *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, *.hh, *.hxx, *.hpp,
+# *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, *.m, *.markdown,
+# *.md, *.mm, *.dox, *.py, *.f90, *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf,
+# *.qsf, *.as and *.js.
+
+FILE_PATTERNS = *.c \
+ *.cc \
+ *.cxx \
+ *.cpp \
+ *.c++ \
+ *.java \
+ *.ii \
+ *.ixx \
+ *.ipp \
+ *.i++ \
+ *.inl \
+ *.idl \
+ *.ddl \
+ *.odl \
+ *.h \
+ *.hh \
+ *.hxx \
+ *.hpp \
+ *.h++ \
+ *.cs \
+ *.d \
+ *.php \
+ *.php4 \
+ *.php5 \
+ *.phtml \
+ *.inc \
+ *.m \
+ *.markdown \
+ *.md \
+ *.mm \
+ *.dox \
+ *.py \
+ *.f90 \
+ *.f \
+ *.for \
+ *.tcl \
+ *.vhd \
+ *.vhdl \
+ *.ucf \
+ *.qsf \
+ *.as \
+ *.js
+
+# The RECURSIVE tag can be used to specify whether or not subdirectories should
+# be searched for input files as well.
+# The default value is: NO.
+
+RECURSIVE = YES
+
+# The EXCLUDE tag can be used to specify files and/or directories that should be
+# excluded from the INPUT source files. This way you can easily exclude a
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+#
+# Note that relative paths are relative to the directory from which doxygen is
+# run.
+
+EXCLUDE =
+
+# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or
+# directories that are symbolic links (a Unix file system feature) are excluded
+# from the input.
+# The default value is: NO.
+
+EXCLUDE_SYMLINKS = NO
+
+# If the value of the INPUT tag contains directories, you can use the
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
+# certain files from those directories.
+#
+# Note that the wildcards are matched against the file with absolute path, so to
+# exclude all test directories for example use the pattern */test/*
+
+EXCLUDE_PATTERNS =
+
+# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
+# (namespaces, classes, functions, etc.) that should be excluded from the
+# output. The symbol name can be a fully qualified name, a word, or if the
+# wildcard * is used, a substring. Examples: ANamespace, AClass,
+# AClass::ANamespace, ANamespace::*Test
+#
+# Note that the wildcards are matched against the file with absolute path, so to
+# exclude all test directories use the pattern */test/*
+
+EXCLUDE_SYMBOLS =
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or directories
+# that contain example code fragments that are included (see the \include
+# command).
+
+EXAMPLE_PATH =
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and
+# *.h) to filter out the source-files in the directories. If left blank all
+# files are included.
+
+EXAMPLE_PATTERNS = *
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
+# searched for input files to be used with the \include or \dontinclude commands
+# irrespective of the value of the RECURSIVE tag.
+# The default value is: NO.
+
+EXAMPLE_RECURSIVE = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or directories
+# that contain images that are to be included in the documentation (see the
+# \image command).
+
+IMAGE_PATH =
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should
+# invoke to filter for each input file. Doxygen will invoke the filter program
+# by executing (via popen()) the command:
+#
+# <filter> <input-file>
+#
+# where <filter> is the value of the INPUT_FILTER tag, and <input-file> is the
+# name of an input file. Doxygen will then use the output that the filter
+# program writes to standard output. If FILTER_PATTERNS is specified, this tag
+# will be ignored.
+#
+# Note that the filter must not add or remove lines; it is applied before the
+# code is scanned, but not when the output code is generated. If lines are added
+# or removed, the anchors will not be placed correctly.
+
+INPUT_FILTER =
+
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
+# basis. Doxygen will compare the file name with each pattern and apply the
+# filter if there is a match. The filters are a list of the form: pattern=filter
+# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how
+# filters are used. If the FILTER_PATTERNS tag is empty or if none of the
+# patterns match the file name, INPUT_FILTER is applied.
+
+FILTER_PATTERNS =
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
+# INPUT_FILTER) will also be used to filter the input files that are used for
+# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES).
+# The default value is: NO.
+
+FILTER_SOURCE_FILES = NO
+
+# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file
+# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and
+# it is also possible to disable source filtering for a specific pattern using
+# *.ext= (so without naming a filter).
+# This tag requires that the tag FILTER_SOURCE_FILES is set to YES.
+
+FILTER_SOURCE_PATTERNS =
+
+# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that
+# is part of the input, its contents will be placed on the main page
+# (index.html). This can be useful if you have a project on for instance GitHub
+# and want to reuse the introduction page also for the doxygen output.
+
+USE_MDFILE_AS_MAINPAGE =
+
+#---------------------------------------------------------------------------
+# Configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will be
+# generated. Documented entities will be cross-referenced with these sources.
+#
+# Note: To get rid of all source code in the generated output, make sure that
+# also VERBATIM_HEADERS is set to NO.
+# The default value is: NO.
+
+SOURCE_BROWSER = NO
+
+# Setting the INLINE_SOURCES tag to YES will include the body of functions,
+# classes and enums directly into the documentation.
+# The default value is: NO.
+
+INLINE_SOURCES = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any
+# special comment blocks from generated source code fragments. Normal C, C++ and
+# Fortran comments will always remain visible.
+# The default value is: YES.
+
+STRIP_CODE_COMMENTS = YES
+
+# If the REFERENCED_BY_RELATION tag is set to YES then for each documented
+# function all documented functions referencing it will be listed.
+# The default value is: NO.
+
+REFERENCED_BY_RELATION = NO
+
+# If the REFERENCES_RELATION tag is set to YES then for each documented function
+# all documented entities called/used by that function will be listed.
+# The default value is: NO.
+
+REFERENCES_RELATION = NO
+
+# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set
+# to YES then the hyperlinks from functions in REFERENCES_RELATION and
+# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will
+# link to the documentation.
+# The default value is: YES.
+
+REFERENCES_LINK_SOURCE = YES
+
+# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the
+# source code will show a tooltip with additional information such as prototype,
+# brief description and links to the definition and documentation. Since this
+# will make the HTML file larger and loading of large files a bit slower, you
+# can opt to disable this feature.
+# The default value is: YES.
+# This tag requires that the tag SOURCE_BROWSER is set to YES.
+
+SOURCE_TOOLTIPS = YES
+
+# If the USE_HTAGS tag is set to YES then the references to source code will
+# point to the HTML generated by the htags(1) tool instead of doxygen built-in
+# source browser. The htags tool is part of GNU's global source tagging system
+# (see http://www.gnu.org/software/global/global.html). You will need version
+# 4.8.6 or higher.
+#
+# To use it do the following:
+# - Install the latest version of global
+# - Enable SOURCE_BROWSER and USE_HTAGS in the config file
+# - Make sure the INPUT points to the root of the source tree
+# - Run doxygen as normal
+#
+# Doxygen will invoke htags (and that will in turn invoke gtags), so these
+# tools must be available from the command line (i.e. in the search path).
+#
+# The result: instead of the source browser generated by doxygen, the links to
+# source code will now point to the output of htags.
+# The default value is: NO.
+# This tag requires that the tag SOURCE_BROWSER is set to YES.
+
+USE_HTAGS = NO
+
+# If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a
+# verbatim copy of the header file for each class for which an include is
+# specified. Set to NO to disable this.
+# See also: Section \class.
+# The default value is: YES.
+
+VERBATIM_HEADERS = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all
+# compounds will be generated. Enable this if the project contains a lot of
+# classes, structs, unions or interfaces.
+# The default value is: YES.
+
+ALPHABETICAL_INDEX = YES
+
+# The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in
+# which the alphabetical index list will be split.
+# Minimum value: 1, maximum value: 20, default value: 5.
+# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
+
+COLS_IN_ALPHA_INDEX = 5
+
+# In case all classes in a project start with a common prefix, all classes will
+# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag
+# can be used to specify a prefix (or a list of prefixes) that should be ignored
+# while generating the index headers.
+# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
+
+IGNORE_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES, doxygen will generate HTML output
+# The default value is: YES.
+
+GENERATE_HTML = NO
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: html.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_OUTPUT = html
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each
+# generated HTML page (for example: .htm, .php, .asp).
+# The default value is: .html.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_FILE_EXTENSION = .html
+
+# The HTML_HEADER tag can be used to specify a user-defined HTML header file for
+# each generated HTML page. If the tag is left blank doxygen will generate a
+# standard header.
+#
+# To get valid HTML the header file that includes any scripts and style sheets
+# that doxygen needs, which is dependent on the configuration options used (e.g.
+# the setting GENERATE_TREEVIEW). It is highly recommended to start with a
+# default header using
+# doxygen -w html new_header.html new_footer.html new_stylesheet.css
+# YourConfigFile
+# and then modify the file new_header.html. See also section "Doxygen usage"
+# for information on how to generate the default header that doxygen normally
+# uses.
+# Note: The header is subject to change so you typically have to regenerate the
+# default header when upgrading to a newer version of doxygen. For a description
+# of the possible markers and block names see the documentation.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_HEADER =
+
+# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each
+# generated HTML page. If the tag is left blank doxygen will generate a standard
+# footer. See HTML_HEADER for more information on how to generate a default
+# footer and what special commands can be used inside the footer. See also
+# section "Doxygen usage" for information on how to generate the default footer
+# that doxygen normally uses.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_FOOTER =
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style
+# sheet that is used by each HTML page. It can be used to fine-tune the look of
+# the HTML output. If left blank doxygen will generate a default style sheet.
+# See also section "Doxygen usage" for information on how to generate the style
+# sheet that doxygen normally uses.
+# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as
+# it is more robust and this tag (HTML_STYLESHEET) will in the future become
+# obsolete.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_STYLESHEET =
+
+# The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined
+# cascading style sheets that are included after the standard style sheets
+# created by doxygen. Using this option one can overrule certain style aspects.
+# This is preferred over using HTML_STYLESHEET since it does not replace the
+# standard style sheet and is therefore more robust against future updates.
+# Doxygen will copy the style sheet files to the output directory.
+# Note: The order of the extra stylesheet files is of importance (e.g. the last
+# stylesheet in the list overrules the setting of the previous ones in the
+# list). For an example see the documentation.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_EXTRA_STYLESHEET =
+
+# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the HTML output directory. Note
+# that these files will be copied to the base HTML output directory. Use the
+# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these
+# files. In the HTML_STYLESHEET file, use the file name only. Also note that the
+# files will be copied as-is; there are no commands or markers available.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_EXTRA_FILES =
+
+# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen
+# will adjust the colors in the stylesheet and background images according to
+# this color. Hue is specified as an angle on a colorwheel, see
+# http://en.wikipedia.org/wiki/Hue for more information. For instance the value
+# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300
+# purple, and 360 is red again.
+# Minimum value: 0, maximum value: 359, default value: 220.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_HUE = 220
+
+# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors
+# in the HTML output. For a value of 0 the output will use grayscales only. A
+# value of 255 will produce the most vivid colors.
+# Minimum value: 0, maximum value: 255, default value: 100.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_SAT = 100
+
+# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the
+# luminance component of the colors in the HTML output. Values below 100
+# gradually make the output lighter, whereas values above 100 make the output
+# darker. The value divided by 100 is the actual gamma applied, so 80 represents
+# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not
+# change the gamma.
+# Minimum value: 40, maximum value: 240, default value: 80.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_GAMMA = 80
+
+# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML
+# page will contain the date and time when the page was generated. Setting this
+# to NO can help when comparing the output of multiple runs.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_TIMESTAMP = YES
+
+# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
+# documentation will contain sections that can be hidden and shown after the
+# page has loaded.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_DYNAMIC_SECTIONS = NO
+
+# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries
+# shown in the various tree structured indices initially; the user can expand
+# and collapse entries dynamically later on. Doxygen will expand the tree to
+# such a level that at most the specified number of entries are visible (unless
+# a fully collapsed tree already exceeds this amount). So setting the number of
+# entries 1 will produce a full collapsed tree by default. 0 is a special value
+# representing an infinite number of entries and will result in a full expanded
+# tree by default.
+# Minimum value: 0, maximum value: 9999, default value: 100.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_INDEX_NUM_ENTRIES = 100
+
+# If the GENERATE_DOCSET tag is set to YES, additional index files will be
+# generated that can be used as input for Apple's Xcode 3 integrated development
+# environment (see: http://developer.apple.com/tools/xcode/), introduced with
+# OSX 10.5 (Leopard). To create a documentation set, doxygen will generate a
+# Makefile in the HTML output directory. Running make will produce the docset in
+# that directory and running make install will install the docset in
+# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at
+# startup. See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html
+# for more information.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_DOCSET = NO
+
+# This tag determines the name of the docset feed. A documentation feed provides
+# an umbrella under which multiple documentation sets from a single provider
+# (such as a company or product suite) can be grouped.
+# The default value is: Doxygen generated docs.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_FEEDNAME = "Doxygen generated docs"
+
+# This tag specifies a string that should uniquely identify the documentation
+# set bundle. This should be a reverse domain-name style string, e.g.
+# com.mycompany.MyDocSet. Doxygen will append .docset to the name.
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_BUNDLE_ID = org.doxygen.Project
+
+# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify
+# the documentation publisher. This should be a reverse domain-name style
+# string, e.g. com.mycompany.MyDocSet.documentation.
+# The default value is: org.doxygen.Publisher.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_PUBLISHER_ID = org.doxygen.Publisher
+
+# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher.
+# The default value is: Publisher.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_PUBLISHER_NAME = Publisher
+
+# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three
+# additional HTML index files: index.hhp, index.hhc, and index.hhk. The
+# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop
+# (see: http://www.microsoft.com/en-us/download/details.aspx?id=21138) on
+# Windows.
+#
+# The HTML Help Workshop contains a compiler that can convert all HTML output
+# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML
+# files are now used as the Windows 98 help format, and will replace the old
+# Windows help format (.hlp) on all Windows platforms in the future. Compressed
+# HTML files also contain an index, a table of contents, and you can search for
+# words in the documentation. The HTML workshop also contains a viewer for
+# compressed HTML files.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_HTMLHELP = NO
+
+# The CHM_FILE tag can be used to specify the file name of the resulting .chm
+# file. You can add a path in front of the file if the result should not be
+# written to the html output directory.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+CHM_FILE =
+
+# The HHC_LOCATION tag can be used to specify the location (absolute path
+# including file name) of the HTML help compiler (hhc.exe). If non-empty,
+# doxygen will try to run the HTML help compiler on the generated index.hhp.
+# The file has to be specified with full path.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+HHC_LOCATION =
+
+# The GENERATE_CHI flag controls if a separate .chi index file is generated
+# (YES) or that it should be included in the master .chm file (NO).
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+GENERATE_CHI = NO
+
+# The CHM_INDEX_ENCODING is used to encode HtmlHelp index (hhk), content (hhc)
+# and project file content.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+CHM_INDEX_ENCODING =
+
+# The BINARY_TOC flag controls whether a binary table of contents is generated
+# (YES) or a normal table of contents (NO) in the .chm file. Furthermore it
+# enables the Previous and Next buttons.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+BINARY_TOC = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members to
+# the table of contents of the HTML help documentation and to the tree view.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+TOC_EXPAND = NO
+
+# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and
+# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that
+# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help
+# (.qch) of the generated HTML documentation.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_QHP = NO
+
+# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify
+# the file name of the resulting .qch file. The path specified is relative to
+# the HTML output folder.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QCH_FILE =
+
+# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help
+# Project output. For more information please see Qt Help Project / Namespace
+# (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#namespace).
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_NAMESPACE = org.doxygen.Project
+
+# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt
+# Help Project output. For more information please see Qt Help Project / Virtual
+# Folders (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#virtual-
+# folders).
+# The default value is: doc.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_VIRTUAL_FOLDER = doc
+
+# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom
+# filter to add. For more information please see Qt Help Project / Custom
+# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-
+# filters).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_CUST_FILTER_NAME =
+
+# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the
+# custom filter to add. For more information please see Qt Help Project / Custom
+# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-
+# filters).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_CUST_FILTER_ATTRS =
+
+# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this
+# project's filter section matches. Qt Help Project / Filter Attributes (see:
+# http://qt-project.org/doc/qt-4.8/qthelpproject.html#filter-attributes).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_SECT_FILTER_ATTRS =
+
+# The QHG_LOCATION tag can be used to specify the location of Qt's
+# qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the
+# generated .qhp file.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHG_LOCATION =
+
+# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be
+# generated, together with the HTML files, they form an Eclipse help plugin. To
+# install this plugin and make it available under the help contents menu in
+# Eclipse, the contents of the directory containing the HTML and XML files needs
+# to be copied into the plugins directory of eclipse. The name of the directory
+# within the plugins directory should be the same as the ECLIPSE_DOC_ID value.
+# After copying Eclipse needs to be restarted before the help appears.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_ECLIPSEHELP = NO
+
+# A unique identifier for the Eclipse help plugin. When installing the plugin
+# the directory name containing the HTML and XML files should also have this
+# name. Each documentation set should have its own identifier.
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES.
+
+ECLIPSE_DOC_ID = org.doxygen.Project
+
+# If you want full control over the layout of the generated HTML pages it might
+# be necessary to disable the index and replace it with your own. The
+# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top
+# of each HTML page. A value of NO enables the index and the value YES disables
+# it. Since the tabs in the index contain the same information as the navigation
+# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+DISABLE_INDEX = NO
+
+# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
+# structure should be generated to display hierarchical information. If the tag
+# value is set to YES, a side panel will be generated containing a tree-like
+# index structure (just like the one that is generated for HTML Help). For this
+# to work a browser that supports JavaScript, DHTML, CSS and frames is required
+# (i.e. any modern browser). Windows users are probably better off using the
+# HTML help feature. Via custom stylesheets (see HTML_EXTRA_STYLESHEET) one can
+# further fine-tune the look of the index. As an example, the default style
+# sheet generated by doxygen has an example that shows how to put an image at
+# the root of the tree instead of the PROJECT_NAME. Since the tree basically has
+# the same information as the tab index, you could consider setting
+# DISABLE_INDEX to YES when enabling this option.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_TREEVIEW = NO
+
+# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that
+# doxygen will group on one line in the generated HTML documentation.
+#
+# Note that a value of 0 will completely suppress the enum values from appearing
+# in the overview section.
+# Minimum value: 0, maximum value: 20, default value: 4.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+ENUM_VALUES_PER_LINE = 4
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used
+# to set the initial width (in pixels) of the frame in which the tree is shown.
+# Minimum value: 0, maximum value: 1500, default value: 250.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+TREEVIEW_WIDTH = 250
+
+# If the EXT_LINKS_IN_WINDOW option is set to YES, doxygen will open links to
+# external symbols imported via tag files in a separate window.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+EXT_LINKS_IN_WINDOW = NO
+
+# Use this tag to change the font size of LaTeX formulas included as images in
+# the HTML documentation. When you change the font size after a successful
+# doxygen run you need to manually remove any form_*.png images from the HTML
+# output directory to force them to be regenerated.
+# Minimum value: 8, maximum value: 50, default value: 10.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+FORMULA_FONTSIZE = 10
+
+# Use the FORMULA_TRANPARENT tag to determine whether or not the images
+# generated for formulas are transparent PNGs. Transparent PNGs are not
+# supported properly for IE 6.0, but are supported on all modern browsers.
+#
+# Note that when changing this option you need to delete any form_*.png files in
+# the HTML output directory before the changes have effect.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+FORMULA_TRANSPARENT = YES
+
+# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see
+# http://www.mathjax.org) which uses client side Javascript for the rendering
+# instead of using pre-rendered bitmaps. Use this if you do not have LaTeX
+# installed or if you want to formulas look prettier in the HTML output. When
+# enabled you may also need to install MathJax separately and configure the path
+# to it using the MATHJAX_RELPATH option.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+USE_MATHJAX = NO
+
+# When MathJax is enabled you can set the default output format to be used for
+# the MathJax output. See the MathJax site (see:
+# http://docs.mathjax.org/en/latest/output.html) for more details.
+# Possible values are: HTML-CSS (which is slower, but has the best
+# compatibility), NativeMML (i.e. MathML) and SVG.
+# The default value is: HTML-CSS.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_FORMAT = HTML-CSS
+
+# When MathJax is enabled you need to specify the location relative to the HTML
+# output directory using the MATHJAX_RELPATH option. The destination directory
+# should contain the MathJax.js script. For instance, if the mathjax directory
+# is located at the same level as the HTML output directory, then
+# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax
+# Content Delivery Network so you can quickly see the result without installing
+# MathJax. However, it is strongly recommended to install a local copy of
+# MathJax from http://www.mathjax.org before deployment.
+# The default value is: http://cdn.mathjax.org/mathjax/latest.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest
+
+# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax
+# extension names that should be enabled during MathJax rendering. For example
+# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_EXTENSIONS =
+
+# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces
+# of code that will be used on startup of the MathJax code. See the MathJax site
+# (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an
+# example see the documentation.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_CODEFILE =
+
+# When the SEARCHENGINE tag is enabled doxygen will generate a search box for
+# the HTML output. The underlying search engine uses javascript and DHTML and
+# should work on any modern browser. Note that when using HTML help
+# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET)
+# there is already a search function so this one should typically be disabled.
+# For large projects the javascript based search engine can be slow, then
+# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to
+# search using the keyboard; to jump to the search box use <access key> + S
+# (what the <access key> is depends on the OS and browser, but it is typically
+# <CTRL>, <ALT>/<option>, or both). Inside the search box use the <cursor down
+# key> to jump into the search results window, the results can be navigated
+# using the <cursor keys>. Press <Enter> to select an item or <escape> to cancel
+# the search. The filter options can be selected when the cursor is inside the
+# search box by pressing <Shift>+<cursor down>. Also here use the <cursor keys>
+# to select a filter and <Enter> or <escape> to activate or cancel the filter
+# option.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+SEARCHENGINE = YES
+
+# When the SERVER_BASED_SEARCH tag is enabled the search engine will be
+# implemented using a web server instead of a web client using Javascript. There
+# are two flavors of web server based searching depending on the EXTERNAL_SEARCH
+# setting. When disabled, doxygen will generate a PHP script for searching and
+# an index file used by the script. When EXTERNAL_SEARCH is enabled the indexing
+# and searching needs to be provided by external tools. See the section
+# "External Indexing and Searching" for details.
+# The default value is: NO.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SERVER_BASED_SEARCH = NO
+
+# When EXTERNAL_SEARCH tag is enabled doxygen will no longer generate the PHP
+# script for searching. Instead the search results are written to an XML file
+# which needs to be processed by an external indexer. Doxygen will invoke an
+# external search engine pointed to by the SEARCHENGINE_URL option to obtain the
+# search results.
+#
+# Doxygen ships with an example indexer (doxyindexer) and search engine
+# (doxysearch.cgi) which are based on the open source search engine library
+# Xapian (see: http://xapian.org/).
+#
+# See the section "External Indexing and Searching" for details.
+# The default value is: NO.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTERNAL_SEARCH = NO
+
+# The SEARCHENGINE_URL should point to a search engine hosted by a web server
+# which will return the search results when EXTERNAL_SEARCH is enabled.
+#
+# Doxygen ships with an example indexer (doxyindexer) and search engine
+# (doxysearch.cgi) which are based on the open source search engine library
+# Xapian (see: http://xapian.org/). See the section "External Indexing and
+# Searching" for details.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SEARCHENGINE_URL =
+
+# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the unindexed
+# search data is written to a file for indexing by an external tool. With the
+# SEARCHDATA_FILE tag the name of this file can be specified.
+# The default file is: searchdata.xml.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SEARCHDATA_FILE = searchdata.xml
+
+# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the
+# EXTERNAL_SEARCH_ID tag can be used as an identifier for the project. This is
+# useful in combination with EXTRA_SEARCH_MAPPINGS to search through multiple
+# projects and redirect the results back to the right project.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTERNAL_SEARCH_ID =
+
+# The EXTRA_SEARCH_MAPPINGS tag can be used to enable searching through doxygen
+# projects other than the one defined by this configuration file, but that are
+# all added to the same external search index. Each project needs to have a
+# unique id set via EXTERNAL_SEARCH_ID. The search mapping then maps the id of
+# to a relative location where the documentation can be found. The format is:
+# EXTRA_SEARCH_MAPPINGS = tagname1=loc1 tagname2=loc2 ...
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTRA_SEARCH_MAPPINGS =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES, doxygen will generate LaTeX output.
+# The default value is: YES.
+
+GENERATE_LATEX = NO
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: latex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_OUTPUT = latex
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
+# invoked.
+#
+# Note that when enabling USE_PDFLATEX this option is only used for generating
+# bitmaps for formulas in the HTML output, but not in the Makefile that is
+# written to the output directory.
+# The default file is: latex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_CMD_NAME = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to generate
+# index for LaTeX.
+# The default file is: makeindex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+MAKEINDEX_CMD_NAME = makeindex
+
+# If the COMPACT_LATEX tag is set to YES, doxygen generates more compact LaTeX
+# documents. This may be useful for small projects and may help to save some
+# trees in general.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+COMPACT_LATEX = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used by the
+# printer.
+# Possible values are: a4 (210 x 297 mm), letter (8.5 x 11 inches), legal (8.5 x
+# 14 inches) and executive (7.25 x 10.5 inches).
+# The default value is: a4.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+PAPER_TYPE = a4
+
+# The EXTRA_PACKAGES tag can be used to specify one or more LaTeX package names
+# that should be included in the LaTeX output. To get the times font for
+# instance you can specify
+# EXTRA_PACKAGES=times
+# If left blank no extra packages will be included.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+EXTRA_PACKAGES =
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for the
+# generated LaTeX document. The header should contain everything until the first
+# chapter. If it is left blank doxygen will generate a standard header. See
+# section "Doxygen usage" for information on how to let doxygen write the
+# default header to a separate file.
+#
+# Note: Only use a user-defined header if you know what you are doing! The
+# following commands have a special meaning inside the header: $title,
+# $datetime, $date, $doxygenversion, $projectname, $projectnumber,
+# $projectbrief, $projectlogo. Doxygen will replace $title with the empty
+# string, for the replacement values of the other commands the user is referred
+# to HTML_HEADER.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_HEADER =
+
+# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for the
+# generated LaTeX document. The footer should contain everything after the last
+# chapter. If it is left blank doxygen will generate a standard footer. See
+# LATEX_HEADER for more information on how to generate a default footer and what
+# special commands can be used inside the footer.
+#
+# Note: Only use a user-defined footer if you know what you are doing!
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_FOOTER =
+
+# The LATEX_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the LATEX_OUTPUT output
+# directory. Note that the files will be copied as-is; there are no commands or
+# markers available.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_EXTRA_FILES =
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated is
+# prepared for conversion to PDF (using ps2pdf or pdflatex). The PDF file will
+# contain links (just like the HTML output) instead of page references. This
+# makes the output suitable for online browsing using a PDF viewer.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+PDF_HYPERLINKS = YES
+
+# If the USE_PDFLATEX tag is set to YES, doxygen will use pdflatex to generate
+# the PDF file directly from the LaTeX files. Set this option to YES, to get a
+# higher quality PDF documentation.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+USE_PDFLATEX = YES
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \batchmode
+# command to the generated LaTeX files. This will instruct LaTeX to keep running
+# if errors occur, instead of asking the user for help. This option is also used
+# when generating formulas in HTML.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_BATCHMODE = NO
+
+# If the LATEX_HIDE_INDICES tag is set to YES then doxygen will not include the
+# index chapters (such as File Index, Compound Index, etc.) in the output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_HIDE_INDICES = NO
+
+# If the LATEX_SOURCE_CODE tag is set to YES then doxygen will include source
+# code with syntax highlighting in the LaTeX output.
+#
+# Note that which sources are shown also depends on other settings such as
+# SOURCE_BROWSER.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_SOURCE_CODE = NO
+
+# The LATEX_BIB_STYLE tag can be used to specify the style to use for the
+# bibliography, e.g. plainnat, or ieeetr. See
+# http://en.wikipedia.org/wiki/BibTeX and \cite for more info.
+# The default value is: plain.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_BIB_STYLE = plain
+
+#---------------------------------------------------------------------------
+# Configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES, doxygen will generate RTF output. The
+# RTF output is optimized for Word 97 and may not look too pretty with other RTF
+# readers/editors.
+# The default value is: NO.
+
+GENERATE_RTF = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: rtf.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_OUTPUT = rtf
+
+# If the COMPACT_RTF tag is set to YES, doxygen generates more compact RTF
+# documents. This may be useful for small projects and may help to save some
+# trees in general.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+COMPACT_RTF = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated will
+# contain hyperlink fields. The RTF file will contain links (just like the HTML
+# output) instead of page references. This makes the output suitable for online
+# browsing using Word or some other Word compatible readers that support those
+# fields.
+#
+# Note: WordPad (write) and others do not support links.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_HYPERLINKS = NO
+
+# Load stylesheet definitions from file. Syntax is similar to doxygen's config
+# file, i.e. a series of assignments. You only have to provide replacements,
+# missing definitions are set to their default value.
+#
+# See also section "Doxygen usage" for information on how to generate the
+# default style sheet that doxygen normally uses.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_STYLESHEET_FILE =
+
+# Set optional variables used in the generation of an RTF document. Syntax is
+# similar to doxygen's config file. A template extensions file can be generated
+# using doxygen -e rtf extensionFile.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_EXTENSIONS_FILE =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES, doxygen will generate man pages for
+# classes and files.
+# The default value is: NO.
+
+GENERATE_MAN = NO
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it. A directory man3 will be created inside the directory specified by
+# MAN_OUTPUT.
+# The default directory is: man.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_OUTPUT = man
+
+# The MAN_EXTENSION tag determines the extension that is added to the generated
+# man pages. In case the manual section does not start with a number, the number
+# 3 is prepended. The dot (.) at the beginning of the MAN_EXTENSION tag is
+# optional.
+# The default value is: .3.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_EXTENSION = .3
+
+# The MAN_SUBDIR tag determines the name of the directory created within
+# MAN_OUTPUT in which the man pages are placed. If defaults to man followed by
+# MAN_EXTENSION with the initial . removed.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_SUBDIR =
+
+# If the MAN_LINKS tag is set to YES and doxygen generates man output, then it
+# will generate one additional man file for each entity documented in the real
+# man page(s). These additional files only source the real man page, but without
+# them the man command would be unable to find the correct page.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_LINKS = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES, doxygen will generate an XML file that
+# captures the structure of the code including all documentation.
+# The default value is: NO.
+
+GENERATE_XML = YES
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: xml.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_OUTPUT = xml
+
+# If the XML_PROGRAMLISTING tag is set to YES, doxygen will dump the program
+# listings (including syntax highlighting and cross-referencing information) to
+# the XML output. Note that enabling this will significantly increase the size
+# of the XML output.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_PROGRAMLISTING = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the DOCBOOK output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_DOCBOOK tag is set to YES, doxygen will generate Docbook files
+# that can be used to generate PDF.
+# The default value is: NO.
+
+GENERATE_DOCBOOK = NO
+
+# The DOCBOOK_OUTPUT tag is used to specify where the Docbook pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be put in
+# front of it.
+# The default directory is: docbook.
+# This tag requires that the tag GENERATE_DOCBOOK is set to YES.
+
+DOCBOOK_OUTPUT = docbook
+
+# If the DOCBOOK_PROGRAMLISTING tag is set to YES, doxygen will include the
+# program listings (including syntax highlighting and cross-referencing
+# information) to the DOCBOOK output. Note that enabling this will significantly
+# increase the size of the DOCBOOK output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_DOCBOOK is set to YES.
+
+DOCBOOK_PROGRAMLISTING = NO
+
+#---------------------------------------------------------------------------
+# Configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES, doxygen will generate an
+# AutoGen Definitions (see http://autogen.sf.net) file that captures the
+# structure of the code including all documentation. Note that this feature is
+# still experimental and incomplete at the moment.
+# The default value is: NO.
+
+GENERATE_AUTOGEN_DEF = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES, doxygen will generate a Perl module
+# file that captures the structure of the code including all documentation.
+#
+# Note that this feature is still experimental and incomplete at the moment.
+# The default value is: NO.
+
+GENERATE_PERLMOD = NO
+
+# If the PERLMOD_LATEX tag is set to YES, doxygen will generate the necessary
+# Makefile rules, Perl scripts and LaTeX code to be able to generate PDF and DVI
+# output from the Perl module output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_LATEX = NO
+
+# If the PERLMOD_PRETTY tag is set to YES, the Perl module output will be nicely
+# formatted so it can be parsed by a human reader. This is useful if you want to
+# understand what is going on. On the other hand, if this tag is set to NO, the
+# size of the Perl module output will be much smaller and Perl will parse it
+# just the same.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_PRETTY = YES
+
+# The names of the make variables in the generated doxyrules.make file are
+# prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. This is useful
+# so different doxyrules.make files included by the same Makefile don't
+# overwrite each other's variables.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_MAKEVAR_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES, doxygen will evaluate all
+# C-preprocessor directives found in the sources and include files.
+# The default value is: YES.
+
+ENABLE_PREPROCESSING = YES
+
+# If the MACRO_EXPANSION tag is set to YES, doxygen will expand all macro names
+# in the source code. If set to NO, only conditional compilation will be
+# performed. Macro expansion can be done in a controlled way by setting
+# EXPAND_ONLY_PREDEF to YES.
+# The default value is: NO.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+MACRO_EXPANSION = NO
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES then
+# the macro expansion is limited to the macros specified with the PREDEFINED and
+# EXPAND_AS_DEFINED tags.
+# The default value is: NO.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+EXPAND_ONLY_PREDEF = NO
+
+# If the SEARCH_INCLUDES tag is set to YES, the include files in the
+# INCLUDE_PATH will be searched if a #include is found.
+# The default value is: YES.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+SEARCH_INCLUDES = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that
+# contain include files that are not input files but should be processed by the
+# preprocessor.
+# This tag requires that the tag SEARCH_INCLUDES is set to YES.
+
+INCLUDE_PATH =
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
+# patterns (like *.h and *.hpp) to filter out the header-files in the
+# directories. If left blank, the patterns specified with FILE_PATTERNS will be
+# used.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+INCLUDE_FILE_PATTERNS =
+
+# The PREDEFINED tag can be used to specify one or more macro names that are
+# defined before the preprocessor is started (similar to the -D option of e.g.
+# gcc). The argument of the tag is a list of macros of the form: name or
+# name=definition (no spaces). If the definition and the "=" are omitted, "=1"
+# is assumed. To prevent a macro definition from being undefined via #undef or
+# recursively expanded use the := operator instead of the = operator.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+PREDEFINED =
+
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this
+# tag can be used to specify a list of macro names that should be expanded. The
+# macro definition that is found in the sources will be used. Use the PREDEFINED
+# tag if you want to use a different macro definition that overrules the
+# definition found in the source code.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+EXPAND_AS_DEFINED =
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES then doxygen's preprocessor will
+# remove all references to function-like macros that are alone on a line, have
+# an all uppercase name, and do not end with a semicolon. Such function macros
+# are typically used for boiler-plate code, and will confuse the parser if not
+# removed.
+# The default value is: YES.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+SKIP_FUNCTION_MACROS = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to external references
+#---------------------------------------------------------------------------
+
+# The TAGFILES tag can be used to specify one or more tag files. For each tag
+# file the location of the external documentation should be added. The format of
+# a tag file without this location is as follows:
+# TAGFILES = file1 file2 ...
+# Adding location for the tag files is done as follows:
+# TAGFILES = file1=loc1 "file2 = loc2" ...
+# where loc1 and loc2 can be relative or absolute paths or URLs. See the
+# section "Linking to external documentation" for more information about the use
+# of tag files.
+# Note: Each tag file must have a unique name (where the name does NOT include
+# the path). If a tag file is not located in the directory in which doxygen is
+# run, you must also specify the path to the tagfile here.
+
+TAGFILES =
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create a
+# tag file that is based on the input files it reads. See section "Linking to
+# external documentation" for more information about the usage of tag files.
+
+GENERATE_TAGFILE =
+
+# If the ALLEXTERNALS tag is set to YES, all external class will be listed in
+# the class index. If set to NO, only the inherited external classes will be
+# listed.
+# The default value is: NO.
+
+ALLEXTERNALS = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES, all external groups will be listed
+# in the modules index. If set to NO, only the current project's groups will be
+# listed.
+# The default value is: YES.
+
+EXTERNAL_GROUPS = YES
+
+# If the EXTERNAL_PAGES tag is set to YES, all external pages will be listed in
+# the related pages index. If set to NO, only the current project's pages will
+# be listed.
+# The default value is: YES.
+
+EXTERNAL_PAGES = YES
+
+# The PERL_PATH should be the absolute path and name of the perl script
+# interpreter (i.e. the result of 'which perl').
+# The default file (with absolute path) is: /usr/bin/perl.
+
+PERL_PATH = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES, doxygen will generate a class diagram
+# (in HTML and LaTeX) for classes with base or super classes. Setting the tag to
+# NO turns the diagrams off. Note that this option also works with HAVE_DOT
+# disabled, but it is recommended to install and use dot, since it yields more
+# powerful graphs.
+# The default value is: YES.
+
+CLASS_DIAGRAMS = YES
+
+# You can define message sequence charts within doxygen comments using the \msc
+# command. Doxygen will then run the mscgen tool (see:
+# http://www.mcternan.me.uk/mscgen/)) to produce the chart and insert it in the
+# documentation. The MSCGEN_PATH tag allows you to specify the directory where
+# the mscgen tool resides. If left empty the tool is assumed to be found in the
+# default search path.
+
+MSCGEN_PATH =
+
+# You can include diagrams made with dia in doxygen documentation. Doxygen will
+# then run dia to produce the diagram and insert it in the documentation. The
+# DIA_PATH tag allows you to specify the directory where the dia binary resides.
+# If left empty dia is assumed to be found in the default search path.
+
+DIA_PATH =
+
+# If set to YES the inheritance and collaboration graphs will hide inheritance
+# and usage relations if the target is undocumented or is not a class.
+# The default value is: YES.
+
+HIDE_UNDOC_RELATIONS = YES
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
+# available from the path. This tool is part of Graphviz (see:
+# http://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent
+# Bell Labs. The other options in this section have no effect if this option is
+# set to NO
+# The default value is: NO.
+
+HAVE_DOT = NO
+
+# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is allowed
+# to run in parallel. When set to 0 doxygen will base this on the number of
+# processors available in the system. You can set it explicitly to a value
+# larger than 0 to get control over the balance between CPU load and processing
+# speed.
+# Minimum value: 0, maximum value: 32, default value: 0.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_NUM_THREADS = 0
+
+# When you want a differently looking font in the dot files that doxygen
+# generates you can specify the font name using DOT_FONTNAME. You need to make
+# sure dot is able to find the font, which can be done by putting it in a
+# standard location or by setting the DOTFONTPATH environment variable or by
+# setting DOT_FONTPATH to the directory containing the font.
+# The default value is: Helvetica.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTNAME = Helvetica
+
+# The DOT_FONTSIZE tag can be used to set the size (in points) of the font of
+# dot graphs.
+# Minimum value: 4, maximum value: 24, default value: 10.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTSIZE = 10
+
+# By default doxygen will tell dot to use the default font as specified with
+# DOT_FONTNAME. If you specify a different font using DOT_FONTNAME you can set
+# the path where dot can find it using this tag.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTPATH =
+
+# If the CLASS_GRAPH tag is set to YES then doxygen will generate a graph for
+# each documented class showing the direct and indirect inheritance relations.
+# Setting this tag to YES will force the CLASS_DIAGRAMS tag to NO.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CLASS_GRAPH = YES
+
+# If the COLLABORATION_GRAPH tag is set to YES then doxygen will generate a
+# graph for each documented class showing the direct and indirect implementation
+# dependencies (inheritance, containment, and class references variables) of the
+# class with other documented classes.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+COLLABORATION_GRAPH = YES
+
+# If the GROUP_GRAPHS tag is set to YES then doxygen will generate a graph for
+# groups, showing the direct groups dependencies.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GROUP_GRAPHS = YES
+
+# If the UML_LOOK tag is set to YES, doxygen will generate inheritance and
+# collaboration diagrams in a style similar to the OMG's Unified Modeling
+# Language.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+UML_LOOK = NO
+
+# If the UML_LOOK tag is enabled, the fields and methods are shown inside the
+# class node. If there are many fields or methods and many nodes the graph may
+# become too big to be useful. The UML_LIMIT_NUM_FIELDS threshold limits the
+# number of items for each type to make the size more manageable. Set this to 0
+# for no limit. Note that the threshold may be exceeded by 50% before the limit
+# is enforced. So when you set the threshold to 10, up to 15 fields may appear,
+# but if the number exceeds 15, the total amount of fields shown is limited to
+# 10.
+# Minimum value: 0, maximum value: 100, default value: 10.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+UML_LIMIT_NUM_FIELDS = 10
+
+# If the TEMPLATE_RELATIONS tag is set to YES then the inheritance and
+# collaboration graphs will show the relations between templates and their
+# instances.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+TEMPLATE_RELATIONS = NO
+
+# If the INCLUDE_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are set to
+# YES then doxygen will generate a graph for each documented file showing the
+# direct and indirect include dependencies of the file with other documented
+# files.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INCLUDE_GRAPH = YES
+
+# If the INCLUDED_BY_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are
+# set to YES then doxygen will generate a graph for each documented file showing
+# the direct and indirect include dependencies of the file with other documented
+# files.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INCLUDED_BY_GRAPH = YES
+
+# If the CALL_GRAPH tag is set to YES then doxygen will generate a call
+# dependency graph for every global function or class method.
+#
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable call graphs for selected
+# functions only using the \callgraph command.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CALL_GRAPH = NO
+
+# If the CALLER_GRAPH tag is set to YES then doxygen will generate a caller
+# dependency graph for every global function or class method.
+#
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable caller graphs for selected
+# functions only using the \callergraph command.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CALLER_GRAPH = NO
+
+# If the GRAPHICAL_HIERARCHY tag is set to YES then doxygen will graphical
+# hierarchy of all classes instead of a textual one.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GRAPHICAL_HIERARCHY = YES
+
+# If the DIRECTORY_GRAPH tag is set to YES then doxygen will show the
+# dependencies a directory has on other directories in a graphical way. The
+# dependency relations are determined by the #include relations between the
+# files in the directories.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DIRECTORY_GRAPH = YES
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
+# generated by dot.
+# Note: If you choose svg you need to set HTML_FILE_EXTENSION to xhtml in order
+# to make the SVG files visible in IE 9+ (other browsers do not have this
+# requirement).
+# Possible values are: png, jpg, gif and svg.
+# The default value is: png.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_IMAGE_FORMAT = png
+
+# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to
+# enable generation of interactive SVG images that allow zooming and panning.
+#
+# Note that this requires a modern browser other than Internet Explorer. Tested
+# and working are Firefox, Chrome, Safari, and Opera.
+# Note: For IE 9+ you need to set HTML_FILE_EXTENSION to xhtml in order to make
+# the SVG files visible. Older versions of IE do not have SVG support.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INTERACTIVE_SVG = NO
+
+# The DOT_PATH tag can be used to specify the path where the dot tool can be
+# found. If left blank, it is assumed the dot tool can be found in the path.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_PATH =
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that
+# contain dot files that are included in the documentation (see the \dotfile
+# command).
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOTFILE_DIRS =
+
+# The MSCFILE_DIRS tag can be used to specify one or more directories that
+# contain msc files that are included in the documentation (see the \mscfile
+# command).
+
+MSCFILE_DIRS =
+
+# The DIAFILE_DIRS tag can be used to specify one or more directories that
+# contain dia files that are included in the documentation (see the \diafile
+# command).
+
+DIAFILE_DIRS =
+
+# When using plantuml, the PLANTUML_JAR_PATH tag should be used to specify the
+# path where java can find the plantuml.jar file. If left blank, it is assumed
+# PlantUML is not used or called during a preprocessing step. Doxygen will
+# generate a warning when it encounters a \startuml command in this case and
+# will not generate output for the diagram.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+PLANTUML_JAR_PATH =
+
+# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of nodes
+# that will be shown in the graph. If the number of nodes in a graph becomes
+# larger than this value, doxygen will truncate the graph, which is visualized
+# by representing a node as a red box. Note that doxygen if the number of direct
+# children of the root node in a graph is already larger than
+# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note that
+# the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
+# Minimum value: 0, maximum value: 10000, default value: 50.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_GRAPH_MAX_NODES = 50
+
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the graphs
+# generated by dot. A depth value of 3 means that only nodes reachable from the
+# root by following a path via at most 3 edges will be shown. Nodes that lay
+# further from the root node will be omitted. Note that setting this option to 1
+# or 2 may greatly reduce the computation time needed for large code bases. Also
+# note that the size of a graph can be further restricted by
+# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
+# Minimum value: 0, maximum value: 1000, default value: 0.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+MAX_DOT_GRAPH_DEPTH = 0
+
+# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
+# background. This is disabled by default, because dot on Windows does not seem
+# to support this out of the box.
+#
+# Warning: Depending on the platform used, enabling this option may lead to
+# badly anti-aliased labels on the edges of a graph (i.e. they become hard to
+# read).
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_TRANSPARENT = NO
+
+# Set the DOT_MULTI_TARGETS tag to YES to allow dot to generate multiple output
+# files in one run (i.e. multiple -o and -T options on the command line). This
+# makes dot run faster, but since only newer versions of dot (>1.8.10) support
+# this, this feature is disabled by default.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_MULTI_TARGETS = NO
+
+# If the GENERATE_LEGEND tag is set to YES doxygen will generate a legend page
+# explaining the meaning of the various boxes and arrows in the dot generated
+# graphs.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GENERATE_LEGEND = YES
+
+# If the DOT_CLEANUP tag is set to YES, doxygen will remove the intermediate dot
+# files that are used to generate the various graphs.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_CLEANUP = YES
--- /dev/null
+This directory contains an empty project for testing purposes.
+
+To regenerate the XML output located in `xml`, run `make`. If the `Makefile`
+does not exists, you can regenerate it by running `make bootstrap` in the parent
+directory.
--- /dev/null
+<!-- XSLT script to combine the generated output into a single file.
+ If you have xsltproc you could use:
+ xsltproc combine.xslt index.xml >all.xml
+-->
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
+ <xsl:output method="xml" version="1.0" indent="no" standalone="yes" />
+ <xsl:template match="/">
+ <doxygen version="{doxygenindex/@version}">
+ <!-- Load all doxgen generated xml files -->
+ <xsl:for-each select="doxygenindex/compound">
+ <xsl:copy-of select="document( concat( @refid, '.xml' ) )/doxygen/*" />
+ </xsl:for-each>
+ </doxygen>
+ </xsl:template>
+</xsl:stylesheet>
--- /dev/null
+<?xml version='1.0' encoding='utf-8' ?>
+<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
+ <xsd:element name="doxygen" type="DoxygenType"/>
+
+ <!-- Complex types -->
+
+ <xsd:complexType name="DoxygenType">
+ <xsd:sequence maxOccurs="unbounded">
+ <xsd:element name="compounddef" type="compounddefType" minOccurs="0" />
+ </xsd:sequence>
+ <xsd:attribute name="version" type="DoxVersionNumber" use="required" />
+ </xsd:complexType>
+
+ <xsd:complexType name="compounddefType">
+ <xsd:sequence>
+ <xsd:element name="compoundname" type="xsd:string"/>
+ <xsd:element name="title" type="xsd:string" minOccurs="0" />
+ <xsd:element name="basecompoundref" type="compoundRefType" minOccurs="0" maxOccurs="unbounded" />
+ <xsd:element name="derivedcompoundref" type="compoundRefType" minOccurs="0" maxOccurs="unbounded" />
+ <xsd:element name="includes" type="incType" minOccurs="0" maxOccurs="unbounded" />
+ <xsd:element name="includedby" type="incType" minOccurs="0" maxOccurs="unbounded" />
+ <xsd:element name="incdepgraph" type="graphType" minOccurs="0" />
+ <xsd:element name="invincdepgraph" type="graphType" minOccurs="0" />
+ <xsd:element name="innerdir" type="refType" minOccurs="0" maxOccurs="unbounded" />
+ <xsd:element name="innerfile" type="refType" minOccurs="0" maxOccurs="unbounded" />
+ <xsd:element name="innerclass" type="refType" minOccurs="0" maxOccurs="unbounded" />
+ <xsd:element name="innernamespace" type="refType" minOccurs="0" maxOccurs="unbounded" />
+ <xsd:element name="innerpage" type="refType" minOccurs="0" maxOccurs="unbounded" />
+ <xsd:element name="innergroup" type="refType" minOccurs="0" maxOccurs="unbounded" />
+ <xsd:element name="templateparamlist" type="templateparamlistType" minOccurs="0" />
+ <xsd:element name="sectiondef" type="sectiondefType" minOccurs="0" maxOccurs="unbounded" />
+ <xsd:element name="briefdescription" type="descriptionType" minOccurs="0" />
+ <xsd:element name="detaileddescription" type="descriptionType" minOccurs="0" />
+ <xsd:element name="inheritancegraph" type="graphType" minOccurs="0" />
+ <xsd:element name="collaborationgraph" type="graphType" minOccurs="0" />
+ <xsd:element name="programlisting" type="listingType" minOccurs="0" />
+ <xsd:element name="location" type="locationType" minOccurs="0" />
+ <xsd:element name="listofallmembers" type="listofallmembersType" minOccurs="0" />
+ </xsd:sequence>
+ <xsd:attribute name="id" type="xsd:string" />
+ <xsd:attribute name="kind" type="DoxCompoundKind" />
+ <xsd:attribute name="prot" type="DoxProtectionKind" />
+ <xsd:attribute name="final" type="DoxBool" use="optional"/>
+ <xsd:attribute name="sealed" type="DoxBool" use="optional"/>
+ <xsd:attribute name="abstract" type="DoxBool" use="optional"/>
+ </xsd:complexType>
+
+ <xsd:complexType name="listofallmembersType">
+ <xsd:sequence>
+ <xsd:element name="member" type="memberRefType" minOccurs="0" maxOccurs="unbounded" />
+ </xsd:sequence>
+ </xsd:complexType>
+
+ <xsd:complexType name="memberRefType">
+ <xsd:sequence>
+ <xsd:element name="scope" />
+ <xsd:element name="name" />
+ </xsd:sequence>
+ <xsd:attribute name="refid" type="xsd:string" />
+ <xsd:attribute name="prot" type="DoxProtectionKind" />
+ <xsd:attribute name="virt" type="DoxVirtualKind" />
+ <xsd:attribute name="ambiguityscope" type="xsd:string" />
+ </xsd:complexType>
+
+ <xsd:complexType name="compoundRefType">
+ <xsd:simpleContent>
+ <xsd:extension base="xsd:string">
+ <xsd:attribute name="refid" type="xsd:string" use="optional" />
+ <xsd:attribute name="prot" type="DoxProtectionKind" />
+ <xsd:attribute name="virt" type="DoxVirtualKind" />
+ </xsd:extension>
+ </xsd:simpleContent>
+ </xsd:complexType>
+
+ <xsd:complexType name="reimplementType">
+ <xsd:simpleContent>
+ <xsd:extension base="xsd:string">
+ <xsd:attribute name="refid" type="xsd:string" />
+ </xsd:extension>
+ </xsd:simpleContent>
+ </xsd:complexType>
+
+ <xsd:complexType name="incType">
+ <xsd:simpleContent>
+ <xsd:extension base="xsd:string">
+ <xsd:attribute name="refid" type="xsd:string" />
+ <xsd:attribute name="local" type="DoxBool" />
+ </xsd:extension>
+ </xsd:simpleContent>
+ </xsd:complexType>
+
+ <xsd:complexType name="refType">
+ <xsd:simpleContent>
+ <xsd:extension base="xsd:string">
+ <xsd:attribute name="refid" type="xsd:string" />
+ <xsd:attribute name="prot" type="DoxProtectionKind" use="optional"/>
+ </xsd:extension>
+ </xsd:simpleContent>
+ </xsd:complexType>
+
+ <xsd:complexType name="refTextType">
+ <xsd:simpleContent>
+ <xsd:extension base="xsd:string">
+ <xsd:attribute name="refid" type="xsd:string" />
+ <xsd:attribute name="kindref" type="DoxRefKind" />
+ <xsd:attribute name="external" type="xsd:string" use="optional"/>
+ <xsd:attribute name="tooltip" type="xsd:string" use="optional"/>
+ </xsd:extension>
+ </xsd:simpleContent>
+ </xsd:complexType>
+
+ <xsd:complexType name="sectiondefType">
+ <xsd:sequence>
+ <xsd:element name="header" type="xsd:string" minOccurs="0" />
+ <xsd:element name="description" type="descriptionType" minOccurs="0" />
+ <xsd:element name="memberdef" type="memberdefType" maxOccurs="unbounded" />
+ </xsd:sequence>
+ <xsd:attribute name="kind" type="DoxSectionKind" />
+ </xsd:complexType>
+
+ <xsd:complexType name="memberdefType">
+ <xsd:sequence>
+ <xsd:element name="templateparamlist" type="templateparamlistType" minOccurs="0" />
+ <xsd:element name="type" type="linkedTextType" minOccurs="0" />
+ <xsd:element name="definition" minOccurs="0" />
+ <xsd:element name="argsstring" minOccurs="0" />
+ <xsd:element name="name" />
+ <xsd:element name="read" minOccurs="0" />
+ <xsd:element name="write" minOccurs="0" />
+ <xsd:element name="bitfield" minOccurs="0" />
+ <xsd:element name="reimplements" type="reimplementType" minOccurs="0" maxOccurs="unbounded" />
+ <xsd:element name="reimplementedby" type="reimplementType" minOccurs="0" maxOccurs="unbounded" />
+ <xsd:element name="param" type="paramType" minOccurs="0" maxOccurs="unbounded" />
+ <xsd:element name="enumvalue" type="enumvalueType" minOccurs="0" maxOccurs="unbounded" />
+ <xsd:element name="initializer" type="linkedTextType" minOccurs="0" />
+ <xsd:element name="exceptions" type="linkedTextType" minOccurs="0" />
+ <xsd:element name="briefdescription" type="descriptionType" minOccurs="0" />
+ <xsd:element name="detaileddescription" type="descriptionType" minOccurs="0" />
+ <xsd:element name="inbodydescription" type="descriptionType" minOccurs="0" />
+ <xsd:element name="location" type="locationType" />
+ <xsd:element name="references" type="referenceType" minOccurs="0" maxOccurs="unbounded" />
+ <xsd:element name="referencedby" type="referenceType" minOccurs="0" maxOccurs="unbounded" />
+ </xsd:sequence>
+ <xsd:attribute name="kind" type="DoxMemberKind" />
+ <xsd:attribute name="id" type="xsd:string" />
+ <xsd:attribute name="prot" type="DoxProtectionKind" />
+ <xsd:attribute name="static" type="DoxBool" />
+ <xsd:attribute name="const" type="DoxBool" use="optional"/>
+ <xsd:attribute name="explicit" type="DoxBool" use="optional"/>
+ <xsd:attribute name="inline" type="DoxBool" use="optional"/>
+ <xsd:attribute name="virt" type="DoxVirtualKind" use="optional"/>
+ <xsd:attribute name="volatile" type="DoxBool" use="optional"/>
+ <xsd:attribute name="mutable" type="DoxBool" use="optional"/>
+ <!-- Qt property -->
+ <xsd:attribute name="readable" type="DoxBool" use="optional"/>
+ <xsd:attribute name="writable" type="DoxBool" use="optional"/>
+ <!-- C++/CLI variable -->
+ <xsd:attribute name="initonly" type="DoxBool" use="optional"/>
+ <!-- C++/CLI and C# property -->
+ <xsd:attribute name="settable" type="DoxBool" use="optional"/>
+ <xsd:attribute name="gettable" type="DoxBool" use="optional"/>
+ <!-- C++/CLI function -->
+ <xsd:attribute name="final" type="DoxBool" use="optional"/>
+ <xsd:attribute name="sealed" type="DoxBool" use="optional"/>
+ <xsd:attribute name="new" type="DoxBool" use="optional"/>
+ <!-- C++/CLI event -->
+ <xsd:attribute name="add" type="DoxBool" use="optional"/>
+ <xsd:attribute name="remove" type="DoxBool" use="optional"/>
+ <xsd:attribute name="raise" type="DoxBool" use="optional"/>
+ <!-- Objective-C 2.0 protocol method -->
+ <xsd:attribute name="optional" type="DoxBool" use="optional"/>
+ <xsd:attribute name="required" type="DoxBool" use="optional"/>
+ <!-- Objective-C 2.0 property accessor -->
+ <xsd:attribute name="accessor" type="DoxAccessor" use="optional"/>
+ <!-- UNO IDL -->
+ <xsd:attribute name="attribute" type="DoxBool" use="optional"/>
+ <xsd:attribute name="property" type="DoxBool" use="optional"/>
+ <xsd:attribute name="readonly" type="DoxBool" use="optional"/>
+ <xsd:attribute name="bound" type="DoxBool" use="optional"/>
+ <xsd:attribute name="removable" type="DoxBool" use="optional"/>
+ <xsd:attribute name="contrained" type="DoxBool" use="optional"/>
+ <xsd:attribute name="transient" type="DoxBool" use="optional"/>
+ <xsd:attribute name="maybevoid" type="DoxBool" use="optional"/>
+ <xsd:attribute name="maybedefault" type="DoxBool" use="optional"/>
+ <xsd:attribute name="maybeambiguous" type="DoxBool" use="optional"/>
+
+ </xsd:complexType>
+
+ <xsd:complexType name="descriptionType" mixed="true">
+ <xsd:sequence>
+ <xsd:element name="title" type="xsd:string" minOccurs="0"/>
+ <xsd:element name="para" type="docParaType" minOccurs="0" maxOccurs="unbounded" />
+ <xsd:element name="sect1" type="docSect1Type" minOccurs="0" maxOccurs="unbounded" />
+ <xsd:element name="internal" type="docInternalType" minOccurs="0" />
+ </xsd:sequence>
+ </xsd:complexType>
+
+ <xsd:complexType name="enumvalueType" mixed="true">
+ <xsd:sequence>
+ <xsd:element name="name" />
+ <xsd:element name="initializer" type="linkedTextType" minOccurs="0" />
+ <xsd:element name="briefdescription" type="descriptionType" minOccurs="0" />
+ <xsd:element name="detaileddescription" type="descriptionType" minOccurs="0" />
+ </xsd:sequence>
+ <xsd:attribute name="id" type="xsd:string" />
+ <xsd:attribute name="prot" type="DoxProtectionKind" />
+ </xsd:complexType>
+
+ <xsd:complexType name="templateparamlistType">
+ <xsd:sequence>
+ <xsd:element name="param" type="paramType" minOccurs="0" maxOccurs="unbounded" />
+ </xsd:sequence>
+ </xsd:complexType>
+
+ <xsd:complexType name="paramType">
+ <xsd:sequence>
+ <xsd:element name="type" type="linkedTextType" minOccurs="0" />
+ <xsd:element name="declname" minOccurs="0" />
+ <xsd:element name="defname" minOccurs="0" />
+ <xsd:element name="array" minOccurs="0" />
+ <xsd:element name="defval" type="linkedTextType" minOccurs="0" />
+ <xsd:element name="briefdescription" type="descriptionType" minOccurs="0" />
+ </xsd:sequence>
+ </xsd:complexType>
+
+ <xsd:complexType name="linkedTextType" mixed="true">
+ <xsd:sequence>
+ <xsd:element name="ref" type="refTextType" minOccurs="0" maxOccurs="unbounded" />
+ </xsd:sequence>
+ </xsd:complexType>
+
+ <xsd:complexType name="graphType">
+ <xsd:sequence>
+ <xsd:element name="node" type="nodeType" maxOccurs="unbounded" />
+ </xsd:sequence>
+ </xsd:complexType>
+
+ <xsd:complexType name="nodeType">
+ <xsd:sequence>
+ <xsd:element name="label" />
+ <xsd:element name="link" type="linkType" minOccurs="0" />
+ <xsd:element name="childnode" type="childnodeType" minOccurs="0" maxOccurs="unbounded" />
+ </xsd:sequence>
+ <xsd:attribute name="id" type="xsd:string" />
+ </xsd:complexType>
+
+ <xsd:complexType name="childnodeType">
+ <xsd:sequence>
+ <xsd:element name="edgelabel" minOccurs="0" maxOccurs="unbounded"/>
+ </xsd:sequence>
+ <xsd:attribute name="refid" type="xsd:string" />
+ <xsd:attribute name="relation" type="DoxGraphRelation" />
+ </xsd:complexType>
+
+ <xsd:complexType name="linkType">
+ <xsd:attribute name="refid" type="xsd:string" />
+ <xsd:attribute name="external" type="xsd:string" use="optional"/>
+ </xsd:complexType>
+
+ <xsd:complexType name="listingType">
+ <xsd:sequence>
+ <xsd:element name="codeline" type="codelineType" minOccurs="0" maxOccurs="unbounded" />
+ </xsd:sequence>
+ </xsd:complexType>
+
+ <xsd:complexType name="codelineType">
+ <xsd:sequence>
+ <xsd:element name="highlight" type="highlightType" minOccurs="0" maxOccurs="unbounded" />
+ </xsd:sequence>
+ <xsd:attribute name="lineno" type="xsd:integer" />
+ <xsd:attribute name="refid" type="xsd:string" />
+ <xsd:attribute name="refkind" type="DoxRefKind" />
+ <xsd:attribute name="external" type="DoxBool" />
+ </xsd:complexType>
+
+ <xsd:complexType name="highlightType" mixed="true">
+ <xsd:choice minOccurs="0" maxOccurs="unbounded">
+ <xsd:element name="sp" />
+ <xsd:element name="ref" type="refTextType" />
+ </xsd:choice>
+ <xsd:attribute name="class" type="DoxHighlightClass" />
+ </xsd:complexType>
+
+ <xsd:complexType name="referenceType" mixed="true">
+ <xsd:attribute name="refid" type="xsd:string" />
+ <xsd:attribute name="compoundref" type="xsd:string" use="optional" />
+ <xsd:attribute name="startline" type="xsd:integer" />
+ <xsd:attribute name="endline" type="xsd:integer" />
+ </xsd:complexType>
+
+ <xsd:complexType name="locationType">
+ <xsd:attribute name="file" type="xsd:string" />
+ <xsd:attribute name="line" type="xsd:integer" />
+ <xsd:attribute name="column" type="xsd:integer" use="optional"/>
+ <xsd:attribute name="bodyfile" type="xsd:string" />
+ <xsd:attribute name="bodystart" type="xsd:integer" />
+ <xsd:attribute name="bodyend" type="xsd:integer" />
+ </xsd:complexType>
+
+ <xsd:complexType name="docSect1Type" mixed="true">
+ <xsd:sequence>
+ <xsd:element name="title" type="xsd:string" />
+ <xsd:element name="para" type="docParaType" minOccurs="0" maxOccurs="unbounded" />
+ <xsd:element name="sect2" type="docSect2Type" minOccurs="0" maxOccurs="unbounded" />
+ <xsd:element name="internal" type="docInternalS1Type" minOccurs="0" />
+ </xsd:sequence>
+ <xsd:attribute name="id" type="xsd:string" />
+ </xsd:complexType>
+
+ <xsd:complexType name="docSect2Type" mixed="true">
+ <xsd:sequence>
+ <xsd:element name="title" type="xsd:string" />
+ <xsd:element name="para" type="docParaType" minOccurs="0" maxOccurs="unbounded" />
+ <xsd:element name="sect3" type="docSect3Type" minOccurs="0" maxOccurs="unbounded" />
+ <xsd:element name="internal" type="docInternalS2Type" minOccurs="0" />
+ </xsd:sequence>
+ <xsd:attribute name="id" type="xsd:string" />
+ </xsd:complexType>
+
+ <xsd:complexType name="docSect3Type" mixed="true">
+ <xsd:sequence>
+ <xsd:element name="title" type="xsd:string" />
+ <xsd:element name="para" type="docParaType" minOccurs="0" maxOccurs="unbounded" />
+ <xsd:element name="sect4" type="docSect4Type" minOccurs="0" maxOccurs="unbounded" />
+ <xsd:element name="internal" type="docInternalS3Type" minOccurs="0" />
+ </xsd:sequence>
+ <xsd:attribute name="id" type="xsd:string" />
+ </xsd:complexType>
+
+ <xsd:complexType name="docSect4Type" mixed="true">
+ <xsd:sequence>
+ <xsd:element name="title" type="xsd:string" />
+ <xsd:element name="para" type="docParaType" minOccurs="0" maxOccurs="unbounded" />
+ <xsd:element name="internal" type="docInternalS4Type" minOccurs="0" />
+ </xsd:sequence>
+ <xsd:attribute name="id" type="xsd:string" />
+ </xsd:complexType>
+
+ <xsd:complexType name="docInternalType" mixed="true">
+ <xsd:sequence>
+ <xsd:element name="para" type="docParaType" minOccurs="0" maxOccurs="unbounded" />
+ <xsd:element name="sect1" type="docSect1Type" minOccurs="0" maxOccurs="unbounded" />
+ </xsd:sequence>
+ </xsd:complexType>
+
+ <xsd:complexType name="docInternalS1Type" mixed="true">
+ <xsd:sequence>
+ <xsd:element name="para" type="docParaType" minOccurs="0" maxOccurs="unbounded" />
+ <xsd:element name="sect2" type="docSect2Type" minOccurs="0" maxOccurs="unbounded" />
+ </xsd:sequence>
+ </xsd:complexType>
+
+ <xsd:complexType name="docInternalS2Type" mixed="true">
+ <xsd:sequence>
+ <xsd:element name="para" type="docParaType" minOccurs="0" maxOccurs="unbounded" />
+ <xsd:element name="sect3" type="docSect3Type" minOccurs="0" maxOccurs="unbounded" />
+ </xsd:sequence>
+ </xsd:complexType>
+
+ <xsd:complexType name="docInternalS3Type" mixed="true">
+ <xsd:sequence>
+ <xsd:element name="para" type="docParaType" minOccurs="0" maxOccurs="unbounded" />
+ <xsd:element name="sect3" type="docSect4Type" minOccurs="0" maxOccurs="unbounded" />
+ </xsd:sequence>
+ </xsd:complexType>
+
+ <xsd:complexType name="docInternalS4Type" mixed="true">
+ <xsd:sequence>
+ <xsd:element name="para" type="docParaType" minOccurs="0" maxOccurs="unbounded" />
+ </xsd:sequence>
+ </xsd:complexType>
+
+ <xsd:group name="docTitleCmdGroup">
+ <xsd:choice>
+ <xsd:element name="ulink" type="docURLLink" />
+ <xsd:element name="bold" type="docMarkupType" />
+ <xsd:element name="emphasis" type="docMarkupType" />
+ <xsd:element name="computeroutput" type="docMarkupType" />
+ <xsd:element name="subscript" type="docMarkupType" />
+ <xsd:element name="superscript" type="docMarkupType" />
+ <xsd:element name="center" type="docMarkupType" />
+ <xsd:element name="small" type="docMarkupType" />
+ <xsd:element name="htmlonly" type="xsd:string" />
+ <xsd:element name="manonly" type="xsd:string" />
+ <xsd:element name="xmlonly" type="xsd:string" />
+ <xsd:element name="rtfonly" type="xsd:string" />
+ <xsd:element name="latexonly" type="xsd:string" />
+ <xsd:element name="dot" type="xsd:string" />
+ <xsd:element name="plantuml" type="xsd:string" />
+ <xsd:element name="anchor" type="docAnchorType" />
+ <xsd:element name="formula" type="docFormulaType" />
+ <xsd:element name="ref" type="docRefTextType" />
+ <xsd:element name="nonbreakablespace" type="docEmptyType" />
+ <xsd:element name="iexcl" type="docEmptyType" />
+ <xsd:element name="cent" type="docEmptyType" />
+ <xsd:element name="pound" type="docEmptyType" />
+ <xsd:element name="curren" type="docEmptyType" />
+ <xsd:element name="yen" type="docEmptyType" />
+ <xsd:element name="brvbar" type="docEmptyType" />
+ <xsd:element name="sect" type="docEmptyType" />
+ <xsd:element name="umlaut" type="docEmptyType" />
+ <xsd:element name="copy" type="docEmptyType" />
+ <xsd:element name="ordf" type="docEmptyType" />
+ <xsd:element name="laquo" type="docEmptyType" />
+ <xsd:element name="not" type="docEmptyType" />
+ <xsd:element name="shy" type="docEmptyType" />
+ <xsd:element name="registered" type="docEmptyType" />
+ <xsd:element name="macr" type="docEmptyType" />
+ <xsd:element name="deg" type="docEmptyType" />
+ <xsd:element name="plusmn" type="docEmptyType" />
+ <xsd:element name="sup2" type="docEmptyType" />
+ <xsd:element name="sup3" type="docEmptyType" />
+ <xsd:element name="acute" type="docEmptyType" />
+ <xsd:element name="micro" type="docEmptyType" />
+ <xsd:element name="para" type="docEmptyType" />
+ <xsd:element name="middot" type="docEmptyType" />
+ <xsd:element name="cedil" type="docEmptyType" />
+ <xsd:element name="sup1" type="docEmptyType" />
+ <xsd:element name="ordm" type="docEmptyType" />
+ <xsd:element name="raquo" type="docEmptyType" />
+ <xsd:element name="frac14" type="docEmptyType" />
+ <xsd:element name="frac12" type="docEmptyType" />
+ <xsd:element name="frac34" type="docEmptyType" />
+ <xsd:element name="iquest" type="docEmptyType" />
+ <xsd:element name="Agrave" type="docEmptyType" />
+ <xsd:element name="Aacute" type="docEmptyType" />
+ <xsd:element name="Acirc" type="docEmptyType" />
+ <xsd:element name="Atilde" type="docEmptyType" />
+ <xsd:element name="Aumlaut" type="docEmptyType" />
+ <xsd:element name="Aring" type="docEmptyType" />
+ <xsd:element name="AElig" type="docEmptyType" />
+ <xsd:element name="Ccedil" type="docEmptyType" />
+ <xsd:element name="Egrave" type="docEmptyType" />
+ <xsd:element name="Eacute" type="docEmptyType" />
+ <xsd:element name="Ecirc" type="docEmptyType" />
+ <xsd:element name="Eumlaut" type="docEmptyType" />
+ <xsd:element name="Igrave" type="docEmptyType" />
+ <xsd:element name="Iacute" type="docEmptyType" />
+ <xsd:element name="Icirc" type="docEmptyType" />
+ <xsd:element name="Iumlaut" type="docEmptyType" />
+ <xsd:element name="ETH" type="docEmptyType" />
+ <xsd:element name="Ntilde" type="docEmptyType" />
+ <xsd:element name="Ograve" type="docEmptyType" />
+ <xsd:element name="Oacute" type="docEmptyType" />
+ <xsd:element name="Ocirc" type="docEmptyType" />
+ <xsd:element name="Otilde" type="docEmptyType" />
+ <xsd:element name="Oumlaut" type="docEmptyType" />
+ <xsd:element name="times" type="docEmptyType" />
+ <xsd:element name="Oslash" type="docEmptyType" />
+ <xsd:element name="Ugrave" type="docEmptyType" />
+ <xsd:element name="Uacute" type="docEmptyType" />
+ <xsd:element name="Ucirc" type="docEmptyType" />
+ <xsd:element name="Uumlaut" type="docEmptyType" />
+ <xsd:element name="Yacute" type="docEmptyType" />
+ <xsd:element name="THORN" type="docEmptyType" />
+ <xsd:element name="szlig" type="docEmptyType" />
+ <xsd:element name="agrave" type="docEmptyType" />
+ <xsd:element name="aacute" type="docEmptyType" />
+ <xsd:element name="acirc" type="docEmptyType" />
+ <xsd:element name="atilde" type="docEmptyType" />
+ <xsd:element name="aumlaut" type="docEmptyType" />
+ <xsd:element name="aring" type="docEmptyType" />
+ <xsd:element name="aelig" type="docEmptyType" />
+ <xsd:element name="ccedil" type="docEmptyType" />
+ <xsd:element name="egrave" type="docEmptyType" />
+ <xsd:element name="eacute" type="docEmptyType" />
+ <xsd:element name="ecirc" type="docEmptyType" />
+ <xsd:element name="eumlaut" type="docEmptyType" />
+ <xsd:element name="igrave" type="docEmptyType" />
+ <xsd:element name="iacute" type="docEmptyType" />
+ <xsd:element name="icirc" type="docEmptyType" />
+ <xsd:element name="iumlaut" type="docEmptyType" />
+ <xsd:element name="eth" type="docEmptyType" />
+ <xsd:element name="ntilde" type="docEmptyType" />
+ <xsd:element name="ograve" type="docEmptyType" />
+ <xsd:element name="oacute" type="docEmptyType" />
+ <xsd:element name="ocirc" type="docEmptyType" />
+ <xsd:element name="otilde" type="docEmptyType" />
+ <xsd:element name="oumlaut" type="docEmptyType" />
+ <xsd:element name="divide" type="docEmptyType" />
+ <xsd:element name="oslash" type="docEmptyType" />
+ <xsd:element name="ugrave" type="docEmptyType" />
+ <xsd:element name="uacute" type="docEmptyType" />
+ <xsd:element name="ucirc" type="docEmptyType" />
+ <xsd:element name="uumlaut" type="docEmptyType" />
+ <xsd:element name="yacute" type="docEmptyType" />
+ <xsd:element name="thorn" type="docEmptyType" />
+ <xsd:element name="yumlaut" type="docEmptyType" />
+ <xsd:element name="fnof" type="docEmptyType" />
+ <xsd:element name="Alpha" type="docEmptyType" />
+ <xsd:element name="Beta" type="docEmptyType" />
+ <xsd:element name="Gamma" type="docEmptyType" />
+ <xsd:element name="Delta" type="docEmptyType" />
+ <xsd:element name="Epsilon" type="docEmptyType" />
+ <xsd:element name="Zeta" type="docEmptyType" />
+ <xsd:element name="Eta" type="docEmptyType" />
+ <xsd:element name="Theta" type="docEmptyType" />
+ <xsd:element name="Iota" type="docEmptyType" />
+ <xsd:element name="Kappa" type="docEmptyType" />
+ <xsd:element name="Lambda" type="docEmptyType" />
+ <xsd:element name="Mu" type="docEmptyType" />
+ <xsd:element name="Nu" type="docEmptyType" />
+ <xsd:element name="Xi" type="docEmptyType" />
+ <xsd:element name="Omicron" type="docEmptyType" />
+ <xsd:element name="Pi" type="docEmptyType" />
+ <xsd:element name="Rho" type="docEmptyType" />
+ <xsd:element name="Sigma" type="docEmptyType" />
+ <xsd:element name="Tau" type="docEmptyType" />
+ <xsd:element name="Upsilon" type="docEmptyType" />
+ <xsd:element name="Phi" type="docEmptyType" />
+ <xsd:element name="Chi" type="docEmptyType" />
+ <xsd:element name="Psi" type="docEmptyType" />
+ <xsd:element name="Omega" type="docEmptyType" />
+ <xsd:element name="alpha" type="docEmptyType" />
+ <xsd:element name="beta" type="docEmptyType" />
+ <xsd:element name="gamma" type="docEmptyType" />
+ <xsd:element name="delta" type="docEmptyType" />
+ <xsd:element name="epsilon" type="docEmptyType" />
+ <xsd:element name="zeta" type="docEmptyType" />
+ <xsd:element name="eta" type="docEmptyType" />
+ <xsd:element name="theta" type="docEmptyType" />
+ <xsd:element name="iota" type="docEmptyType" />
+ <xsd:element name="kappa" type="docEmptyType" />
+ <xsd:element name="lambda" type="docEmptyType" />
+ <xsd:element name="mu" type="docEmptyType" />
+ <xsd:element name="nu" type="docEmptyType" />
+ <xsd:element name="xi" type="docEmptyType" />
+ <xsd:element name="omicron" type="docEmptyType" />
+ <xsd:element name="pi" type="docEmptyType" />
+ <xsd:element name="rho" type="docEmptyType" />
+ <xsd:element name="sigmaf" type="docEmptyType" />
+ <xsd:element name="sigma" type="docEmptyType" />
+ <xsd:element name="tau" type="docEmptyType" />
+ <xsd:element name="upsilon" type="docEmptyType" />
+ <xsd:element name="phi" type="docEmptyType" />
+ <xsd:element name="chi" type="docEmptyType" />
+ <xsd:element name="psi" type="docEmptyType" />
+ <xsd:element name="omega" type="docEmptyType" />
+ <xsd:element name="thetasym" type="docEmptyType" />
+ <xsd:element name="upsih" type="docEmptyType" />
+ <xsd:element name="piv" type="docEmptyType" />
+ <xsd:element name="bull" type="docEmptyType" />
+ <xsd:element name="hellip" type="docEmptyType" />
+ <xsd:element name="prime" type="docEmptyType" />
+ <xsd:element name="Prime" type="docEmptyType" />
+ <xsd:element name="oline" type="docEmptyType" />
+ <xsd:element name="frasl" type="docEmptyType" />
+ <xsd:element name="weierp" type="docEmptyType" />
+ <xsd:element name="image" type="docEmptyType" />
+ <xsd:element name="real" type="docEmptyType" />
+ <xsd:element name="trademark" type="docEmptyType" />
+ <xsd:element name="alefsym" type="docEmptyType" />
+ <xsd:element name="larr" type="docEmptyType" />
+ <xsd:element name="uarr" type="docEmptyType" />
+ <xsd:element name="rarr" type="docEmptyType" />
+ <xsd:element name="darr" type="docEmptyType" />
+ <xsd:element name="harr" type="docEmptyType" />
+ <xsd:element name="crarr" type="docEmptyType" />
+ <xsd:element name="lArr" type="docEmptyType" />
+ <xsd:element name="uArr" type="docEmptyType" />
+ <xsd:element name="rArr" type="docEmptyType" />
+ <xsd:element name="dArr" type="docEmptyType" />
+ <xsd:element name="hArr" type="docEmptyType" />
+ <xsd:element name="forall" type="docEmptyType" />
+ <xsd:element name="part" type="docEmptyType" />
+ <xsd:element name="exist" type="docEmptyType" />
+ <xsd:element name="empty" type="docEmptyType" />
+ <xsd:element name="nabla" type="docEmptyType" />
+ <xsd:element name="isin" type="docEmptyType" />
+ <xsd:element name="notin" type="docEmptyType" />
+ <xsd:element name="ni" type="docEmptyType" />
+ <xsd:element name="prod" type="docEmptyType" />
+ <xsd:element name="sum" type="docEmptyType" />
+ <xsd:element name="minus" type="docEmptyType" />
+ <xsd:element name="lowast" type="docEmptyType" />
+ <xsd:element name="radic" type="docEmptyType" />
+ <xsd:element name="prop" type="docEmptyType" />
+ <xsd:element name="infin" type="docEmptyType" />
+ <xsd:element name="ang" type="docEmptyType" />
+ <xsd:element name="and" type="docEmptyType" />
+ <xsd:element name="or" type="docEmptyType" />
+ <xsd:element name="cap" type="docEmptyType" />
+ <xsd:element name="cup" type="docEmptyType" />
+ <xsd:element name="int" type="docEmptyType" />
+ <xsd:element name="there4" type="docEmptyType" />
+ <xsd:element name="sim" type="docEmptyType" />
+ <xsd:element name="cong" type="docEmptyType" />
+ <xsd:element name="asymp" type="docEmptyType" />
+ <xsd:element name="ne" type="docEmptyType" />
+ <xsd:element name="equiv" type="docEmptyType" />
+ <xsd:element name="le" type="docEmptyType" />
+ <xsd:element name="ge" type="docEmptyType" />
+ <xsd:element name="sub" type="docEmptyType" />
+ <xsd:element name="sup" type="docEmptyType" />
+ <xsd:element name="nsub" type="docEmptyType" />
+ <xsd:element name="sube" type="docEmptyType" />
+ <xsd:element name="supe" type="docEmptyType" />
+ <xsd:element name="oplus" type="docEmptyType" />
+ <xsd:element name="otimes" type="docEmptyType" />
+ <xsd:element name="perp" type="docEmptyType" />
+ <xsd:element name="sdot" type="docEmptyType" />
+ <xsd:element name="lceil" type="docEmptyType" />
+ <xsd:element name="rceil" type="docEmptyType" />
+ <xsd:element name="lfloor" type="docEmptyType" />
+ <xsd:element name="rfloor" type="docEmptyType" />
+ <xsd:element name="lang" type="docEmptyType" />
+ <xsd:element name="rang" type="docEmptyType" />
+ <xsd:element name="loz" type="docEmptyType" />
+ <xsd:element name="spades" type="docEmptyType" />
+ <xsd:element name="clubs" type="docEmptyType" />
+ <xsd:element name="hearts" type="docEmptyType" />
+ <xsd:element name="diams" type="docEmptyType" />
+ <xsd:element name="OElig" type="docEmptyType" />
+ <xsd:element name="oelig" type="docEmptyType" />
+ <xsd:element name="Scaron" type="docEmptyType" />
+ <xsd:element name="scaron" type="docEmptyType" />
+ <xsd:element name="Yumlaut" type="docEmptyType" />
+ <xsd:element name="circ" type="docEmptyType" />
+ <xsd:element name="tilde" type="docEmptyType" />
+ <xsd:element name="ensp" type="docEmptyType" />
+ <xsd:element name="emsp" type="docEmptyType" />
+ <xsd:element name="thinsp" type="docEmptyType" />
+ <xsd:element name="zwnj" type="docEmptyType" />
+ <xsd:element name="zwj" type="docEmptyType" />
+ <xsd:element name="lrm" type="docEmptyType" />
+ <xsd:element name="rlm" type="docEmptyType" />
+ <xsd:element name="ndash" type="docEmptyType" />
+ <xsd:element name="mdash" type="docEmptyType" />
+ <xsd:element name="lsquo" type="docEmptyType" />
+ <xsd:element name="rsquo" type="docEmptyType" />
+ <xsd:element name="sbquo" type="docEmptyType" />
+ <xsd:element name="ldquo" type="docEmptyType" />
+ <xsd:element name="rdquo" type="docEmptyType" />
+ <xsd:element name="bdquo" type="docEmptyType" />
+ <xsd:element name="dagger" type="docEmptyType" />
+ <xsd:element name="Dagger" type="docEmptyType" />
+ <xsd:element name="permil" type="docEmptyType" />
+ <xsd:element name="lsaquo" type="docEmptyType" />
+ <xsd:element name="rsaquo" type="docEmptyType" />
+ <xsd:element name="euro" type="docEmptyType" />
+ <xsd:element name="trademark" type="docEmptyType" />
+ </xsd:choice>
+ </xsd:group>
+
+ <xsd:complexType name="docTitleType" mixed="true">
+ <xsd:group ref="docTitleCmdGroup" minOccurs="0" maxOccurs="unbounded" />
+ </xsd:complexType>
+
+ <xsd:group name="docCmdGroup">
+ <xsd:choice>
+ <xsd:group ref="docTitleCmdGroup"/>
+ <xsd:element name="linebreak" type="docEmptyType" />
+ <xsd:element name="hruler" type="docEmptyType" />
+ <xsd:element name="preformatted" type="docMarkupType" />
+ <xsd:element name="programlisting" type="listingType" />
+ <xsd:element name="verbatim" type="xsd:string" />
+ <xsd:element name="indexentry" type="docIndexEntryType" />
+ <xsd:element name="orderedlist" type="docListType" />
+ <xsd:element name="itemizedlist" type="docListType" />
+ <xsd:element name="simplesect" type="docSimpleSectType" />
+ <xsd:element name="title" type="docTitleType" />
+ <xsd:element name="variablelist" type="docVariableListType" />
+ <xsd:element name="table" type="docTableType" />
+ <xsd:element name="heading" type="docHeadingType" />
+ <xsd:element name="image" type="docImageType" />
+ <xsd:element name="dotfile" type="docFileType" />
+ <xsd:element name="mscfile" type="docFileType" />
+ <xsd:element name="diafile" type="docFileType" />
+ <xsd:element name="toclist" type="docTocListType" />
+ <xsd:element name="language" type="docLanguageType" />
+ <xsd:element name="parameterlist" type="docParamListType" />
+ <xsd:element name="xrefsect" type="docXRefSectType" />
+ <xsd:element name="copydoc" type="docCopyType" />
+ <xsd:element name="blockquote" type="docBlockQuoteType" />
+ <xsd:element name="parblock" type="docParBlockType" />
+ </xsd:choice>
+ </xsd:group>
+
+ <xsd:complexType name="docParaType" mixed="true">
+ <xsd:group ref="docCmdGroup" minOccurs="0" maxOccurs="unbounded" />
+ </xsd:complexType>
+
+ <xsd:complexType name="docMarkupType" mixed="true">
+ <xsd:group ref="docCmdGroup" minOccurs="0" maxOccurs="unbounded" />
+ </xsd:complexType>
+
+ <xsd:complexType name="docURLLink" mixed="true">
+ <xsd:group ref="docTitleCmdGroup" minOccurs="0" maxOccurs="unbounded" />
+ <xsd:attribute name="url" type="xsd:string" />
+ </xsd:complexType>
+
+ <xsd:complexType name="docAnchorType" mixed="true">
+ <xsd:attribute name="id" type="xsd:string" />
+ </xsd:complexType>
+
+ <xsd:complexType name="docFormulaType" mixed="true">
+ <xsd:attribute name="id" type="xsd:string" />
+ </xsd:complexType>
+
+ <xsd:complexType name="docIndexEntryType">
+ <xsd:sequence>
+ <xsd:element name="primaryie" type="xsd:string" />
+ <xsd:element name="secondaryie" type="xsd:string" />
+ </xsd:sequence>
+ </xsd:complexType>
+
+ <xsd:complexType name="docListType">
+ <xsd:sequence>
+ <xsd:element name="listitem" type="docListItemType" maxOccurs="unbounded" />
+ </xsd:sequence>
+ </xsd:complexType>
+
+ <xsd:complexType name="docListItemType">
+ <xsd:sequence>
+ <xsd:element name="para" type="docParaType" minOccurs="0" maxOccurs="unbounded" />
+ </xsd:sequence>
+ </xsd:complexType>
+
+ <xsd:complexType name="docSimpleSectType">
+ <xsd:sequence>
+ <xsd:element name="title" type="docTitleType" minOccurs="0" />
+ <xsd:sequence minOccurs="0" maxOccurs="unbounded">
+ <xsd:element name="para" type="docParaType" minOccurs="1" maxOccurs="unbounded" />
+ </xsd:sequence>
+ </xsd:sequence>
+ <xsd:attribute name="kind" type="DoxSimpleSectKind" />
+ </xsd:complexType>
+
+ <xsd:complexType name="docVarListEntryType">
+ <xsd:sequence>
+ <xsd:element name="term" type="docTitleType" />
+ </xsd:sequence>
+ </xsd:complexType>
+
+ <xsd:group name="docVariableListGroup">
+ <xsd:sequence>
+ <xsd:element name="varlistentry" type="docVarListEntryType" />
+ <xsd:element name="listitem" type="docListItemType" />
+ </xsd:sequence>
+ </xsd:group>
+
+ <xsd:complexType name="docVariableListType">
+ <xsd:sequence>
+ <xsd:group ref="docVariableListGroup" maxOccurs="unbounded" />
+ </xsd:sequence>
+ </xsd:complexType>
+
+ <xsd:complexType name="docRefTextType" mixed="true">
+ <xsd:group ref="docTitleCmdGroup" minOccurs="0" maxOccurs="unbounded" />
+ <xsd:attribute name="refid" type="xsd:string" />
+ <xsd:attribute name="kindref" type="DoxRefKind" />
+ <xsd:attribute name="external" type="xsd:string" />
+ </xsd:complexType>
+
+ <xsd:complexType name="docTableType">
+ <xsd:sequence>
+ <xsd:element name="row" type="docRowType" minOccurs="0" maxOccurs="unbounded" />
+ <xsd:element name="caption" type="docCaptionType" minOccurs="0" />
+ </xsd:sequence>
+ <xsd:attribute name="rows" type="xsd:integer" />
+ <xsd:attribute name="cols" type="xsd:integer" />
+ </xsd:complexType>
+
+ <xsd:complexType name="docRowType">
+ <xsd:sequence>
+ <xsd:element name="entry" type="docEntryType" minOccurs="0" maxOccurs="unbounded" />
+ </xsd:sequence>
+ </xsd:complexType>
+
+ <xsd:complexType name="docEntryType">
+ <xsd:sequence>
+ <xsd:element name="para" type="docParaType" minOccurs="0" maxOccurs="unbounded" />
+ </xsd:sequence>
+ <xsd:attribute name="thead" type="DoxBool" />
+ </xsd:complexType>
+
+ <xsd:complexType name="docCaptionType" mixed="true">
+ <xsd:group ref="docTitleCmdGroup" minOccurs="0" maxOccurs="unbounded" />
+ </xsd:complexType>
+
+ <xsd:complexType name="docHeadingType" mixed="true">
+ <xsd:group ref="docTitleCmdGroup" minOccurs="0" maxOccurs="unbounded" />
+ <xsd:attribute name="level" type="xsd:integer" /> <!-- todo: range 1-6 -->
+ </xsd:complexType>
+
+ <xsd:complexType name="docImageType" mixed="true">
+ <xsd:group ref="docTitleCmdGroup" minOccurs="0" maxOccurs="unbounded" />
+ <xsd:attribute name="type" type="DoxImageKind" />
+ <xsd:attribute name="name" type="xsd:string" />
+ <xsd:attribute name="width" type="xsd:string" />
+ <xsd:attribute name="height" type="xsd:string" />
+ </xsd:complexType>
+
+ <xsd:complexType name="docFileType" mixed="true">
+ <xsd:group ref="docTitleCmdGroup" minOccurs="0" maxOccurs="unbounded" />
+ <xsd:attribute name="name" type="xsd:string" />
+ </xsd:complexType>
+
+ <xsd:complexType name="docTocItemType" mixed="true">
+ <xsd:group ref="docTitleCmdGroup" minOccurs="0" maxOccurs="unbounded" />
+ <xsd:attribute name="id" type="xsd:string" />
+ </xsd:complexType>
+
+ <xsd:complexType name="docTocListType">
+ <xsd:sequence>
+ <xsd:element name="tocitem" type="docTocItemType" minOccurs="0" maxOccurs="unbounded" />
+ </xsd:sequence>
+ </xsd:complexType>
+
+ <xsd:complexType name="docLanguageType">
+ <xsd:sequence>
+ <xsd:element name="para" type="docParaType" minOccurs="0" maxOccurs="unbounded" />
+ </xsd:sequence>
+ <xsd:attribute name="langid" type="xsd:string" />
+ </xsd:complexType>
+
+ <xsd:complexType name="docParamListType">
+ <xsd:sequence>
+ <xsd:element name="parameteritem" type="docParamListItem" minOccurs="0" maxOccurs="unbounded" />
+ </xsd:sequence>
+ <xsd:attribute name="kind" type="DoxParamListKind" />
+ </xsd:complexType>
+
+ <xsd:complexType name="docParamListItem">
+ <xsd:sequence>
+ <xsd:element name="parameternamelist" type="docParamNameList" minOccurs="0" maxOccurs="unbounded" />
+ <xsd:element name="parameterdescription" type="descriptionType" />
+ </xsd:sequence>
+ </xsd:complexType>
+
+ <xsd:complexType name="docParamNameList">
+ <xsd:sequence>
+ <xsd:element name="parametertype" type="docParamType" minOccurs="0" maxOccurs="unbounded" />
+ <xsd:element name="parametername" type="docParamName" minOccurs="0" maxOccurs="unbounded" />
+ </xsd:sequence>
+ </xsd:complexType>
+
+ <xsd:complexType name="docParamType" mixed="true">
+ <xsd:sequence>
+ <xsd:element name="ref" type="refTextType" minOccurs="0" maxOccurs="1" />
+ </xsd:sequence>
+ </xsd:complexType>
+
+ <xsd:complexType name="docParamName" mixed="true">
+ <xsd:sequence>
+ <xsd:element name="ref" type="refTextType" minOccurs="0" maxOccurs="1" />
+ </xsd:sequence>
+ <xsd:attribute name="direction" type="DoxParamDir" use="optional" />
+ </xsd:complexType>
+
+ <xsd:complexType name="docXRefSectType">
+ <xsd:sequence>
+ <xsd:element name="xreftitle" type="xsd:string" minOccurs="0" maxOccurs="unbounded" />
+ <xsd:element name="xrefdescription" type="descriptionType" />
+ </xsd:sequence>
+ <xsd:attribute name="id" type="xsd:string" />
+ </xsd:complexType>
+
+ <xsd:complexType name="docCopyType">
+ <xsd:sequence>
+ <xsd:element name="para" type="docParaType" minOccurs="0" maxOccurs="unbounded" />
+ <xsd:element name="sect1" type="docSect1Type" minOccurs="0" maxOccurs="unbounded" />
+ <xsd:element name="internal" type="docInternalType" minOccurs="0" />
+ </xsd:sequence>
+ <xsd:attribute name="link" type="xsd:string" />
+ </xsd:complexType>
+
+ <xsd:complexType name="docBlockQuoteType">
+ <xsd:sequence>
+ <xsd:element name="para" type="docParaType" minOccurs="0" maxOccurs="unbounded" />
+ </xsd:sequence>
+ </xsd:complexType>
+
+ <xsd:complexType name="docParBlockType">
+ <xsd:sequence>
+ <xsd:element name="para" type="docParaType" minOccurs="0" maxOccurs="unbounded" />
+ </xsd:sequence>
+ </xsd:complexType>
+
+ <xsd:complexType name="docEmptyType"/>
+
+ <!-- Simple types -->
+
+ <xsd:simpleType name="DoxBool">
+ <xsd:restriction base="xsd:string">
+ <xsd:enumeration value="yes" />
+ <xsd:enumeration value="no" />
+ </xsd:restriction>
+ </xsd:simpleType>
+
+ <xsd:simpleType name="DoxGraphRelation">
+ <xsd:restriction base="xsd:string">
+ <xsd:enumeration value="include" />
+ <xsd:enumeration value="usage" />
+ <xsd:enumeration value="template-instance" />
+ <xsd:enumeration value="public-inheritance" />
+ <xsd:enumeration value="protected-inheritance" />
+ <xsd:enumeration value="private-inheritance" />
+ </xsd:restriction>
+ </xsd:simpleType>
+
+ <xsd:simpleType name="DoxRefKind">
+ <xsd:restriction base="xsd:string">
+ <xsd:enumeration value="compound" />
+ <xsd:enumeration value="member" />
+ </xsd:restriction>
+ </xsd:simpleType>
+
+ <xsd:simpleType name="DoxMemberKind">
+ <xsd:restriction base="xsd:string">
+ <xsd:enumeration value="define" />
+ <xsd:enumeration value="property" />
+ <xsd:enumeration value="event" />
+ <xsd:enumeration value="variable" />
+ <xsd:enumeration value="typedef" />
+ <xsd:enumeration value="enum" />
+ <xsd:enumeration value="function" />
+ <xsd:enumeration value="signal" />
+ <xsd:enumeration value="prototype" />
+ <xsd:enumeration value="friend" />
+ <xsd:enumeration value="dcop" />
+ <xsd:enumeration value="slot" />
+ <xsd:enumeration value="interface" />
+ <xsd:enumeration value="service" />
+ </xsd:restriction>
+ </xsd:simpleType>
+
+ <xsd:simpleType name="DoxProtectionKind">
+ <xsd:restriction base="xsd:string">
+ <xsd:enumeration value="public" />
+ <xsd:enumeration value="protected" />
+ <xsd:enumeration value="private" />
+ <xsd:enumeration value="package" />
+ </xsd:restriction>
+ </xsd:simpleType>
+
+ <xsd:simpleType name="DoxVirtualKind">
+ <xsd:restriction base="xsd:string">
+ <xsd:enumeration value="non-virtual" />
+ <xsd:enumeration value="virtual" />
+ <xsd:enumeration value="pure-virtual" />
+ </xsd:restriction>
+ </xsd:simpleType>
+
+ <xsd:simpleType name="DoxCompoundKind">
+ <xsd:restriction base="xsd:string">
+ <xsd:enumeration value="class" />
+ <xsd:enumeration value="struct" />
+ <xsd:enumeration value="union" />
+ <xsd:enumeration value="interface" />
+ <xsd:enumeration value="protocol" />
+ <xsd:enumeration value="category" />
+ <xsd:enumeration value="exception" />
+ <xsd:enumeration value="service" />
+ <xsd:enumeration value="singleton" />
+ <xsd:enumeration value="module" />
+ <xsd:enumeration value="type" />
+ <xsd:enumeration value="file" />
+ <xsd:enumeration value="namespace" />
+ <xsd:enumeration value="group" />
+ <xsd:enumeration value="page" />
+ <xsd:enumeration value="example" />
+ <xsd:enumeration value="dir" />
+ </xsd:restriction>
+ </xsd:simpleType>
+
+ <xsd:simpleType name="DoxSectionKind">
+ <xsd:restriction base="xsd:string">
+ <xsd:enumeration value="user-defined" />
+ <xsd:enumeration value="public-type" />
+ <xsd:enumeration value="public-func" />
+ <xsd:enumeration value="public-attrib" />
+ <xsd:enumeration value="public-slot" />
+ <xsd:enumeration value="signal" />
+ <xsd:enumeration value="dcop-func" />
+ <xsd:enumeration value="property" />
+ <xsd:enumeration value="event" />
+ <xsd:enumeration value="public-static-func" />
+ <xsd:enumeration value="public-static-attrib" />
+ <xsd:enumeration value="protected-type" />
+ <xsd:enumeration value="protected-func" />
+ <xsd:enumeration value="protected-attrib" />
+ <xsd:enumeration value="protected-slot" />
+ <xsd:enumeration value="protected-static-func" />
+ <xsd:enumeration value="protected-static-attrib" />
+ <xsd:enumeration value="package-type" />
+ <xsd:enumeration value="package-func" />
+ <xsd:enumeration value="package-attrib" />
+ <xsd:enumeration value="package-static-func" />
+ <xsd:enumeration value="package-static-attrib" />
+ <xsd:enumeration value="private-type" />
+ <xsd:enumeration value="private-func" />
+ <xsd:enumeration value="private-attrib" />
+ <xsd:enumeration value="private-slot" />
+ <xsd:enumeration value="private-static-func" />
+ <xsd:enumeration value="private-static-attrib" />
+ <xsd:enumeration value="friend" />
+ <xsd:enumeration value="related" />
+ <xsd:enumeration value="define" />
+ <xsd:enumeration value="prototype" />
+ <xsd:enumeration value="typedef" />
+ <xsd:enumeration value="enum" />
+ <xsd:enumeration value="func" />
+ <xsd:enumeration value="var" />
+ </xsd:restriction>
+ </xsd:simpleType>
+
+ <xsd:simpleType name="DoxHighlightClass">
+ <xsd:restriction base="xsd:string">
+ <xsd:enumeration value="comment" />
+ <xsd:enumeration value="normal" />
+ <xsd:enumeration value="preprocessor" />
+ <xsd:enumeration value="keyword" />
+ <xsd:enumeration value="keywordtype" />
+ <xsd:enumeration value="keywordflow" />
+ <xsd:enumeration value="stringliteral" />
+ <xsd:enumeration value="charliteral" />
+ </xsd:restriction>
+ </xsd:simpleType>
+
+ <xsd:simpleType name="DoxSimpleSectKind">
+ <xsd:restriction base="xsd:string">
+ <xsd:enumeration value="see" />
+ <xsd:enumeration value="return" />
+ <xsd:enumeration value="author" />
+ <xsd:enumeration value="authors" />
+ <xsd:enumeration value="version" />
+ <xsd:enumeration value="since" />
+ <xsd:enumeration value="date" />
+ <xsd:enumeration value="note" />
+ <xsd:enumeration value="warning" />
+ <xsd:enumeration value="pre" />
+ <xsd:enumeration value="post" />
+ <xsd:enumeration value="copyright" />
+ <xsd:enumeration value="invariant" />
+ <xsd:enumeration value="remark" />
+ <xsd:enumeration value="attention" />
+ <xsd:enumeration value="par" />
+ <xsd:enumeration value="rcs" />
+ </xsd:restriction>
+ </xsd:simpleType>
+
+ <xsd:simpleType name="DoxVersionNumber">
+ <xsd:restriction base="xsd:string">
+ <xsd:pattern value="\d+\.\d+.*" />
+ </xsd:restriction>
+ </xsd:simpleType>
+
+ <xsd:simpleType name="DoxImageKind">
+ <xsd:restriction base="xsd:string">
+ <xsd:enumeration value="html" />
+ <xsd:enumeration value="latex" />
+ <xsd:enumeration value="rtf" />
+ </xsd:restriction>
+ </xsd:simpleType>
+
+ <xsd:simpleType name="DoxParamListKind">
+ <xsd:restriction base="xsd:string">
+ <xsd:enumeration value="param" />
+ <xsd:enumeration value="retval" />
+ <xsd:enumeration value="exception" />
+ <xsd:enumeration value="templateparam" />
+ </xsd:restriction>
+ </xsd:simpleType>
+
+ <xsd:simpleType name="DoxCharRange">
+ <xsd:restriction base="xsd:string">
+ <xsd:pattern value="[aeiouncAEIOUNC]" />
+ </xsd:restriction>
+ </xsd:simpleType>
+
+ <xsd:simpleType name="DoxParamDir">
+ <xsd:restriction base="xsd:string">
+ <xsd:enumeration value="in"/>
+ <xsd:enumeration value="out"/>
+ <xsd:enumeration value="inout"/>
+ </xsd:restriction>
+ </xsd:simpleType>
+
+ <xsd:simpleType name="DoxAccessor">
+ <xsd:restriction base="xsd:string">
+ <xsd:enumeration value="retain"/>
+ <xsd:enumeration value="copy"/>
+ <xsd:enumeration value="assign"/>
+ <xsd:enumeration value="weak"/>
+ <xsd:enumeration value="strong"/>
+ <xsd:enumeration value="unretained"/>
+ </xsd:restriction>
+ </xsd:simpleType>
+
+</xsd:schema>
+
--- /dev/null
+<?xml version='1.0' encoding='UTF-8' standalone='no'?>
+<doxygenindex xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="index.xsd" version="1.8.8">
+</doxygenindex>
--- /dev/null
+<?xml version='1.0' encoding='utf-8' ?>
+<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
+ <xsd:element name="doxygenindex" type="DoxygenType"/>
+
+ <xsd:complexType name="DoxygenType">
+ <xsd:sequence>
+ <xsd:element name="compound" type="CompoundType" minOccurs="0" maxOccurs="unbounded"/>
+ </xsd:sequence>
+ <xsd:attribute name="version" type="xsd:string" use="required"/>
+ </xsd:complexType>
+
+ <xsd:complexType name="CompoundType">
+ <xsd:sequence>
+ <xsd:element name="name" type="xsd:string"/>
+ <xsd:element name="member" type="MemberType" minOccurs="0" maxOccurs="unbounded"/>
+ </xsd:sequence>
+ <xsd:attribute name="refid" type="xsd:string" use="required"/>
+ <xsd:attribute name="kind" type="CompoundKind" use="required"/>
+ </xsd:complexType>
+
+ <xsd:complexType name="MemberType">
+ <xsd:sequence>
+ <xsd:element name="name" type="xsd:string"/>
+ </xsd:sequence>
+ <xsd:attribute name="refid" type="xsd:string" use="required"/>
+ <xsd:attribute name="kind" type="MemberKind" use="required"/>
+ </xsd:complexType>
+
+ <xsd:simpleType name="CompoundKind">
+ <xsd:restriction base="xsd:string">
+ <xsd:enumeration value="class"/>
+ <xsd:enumeration value="struct"/>
+ <xsd:enumeration value="union"/>
+ <xsd:enumeration value="interface"/>
+ <xsd:enumeration value="protocol"/>
+ <xsd:enumeration value="category"/>
+ <xsd:enumeration value="exception"/>
+ <xsd:enumeration value="file"/>
+ <xsd:enumeration value="namespace"/>
+ <xsd:enumeration value="group"/>
+ <xsd:enumeration value="page"/>
+ <xsd:enumeration value="example"/>
+ <xsd:enumeration value="dir"/>
+ </xsd:restriction>
+ </xsd:simpleType>
+
+ <xsd:simpleType name="MemberKind">
+ <xsd:restriction base="xsd:string">
+ <xsd:enumeration value="define"/>
+ <xsd:enumeration value="property"/>
+ <xsd:enumeration value="event"/>
+ <xsd:enumeration value="variable"/>
+ <xsd:enumeration value="typedef"/>
+ <xsd:enumeration value="enum"/>
+ <xsd:enumeration value="enumvalue"/>
+ <xsd:enumeration value="function"/>
+ <xsd:enumeration value="signal"/>
+ <xsd:enumeration value="prototype"/>
+ <xsd:enumeration value="friend"/>
+ <xsd:enumeration value="dcop"/>
+ <xsd:enumeration value="slot"/>
+ </xsd:restriction>
+ </xsd:simpleType>
+
+</xsd:schema>
+
--- /dev/null
+# Doxyfile 1.8.8
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project.
+#
+# All text after a double hash (##) is considered a comment and is placed in
+# front of the TAG it is preceding.
+#
+# All text after a single hash (#) is considered a comment and will be ignored.
+# The format is:
+# TAG = value [value, ...]
+# For lists, items can also be appended using:
+# TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (\" \").
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# This tag specifies the encoding used for all characters in the config file
+# that follow. The default is UTF-8 which is also the encoding used for all text
+# before the first occurrence of this tag. Doxygen uses libiconv (or the iconv
+# built into libc) for the transcoding. See http://www.gnu.org/software/libiconv
+# for the list of possible encodings.
+# The default value is: UTF-8.
+
+DOXYFILE_ENCODING = UTF-8
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by
+# double-quotes, unless you are using Doxywizard) that should identify the
+# project for which the documentation is generated. This name is used in the
+# title of most generated pages and in a few other places.
+# The default value is: My Project.
+
+PROJECT_NAME = "Test Project"
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number. This
+# could be handy for archiving the generated documentation or if some version
+# control system is used.
+
+PROJECT_NUMBER =
+
+# Using the PROJECT_BRIEF tag one can provide an optional one line description
+# for a project that appears at the top of each page and should give viewer a
+# quick idea about the purpose of the project. Keep the description short.
+
+PROJECT_BRIEF =
+
+# With the PROJECT_LOGO tag one can specify a logo or an icon that is included
+# in the documentation. The maximum height of the logo should not exceed 55
+# pixels and the maximum width should not exceed 200 pixels. Doxygen will copy
+# the logo to the output directory.
+
+PROJECT_LOGO =
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path
+# into which the generated documentation will be written. If a relative path is
+# entered, it will be relative to the location where doxygen was started. If
+# left blank the current directory will be used.
+
+OUTPUT_DIRECTORY =
+
+# If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub-
+# directories (in 2 levels) under the output directory of each output format and
+# will distribute the generated files over these directories. Enabling this
+# option can be useful when feeding doxygen a huge amount of source files, where
+# putting all generated files in the same directory would otherwise causes
+# performance problems for the file system.
+# The default value is: NO.
+
+CREATE_SUBDIRS = NO
+
+# If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII
+# characters to appear in the names of generated files. If set to NO, non-ASCII
+# characters will be escaped, for example _xE3_x81_x84 will be used for Unicode
+# U+3044.
+# The default value is: NO.
+
+ALLOW_UNICODE_NAMES = NO
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all
+# documentation generated by doxygen is written. Doxygen will use this
+# information to generate all constant output in the proper language.
+# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese,
+# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States),
+# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian,
+# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages),
+# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian,
+# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian,
+# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish,
+# Ukrainian and Vietnamese.
+# The default value is: English.
+
+OUTPUT_LANGUAGE = English
+
+# If the BRIEF_MEMBER_DESC tag is set to YES, doxygen will include brief member
+# descriptions after the members that are listed in the file and class
+# documentation (similar to Javadoc). Set to NO to disable this.
+# The default value is: YES.
+
+BRIEF_MEMBER_DESC = YES
+
+# If the REPEAT_BRIEF tag is set to YES, doxygen will prepend the brief
+# description of a member or function before the detailed description
+#
+# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
+# brief descriptions will be completely suppressed.
+# The default value is: YES.
+
+REPEAT_BRIEF = YES
+
+# This tag implements a quasi-intelligent brief description abbreviator that is
+# used to form the text in various listings. Each string in this list, if found
+# as the leading text of the brief description, will be stripped from the text
+# and the result, after processing the whole list, is used as the annotated
+# text. Otherwise, the brief description is used as-is. If left blank, the
+# following values are used ($name is automatically replaced with the name of
+# the entity):The $name class, The $name widget, The $name file, is, provides,
+# specifies, contains, represents, a, an and the.
+
+ABBREVIATE_BRIEF = "The $name class" \
+ "The $name widget" \
+ "The $name file" \
+ is \
+ provides \
+ specifies \
+ contains \
+ represents \
+ a \
+ an \
+ the
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
+# doxygen will generate a detailed section even if there is only a brief
+# description.
+# The default value is: NO.
+
+ALWAYS_DETAILED_SEC = NO
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
+# inherited members of a class in the documentation of that class as if those
+# members were ordinary class members. Constructors, destructors and assignment
+# operators of the base classes will not be shown.
+# The default value is: NO.
+
+INLINE_INHERITED_MEMB = NO
+
+# If the FULL_PATH_NAMES tag is set to YES, doxygen will prepend the full path
+# before files name in the file list and in the header files. If set to NO the
+# shortest path that makes the file name unique will be used
+# The default value is: YES.
+
+FULL_PATH_NAMES = YES
+
+# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path.
+# Stripping is only done if one of the specified strings matches the left-hand
+# part of the path. The tag can be used to show relative paths in the file list.
+# If left blank the directory from which doxygen is run is used as the path to
+# strip.
+#
+# Note that you can specify absolute paths here, but also relative paths, which
+# will be relative from the directory where doxygen is started.
+# This tag requires that the tag FULL_PATH_NAMES is set to YES.
+
+STRIP_FROM_PATH =
+
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the
+# path mentioned in the documentation of a class, which tells the reader which
+# header file to include in order to use a class. If left blank only the name of
+# the header file containing the class definition is used. Otherwise one should
+# specify the list of include paths that are normally passed to the compiler
+# using the -I flag.
+
+STRIP_FROM_INC_PATH =
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but
+# less readable) file names. This can be useful is your file systems doesn't
+# support long names like on DOS, Mac, or CD-ROM.
+# The default value is: NO.
+
+SHORT_NAMES = NO
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the
+# first line (until the first dot) of a Javadoc-style comment as the brief
+# description. If set to NO, the Javadoc-style will behave just like regular Qt-
+# style comments (thus requiring an explicit @brief command for a brief
+# description.)
+# The default value is: NO.
+
+JAVADOC_AUTOBRIEF = NO
+
+# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first
+# line (until the first dot) of a Qt-style comment as the brief description. If
+# set to NO, the Qt-style will behave just like regular Qt-style comments (thus
+# requiring an explicit \brief command for a brief description.)
+# The default value is: NO.
+
+QT_AUTOBRIEF = NO
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a
+# multi-line C++ special comment block (i.e. a block of //! or /// comments) as
+# a brief description. This used to be the default behavior. The new default is
+# to treat a multi-line C++ comment block as a detailed description. Set this
+# tag to YES if you prefer the old behavior instead.
+#
+# Note that setting this tag to YES also means that rational rose comments are
+# not recognized any more.
+# The default value is: NO.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the
+# documentation from any documented member that it re-implements.
+# The default value is: YES.
+
+INHERIT_DOCS = YES
+
+# If the SEPARATE_MEMBER_PAGES tag is set to YES then doxygen will produce a new
+# page for each member. If set to NO, the documentation of a member will be part
+# of the file/class/namespace that contains it.
+# The default value is: NO.
+
+SEPARATE_MEMBER_PAGES = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen
+# uses this value to replace tabs by spaces in code fragments.
+# Minimum value: 1, maximum value: 16, default value: 4.
+
+TAB_SIZE = 4
+
+# This tag can be used to specify a number of aliases that act as commands in
+# the documentation. An alias has the form:
+# name=value
+# For example adding
+# "sideeffect=@par Side Effects:\n"
+# will allow you to put the command \sideeffect (or @sideeffect) in the
+# documentation, which will result in a user-defined paragraph with heading
+# "Side Effects:". You can put \n's in the value part of an alias to insert
+# newlines.
+
+ALIASES =
+
+# This tag can be used to specify a number of word-keyword mappings (TCL only).
+# A mapping has the form "name=value". For example adding "class=itcl::class"
+# will allow you to use the command class in the itcl::class meaning.
+
+TCL_SUBST =
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources
+# only. Doxygen will then generate output that is more tailored for C. For
+# instance, some of the names that are used will be different. The list of all
+# members will be omitted, etc.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_FOR_C = NO
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or
+# Python sources only. Doxygen will then generate output that is more tailored
+# for that language. For instance, namespaces will be presented as packages,
+# qualified scopes will look different, etc.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_JAVA = YES
+
+# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran
+# sources. Doxygen will then generate output that is tailored for Fortran.
+# The default value is: NO.
+
+OPTIMIZE_FOR_FORTRAN = NO
+
+# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL
+# sources. Doxygen will then generate output that is tailored for VHDL.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_VHDL = NO
+
+# Doxygen selects the parser to use depending on the extension of the files it
+# parses. With this tag you can assign which parser to use for a given
+# extension. Doxygen has a built-in mapping, but you can override or extend it
+# using this tag. The format is ext=language, where ext is a file extension, and
+# language is one of the parsers supported by doxygen: IDL, Java, Javascript,
+# C#, C, C++, D, PHP, Objective-C, Python, Fortran (fixed format Fortran:
+# FortranFixed, free formatted Fortran: FortranFree, unknown formatted Fortran:
+# Fortran. In the later case the parser tries to guess whether the code is fixed
+# or free formatted code, this is the default for Fortran type files), VHDL. For
+# instance to make doxygen treat .inc files as Fortran files (default is PHP),
+# and .f files as C (default is Fortran), use: inc=Fortran f=C.
+#
+# Note: For files without extension you can use no_extension as a placeholder.
+#
+# Note that for custom extensions you also need to set FILE_PATTERNS otherwise
+# the files are not read by doxygen.
+
+EXTENSION_MAPPING =
+
+# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments
+# according to the Markdown format, which allows for more readable
+# documentation. See http://daringfireball.net/projects/markdown/ for details.
+# The output of markdown processing is further processed by doxygen, so you can
+# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in
+# case of backward compatibilities issues.
+# The default value is: YES.
+
+MARKDOWN_SUPPORT = YES
+
+# When enabled doxygen tries to link words that correspond to documented
+# classes, or namespaces to their corresponding documentation. Such a link can
+# be prevented in individual cases by putting a % sign in front of the word or
+# globally by setting AUTOLINK_SUPPORT to NO.
+# The default value is: YES.
+
+AUTOLINK_SUPPORT = YES
+
+# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
+# to include (a tag file for) the STL sources as input, then you should set this
+# tag to YES in order to let doxygen match functions declarations and
+# definitions whose arguments contain STL classes (e.g. func(std::string);
+# versus func(std::string) {}). This also make the inheritance and collaboration
+# diagrams that involve STL classes more complete and accurate.
+# The default value is: NO.
+
+BUILTIN_STL_SUPPORT = NO
+
+# If you use Microsoft's C++/CLI language, you should set this option to YES to
+# enable parsing support.
+# The default value is: NO.
+
+CPP_CLI_SUPPORT = NO
+
+# Set the SIP_SUPPORT tag to YES if your project consists of sip (see:
+# http://www.riverbankcomputing.co.uk/software/sip/intro) sources only. Doxygen
+# will parse them like normal C++ but will assume all classes use public instead
+# of private inheritance when no explicit protection keyword is present.
+# The default value is: NO.
+
+SIP_SUPPORT = NO
+
+# For Microsoft's IDL there are propget and propput attributes to indicate
+# getter and setter methods for a property. Setting this option to YES will make
+# doxygen to replace the get and set methods by a property in the documentation.
+# This will only work if the methods are indeed getting or setting a simple
+# type. If this is not the case, or you want to show the methods anyway, you
+# should set this option to NO.
+# The default value is: YES.
+
+IDL_PROPERTY_SUPPORT = YES
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
+# tag is set to YES then doxygen will reuse the documentation of the first
+# member in the group (if any) for the other members of the group. By default
+# all members of a group must be documented explicitly.
+# The default value is: NO.
+
+DISTRIBUTE_GROUP_DOC = NO
+
+# Set the SUBGROUPING tag to YES to allow class member groups of the same type
+# (for instance a group of public functions) to be put as a subgroup of that
+# type (e.g. under the Public Functions section). Set it to NO to prevent
+# subgrouping. Alternatively, this can be done per class using the
+# \nosubgrouping command.
+# The default value is: YES.
+
+SUBGROUPING = YES
+
+# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions
+# are shown inside the group in which they are included (e.g. using \ingroup)
+# instead of on a separate page (for HTML and Man pages) or section (for LaTeX
+# and RTF).
+#
+# Note that this feature does not work in combination with
+# SEPARATE_MEMBER_PAGES.
+# The default value is: NO.
+
+INLINE_GROUPED_CLASSES = NO
+
+# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions
+# with only public data fields or simple typedef fields will be shown inline in
+# the documentation of the scope in which they are defined (i.e. file,
+# namespace, or group documentation), provided this scope is documented. If set
+# to NO, structs, classes, and unions are shown on a separate page (for HTML and
+# Man pages) or section (for LaTeX and RTF).
+# The default value is: NO.
+
+INLINE_SIMPLE_STRUCTS = NO
+
+# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or
+# enum is documented as struct, union, or enum with the name of the typedef. So
+# typedef struct TypeS {} TypeT, will appear in the documentation as a struct
+# with name TypeT. When disabled the typedef will appear as a member of a file,
+# namespace, or class. And the struct will be named TypeS. This can typically be
+# useful for C code in case the coding convention dictates that all compound
+# types are typedef'ed and only the typedef is referenced, never the tag name.
+# The default value is: NO.
+
+TYPEDEF_HIDES_STRUCT = NO
+
+# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This
+# cache is used to resolve symbols given their name and scope. Since this can be
+# an expensive process and often the same symbol appears multiple times in the
+# code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small
+# doxygen will become slower. If the cache is too large, memory is wasted. The
+# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range
+# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536
+# symbols. At the end of a run doxygen will report the cache usage and suggest
+# the optimal cache size from a speed point of view.
+# Minimum value: 0, maximum value: 9, default value: 0.
+
+LOOKUP_CACHE_SIZE = 0
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# If the EXTRACT_ALL tag is set to YES, doxygen will assume all entities in
+# documentation are documented, even if no documentation was available. Private
+# class members and static file members will be hidden unless the
+# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES.
+# Note: This will also disable the warnings about undocumented members that are
+# normally produced when WARNINGS is set to YES.
+# The default value is: NO.
+
+EXTRACT_ALL = NO
+
+# If the EXTRACT_PRIVATE tag is set to YES, all private members of a class will
+# be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PRIVATE = NO
+
+# If the EXTRACT_PACKAGE tag is set to YES, all members with package or internal
+# scope will be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PACKAGE = NO
+
+# If the EXTRACT_STATIC tag is set to YES, all static members of a file will be
+# included in the documentation.
+# The default value is: NO.
+
+EXTRACT_STATIC = NO
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES, classes (and structs) defined
+# locally in source files will be included in the documentation. If set to NO,
+# only classes defined in header files are included. Does not have any effect
+# for Java sources.
+# The default value is: YES.
+
+EXTRACT_LOCAL_CLASSES = YES
+
+# This flag is only useful for Objective-C code. If set to YES, local methods,
+# which are defined in the implementation section but not in the interface are
+# included in the documentation. If set to NO, only methods in the interface are
+# included.
+# The default value is: NO.
+
+EXTRACT_LOCAL_METHODS = NO
+
+# If this flag is set to YES, the members of anonymous namespaces will be
+# extracted and appear in the documentation as a namespace called
+# 'anonymous_namespace{file}', where file will be replaced with the base name of
+# the file that contains the anonymous namespace. By default anonymous namespace
+# are hidden.
+# The default value is: NO.
+
+EXTRACT_ANON_NSPACES = NO
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all
+# undocumented members inside documented classes or files. If set to NO these
+# members will be included in the various overviews, but no documentation
+# section is generated. This option has no effect if EXTRACT_ALL is enabled.
+# The default value is: NO.
+
+HIDE_UNDOC_MEMBERS = NO
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all
+# undocumented classes that are normally visible in the class hierarchy. If set
+# to NO, these classes will be included in the various overviews. This option
+# has no effect if EXTRACT_ALL is enabled.
+# The default value is: NO.
+
+HIDE_UNDOC_CLASSES = NO
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend
+# (class|struct|union) declarations. If set to NO, these declarations will be
+# included in the documentation.
+# The default value is: NO.
+
+HIDE_FRIEND_COMPOUNDS = NO
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any
+# documentation blocks found inside the body of a function. If set to NO, these
+# blocks will be appended to the function's detailed documentation block.
+# The default value is: NO.
+
+HIDE_IN_BODY_DOCS = NO
+
+# The INTERNAL_DOCS tag determines if documentation that is typed after a
+# \internal command is included. If the tag is set to NO then the documentation
+# will be excluded. Set it to YES to include the internal documentation.
+# The default value is: NO.
+
+INTERNAL_DOCS = NO
+
+# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file
+# names in lower-case letters. If set to YES, upper-case letters are also
+# allowed. This is useful if you have classes or files whose names only differ
+# in case and if your file system supports case sensitive file names. Windows
+# and Mac users are advised to set this option to NO.
+# The default value is: system dependent.
+
+CASE_SENSE_NAMES = NO
+
+# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with
+# their full class and namespace scopes in the documentation. If set to YES, the
+# scope will be hidden.
+# The default value is: NO.
+
+HIDE_SCOPE_NAMES = NO
+
+# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of
+# the files that are included by a file in the documentation of that file.
+# The default value is: YES.
+
+SHOW_INCLUDE_FILES = YES
+
+# If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each
+# grouped member an include statement to the documentation, telling the reader
+# which file to include in order to use the member.
+# The default value is: NO.
+
+SHOW_GROUPED_MEMB_INC = NO
+
+# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include
+# files with double quotes in the documentation rather than with sharp brackets.
+# The default value is: NO.
+
+FORCE_LOCAL_INCLUDES = NO
+
+# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the
+# documentation for inline members.
+# The default value is: YES.
+
+INLINE_INFO = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the
+# (detailed) documentation of file and class members alphabetically by member
+# name. If set to NO, the members will appear in declaration order.
+# The default value is: YES.
+
+SORT_MEMBER_DOCS = YES
+
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief
+# descriptions of file, namespace and class members alphabetically by member
+# name. If set to NO, the members will appear in declaration order. Note that
+# this will also influence the order of the classes in the class list.
+# The default value is: NO.
+
+SORT_BRIEF_DOCS = NO
+
+# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the
+# (brief and detailed) documentation of class members so that constructors and
+# destructors are listed first. If set to NO the constructors will appear in the
+# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS.
+# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief
+# member documentation.
+# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting
+# detailed member documentation.
+# The default value is: NO.
+
+SORT_MEMBERS_CTORS_1ST = NO
+
+# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy
+# of group names into alphabetical order. If set to NO the group names will
+# appear in their defined order.
+# The default value is: NO.
+
+SORT_GROUP_NAMES = NO
+
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by
+# fully-qualified names, including namespaces. If set to NO, the class list will
+# be sorted only by class name, not including the namespace part.
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
+# Note: This option applies only to the class list, not to the alphabetical
+# list.
+# The default value is: NO.
+
+SORT_BY_SCOPE_NAME = NO
+
+# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper
+# type resolution of all parameters of a function it will reject a match between
+# the prototype and the implementation of a member function even if there is
+# only one candidate or it is obvious which candidate to choose by doing a
+# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still
+# accept a match between prototype and implementation in such cases.
+# The default value is: NO.
+
+STRICT_PROTO_MATCHING = NO
+
+# The GENERATE_TODOLIST tag can be used to enable (YES) or disable (NO) the todo
+# list. This list is created by putting \todo commands in the documentation.
+# The default value is: YES.
+
+GENERATE_TODOLIST = YES
+
+# The GENERATE_TESTLIST tag can be used to enable (YES) or disable (NO) the test
+# list. This list is created by putting \test commands in the documentation.
+# The default value is: YES.
+
+GENERATE_TESTLIST = YES
+
+# The GENERATE_BUGLIST tag can be used to enable (YES) or disable (NO) the bug
+# list. This list is created by putting \bug commands in the documentation.
+# The default value is: YES.
+
+GENERATE_BUGLIST = YES
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or disable (NO)
+# the deprecated list. This list is created by putting \deprecated commands in
+# the documentation.
+# The default value is: YES.
+
+GENERATE_DEPRECATEDLIST= YES
+
+# The ENABLED_SECTIONS tag can be used to enable conditional documentation
+# sections, marked by \if <section_label> ... \endif and \cond <section_label>
+# ... \endcond blocks.
+
+ENABLED_SECTIONS =
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the
+# initial value of a variable or macro / define can have for it to appear in the
+# documentation. If the initializer consists of more lines than specified here
+# it will be hidden. Use a value of 0 to hide initializers completely. The
+# appearance of the value of individual variables and macros / defines can be
+# controlled using \showinitializer or \hideinitializer command in the
+# documentation regardless of this setting.
+# Minimum value: 0, maximum value: 10000, default value: 30.
+
+MAX_INITIALIZER_LINES = 30
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at
+# the bottom of the documentation of classes and structs. If set to YES, the
+# list will mention the files that were used to generate the documentation.
+# The default value is: YES.
+
+SHOW_USED_FILES = YES
+
+# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This
+# will remove the Files entry from the Quick Index and from the Folder Tree View
+# (if specified).
+# The default value is: YES.
+
+SHOW_FILES = YES
+
+# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces
+# page. This will remove the Namespaces entry from the Quick Index and from the
+# Folder Tree View (if specified).
+# The default value is: YES.
+
+SHOW_NAMESPACES = YES
+
+# The FILE_VERSION_FILTER tag can be used to specify a program or script that
+# doxygen should invoke to get the current version for each file (typically from
+# the version control system). Doxygen will invoke the program by executing (via
+# popen()) the command command input-file, where command is the value of the
+# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided
+# by doxygen. Whatever the program writes to standard output is used as the file
+# version. For an example see the documentation.
+
+FILE_VERSION_FILTER =
+
+# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed
+# by doxygen. The layout file controls the global structure of the generated
+# output files in an output format independent way. To create the layout file
+# that represents doxygen's defaults, run doxygen with the -l option. You can
+# optionally specify a file name after the option, if omitted DoxygenLayout.xml
+# will be used as the name of the layout file.
+#
+# Note that if you run doxygen from a directory containing a file called
+# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE
+# tag is left empty.
+
+LAYOUT_FILE =
+
+# The CITE_BIB_FILES tag can be used to specify one or more bib files containing
+# the reference definitions. This must be a list of .bib files. The .bib
+# extension is automatically appended if omitted. This requires the bibtex tool
+# to be installed. See also http://en.wikipedia.org/wiki/BibTeX for more info.
+# For LaTeX the style of the bibliography can be controlled using
+# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the
+# search path. See also \cite for info how to create references.
+
+CITE_BIB_FILES =
+
+#---------------------------------------------------------------------------
+# Configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated to
+# standard output by doxygen. If QUIET is set to YES this implies that the
+# messages are off.
+# The default value is: NO.
+
+QUIET = NO
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are
+# generated to standard error (stderr) by doxygen. If WARNINGS is set to YES
+# this implies that the warnings are on.
+#
+# Tip: Turn warnings on while writing the documentation.
+# The default value is: YES.
+
+WARNINGS = YES
+
+# If the WARN_IF_UNDOCUMENTED tag is set to YES then doxygen will generate
+# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag
+# will automatically be disabled.
+# The default value is: YES.
+
+WARN_IF_UNDOCUMENTED = YES
+
+# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for
+# potential errors in the documentation, such as not documenting some parameters
+# in a documented function, or documenting parameters that don't exist or using
+# markup commands wrongly.
+# The default value is: YES.
+
+WARN_IF_DOC_ERROR = YES
+
+# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that
+# are documented, but have no documentation for their parameters or return
+# value. If set to NO, doxygen will only warn about wrong or incomplete
+# parameter documentation, but not about the absence of documentation.
+# The default value is: NO.
+
+WARN_NO_PARAMDOC = NO
+
+# The WARN_FORMAT tag determines the format of the warning messages that doxygen
+# can produce. The string should contain the $file, $line, and $text tags, which
+# will be replaced by the file and line number from which the warning originated
+# and the warning text. Optionally the format may contain $version, which will
+# be replaced by the version of the file (if it could be obtained via
+# FILE_VERSION_FILTER)
+# The default value is: $file:$line: $text.
+
+WARN_FORMAT = "$file:$line: $text"
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning and error
+# messages should be written. If left blank the output is written to standard
+# error (stderr).
+
+WARN_LOGFILE =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag is used to specify the files and/or directories that contain
+# documented source files. You may enter file names like myfile.cpp or
+# directories like /usr/src/myproject. Separate the files or directories with
+# spaces.
+# Note: If this tag is empty the current directory is searched.
+
+INPUT = src
+
+# This tag can be used to specify the character encoding of the source files
+# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
+# libiconv (or the iconv built into libc) for the transcoding. See the libiconv
+# documentation (see: http://www.gnu.org/software/libiconv) for the list of
+# possible encodings.
+# The default value is: UTF-8.
+
+INPUT_ENCODING = UTF-8
+
+# If the value of the INPUT tag contains directories, you can use the
+# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and
+# *.h) to filter out the source-files in the directories. If left blank the
+# following patterns are tested:*.c, *.cc, *.cxx, *.cpp, *.c++, *.java, *.ii,
+# *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, *.hh, *.hxx, *.hpp,
+# *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, *.m, *.markdown,
+# *.md, *.mm, *.dox, *.py, *.f90, *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf,
+# *.qsf, *.as and *.js.
+
+FILE_PATTERNS = *.c \
+ *.cc \
+ *.cxx \
+ *.cpp \
+ *.c++ \
+ *.java \
+ *.ii \
+ *.ixx \
+ *.ipp \
+ *.i++ \
+ *.inl \
+ *.idl \
+ *.ddl \
+ *.odl \
+ *.h \
+ *.hh \
+ *.hxx \
+ *.hpp \
+ *.h++ \
+ *.cs \
+ *.d \
+ *.php \
+ *.php4 \
+ *.php5 \
+ *.phtml \
+ *.inc \
+ *.m \
+ *.markdown \
+ *.md \
+ *.mm \
+ *.dox \
+ *.py \
+ *.f90 \
+ *.f \
+ *.for \
+ *.tcl \
+ *.vhd \
+ *.vhdl \
+ *.ucf \
+ *.qsf \
+ *.as \
+ *.js
+
+# The RECURSIVE tag can be used to specify whether or not subdirectories should
+# be searched for input files as well.
+# The default value is: NO.
+
+RECURSIVE = YES
+
+# The EXCLUDE tag can be used to specify files and/or directories that should be
+# excluded from the INPUT source files. This way you can easily exclude a
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+#
+# Note that relative paths are relative to the directory from which doxygen is
+# run.
+
+EXCLUDE =
+
+# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or
+# directories that are symbolic links (a Unix file system feature) are excluded
+# from the input.
+# The default value is: NO.
+
+EXCLUDE_SYMLINKS = NO
+
+# If the value of the INPUT tag contains directories, you can use the
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
+# certain files from those directories.
+#
+# Note that the wildcards are matched against the file with absolute path, so to
+# exclude all test directories for example use the pattern */test/*
+
+EXCLUDE_PATTERNS =
+
+# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
+# (namespaces, classes, functions, etc.) that should be excluded from the
+# output. The symbol name can be a fully qualified name, a word, or if the
+# wildcard * is used, a substring. Examples: ANamespace, AClass,
+# AClass::ANamespace, ANamespace::*Test
+#
+# Note that the wildcards are matched against the file with absolute path, so to
+# exclude all test directories use the pattern */test/*
+
+EXCLUDE_SYMBOLS =
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or directories
+# that contain example code fragments that are included (see the \include
+# command).
+
+EXAMPLE_PATH =
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and
+# *.h) to filter out the source-files in the directories. If left blank all
+# files are included.
+
+EXAMPLE_PATTERNS = *
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
+# searched for input files to be used with the \include or \dontinclude commands
+# irrespective of the value of the RECURSIVE tag.
+# The default value is: NO.
+
+EXAMPLE_RECURSIVE = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or directories
+# that contain images that are to be included in the documentation (see the
+# \image command).
+
+IMAGE_PATH =
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should
+# invoke to filter for each input file. Doxygen will invoke the filter program
+# by executing (via popen()) the command:
+#
+# <filter> <input-file>
+#
+# where <filter> is the value of the INPUT_FILTER tag, and <input-file> is the
+# name of an input file. Doxygen will then use the output that the filter
+# program writes to standard output. If FILTER_PATTERNS is specified, this tag
+# will be ignored.
+#
+# Note that the filter must not add or remove lines; it is applied before the
+# code is scanned, but not when the output code is generated. If lines are added
+# or removed, the anchors will not be placed correctly.
+
+INPUT_FILTER =
+
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
+# basis. Doxygen will compare the file name with each pattern and apply the
+# filter if there is a match. The filters are a list of the form: pattern=filter
+# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how
+# filters are used. If the FILTER_PATTERNS tag is empty or if none of the
+# patterns match the file name, INPUT_FILTER is applied.
+
+FILTER_PATTERNS =
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
+# INPUT_FILTER) will also be used to filter the input files that are used for
+# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES).
+# The default value is: NO.
+
+FILTER_SOURCE_FILES = NO
+
+# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file
+# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and
+# it is also possible to disable source filtering for a specific pattern using
+# *.ext= (so without naming a filter).
+# This tag requires that the tag FILTER_SOURCE_FILES is set to YES.
+
+FILTER_SOURCE_PATTERNS =
+
+# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that
+# is part of the input, its contents will be placed on the main page
+# (index.html). This can be useful if you have a project on for instance GitHub
+# and want to reuse the introduction page also for the doxygen output.
+
+USE_MDFILE_AS_MAINPAGE =
+
+#---------------------------------------------------------------------------
+# Configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will be
+# generated. Documented entities will be cross-referenced with these sources.
+#
+# Note: To get rid of all source code in the generated output, make sure that
+# also VERBATIM_HEADERS is set to NO.
+# The default value is: NO.
+
+SOURCE_BROWSER = NO
+
+# Setting the INLINE_SOURCES tag to YES will include the body of functions,
+# classes and enums directly into the documentation.
+# The default value is: NO.
+
+INLINE_SOURCES = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any
+# special comment blocks from generated source code fragments. Normal C, C++ and
+# Fortran comments will always remain visible.
+# The default value is: YES.
+
+STRIP_CODE_COMMENTS = YES
+
+# If the REFERENCED_BY_RELATION tag is set to YES then for each documented
+# function all documented functions referencing it will be listed.
+# The default value is: NO.
+
+REFERENCED_BY_RELATION = NO
+
+# If the REFERENCES_RELATION tag is set to YES then for each documented function
+# all documented entities called/used by that function will be listed.
+# The default value is: NO.
+
+REFERENCES_RELATION = NO
+
+# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set
+# to YES then the hyperlinks from functions in REFERENCES_RELATION and
+# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will
+# link to the documentation.
+# The default value is: YES.
+
+REFERENCES_LINK_SOURCE = YES
+
+# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the
+# source code will show a tooltip with additional information such as prototype,
+# brief description and links to the definition and documentation. Since this
+# will make the HTML file larger and loading of large files a bit slower, you
+# can opt to disable this feature.
+# The default value is: YES.
+# This tag requires that the tag SOURCE_BROWSER is set to YES.
+
+SOURCE_TOOLTIPS = YES
+
+# If the USE_HTAGS tag is set to YES then the references to source code will
+# point to the HTML generated by the htags(1) tool instead of doxygen built-in
+# source browser. The htags tool is part of GNU's global source tagging system
+# (see http://www.gnu.org/software/global/global.html). You will need version
+# 4.8.6 or higher.
+#
+# To use it do the following:
+# - Install the latest version of global
+# - Enable SOURCE_BROWSER and USE_HTAGS in the config file
+# - Make sure the INPUT points to the root of the source tree
+# - Run doxygen as normal
+#
+# Doxygen will invoke htags (and that will in turn invoke gtags), so these
+# tools must be available from the command line (i.e. in the search path).
+#
+# The result: instead of the source browser generated by doxygen, the links to
+# source code will now point to the output of htags.
+# The default value is: NO.
+# This tag requires that the tag SOURCE_BROWSER is set to YES.
+
+USE_HTAGS = NO
+
+# If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a
+# verbatim copy of the header file for each class for which an include is
+# specified. Set to NO to disable this.
+# See also: Section \class.
+# The default value is: YES.
+
+VERBATIM_HEADERS = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all
+# compounds will be generated. Enable this if the project contains a lot of
+# classes, structs, unions or interfaces.
+# The default value is: YES.
+
+ALPHABETICAL_INDEX = YES
+
+# The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in
+# which the alphabetical index list will be split.
+# Minimum value: 1, maximum value: 20, default value: 5.
+# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
+
+COLS_IN_ALPHA_INDEX = 5
+
+# In case all classes in a project start with a common prefix, all classes will
+# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag
+# can be used to specify a prefix (or a list of prefixes) that should be ignored
+# while generating the index headers.
+# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
+
+IGNORE_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES, doxygen will generate HTML output
+# The default value is: YES.
+
+GENERATE_HTML = NO
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: html.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_OUTPUT = html
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each
+# generated HTML page (for example: .htm, .php, .asp).
+# The default value is: .html.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_FILE_EXTENSION = .html
+
+# The HTML_HEADER tag can be used to specify a user-defined HTML header file for
+# each generated HTML page. If the tag is left blank doxygen will generate a
+# standard header.
+#
+# To get valid HTML the header file that includes any scripts and style sheets
+# that doxygen needs, which is dependent on the configuration options used (e.g.
+# the setting GENERATE_TREEVIEW). It is highly recommended to start with a
+# default header using
+# doxygen -w html new_header.html new_footer.html new_stylesheet.css
+# YourConfigFile
+# and then modify the file new_header.html. See also section "Doxygen usage"
+# for information on how to generate the default header that doxygen normally
+# uses.
+# Note: The header is subject to change so you typically have to regenerate the
+# default header when upgrading to a newer version of doxygen. For a description
+# of the possible markers and block names see the documentation.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_HEADER =
+
+# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each
+# generated HTML page. If the tag is left blank doxygen will generate a standard
+# footer. See HTML_HEADER for more information on how to generate a default
+# footer and what special commands can be used inside the footer. See also
+# section "Doxygen usage" for information on how to generate the default footer
+# that doxygen normally uses.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_FOOTER =
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style
+# sheet that is used by each HTML page. It can be used to fine-tune the look of
+# the HTML output. If left blank doxygen will generate a default style sheet.
+# See also section "Doxygen usage" for information on how to generate the style
+# sheet that doxygen normally uses.
+# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as
+# it is more robust and this tag (HTML_STYLESHEET) will in the future become
+# obsolete.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_STYLESHEET =
+
+# The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined
+# cascading style sheets that are included after the standard style sheets
+# created by doxygen. Using this option one can overrule certain style aspects.
+# This is preferred over using HTML_STYLESHEET since it does not replace the
+# standard style sheet and is therefore more robust against future updates.
+# Doxygen will copy the style sheet files to the output directory.
+# Note: The order of the extra stylesheet files is of importance (e.g. the last
+# stylesheet in the list overrules the setting of the previous ones in the
+# list). For an example see the documentation.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_EXTRA_STYLESHEET =
+
+# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the HTML output directory. Note
+# that these files will be copied to the base HTML output directory. Use the
+# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these
+# files. In the HTML_STYLESHEET file, use the file name only. Also note that the
+# files will be copied as-is; there are no commands or markers available.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_EXTRA_FILES =
+
+# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen
+# will adjust the colors in the stylesheet and background images according to
+# this color. Hue is specified as an angle on a colorwheel, see
+# http://en.wikipedia.org/wiki/Hue for more information. For instance the value
+# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300
+# purple, and 360 is red again.
+# Minimum value: 0, maximum value: 359, default value: 220.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_HUE = 220
+
+# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors
+# in the HTML output. For a value of 0 the output will use grayscales only. A
+# value of 255 will produce the most vivid colors.
+# Minimum value: 0, maximum value: 255, default value: 100.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_SAT = 100
+
+# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the
+# luminance component of the colors in the HTML output. Values below 100
+# gradually make the output lighter, whereas values above 100 make the output
+# darker. The value divided by 100 is the actual gamma applied, so 80 represents
+# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not
+# change the gamma.
+# Minimum value: 40, maximum value: 240, default value: 80.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_GAMMA = 80
+
+# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML
+# page will contain the date and time when the page was generated. Setting this
+# to NO can help when comparing the output of multiple runs.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_TIMESTAMP = YES
+
+# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
+# documentation will contain sections that can be hidden and shown after the
+# page has loaded.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_DYNAMIC_SECTIONS = NO
+
+# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries
+# shown in the various tree structured indices initially; the user can expand
+# and collapse entries dynamically later on. Doxygen will expand the tree to
+# such a level that at most the specified number of entries are visible (unless
+# a fully collapsed tree already exceeds this amount). So setting the number of
+# entries 1 will produce a full collapsed tree by default. 0 is a special value
+# representing an infinite number of entries and will result in a full expanded
+# tree by default.
+# Minimum value: 0, maximum value: 9999, default value: 100.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_INDEX_NUM_ENTRIES = 100
+
+# If the GENERATE_DOCSET tag is set to YES, additional index files will be
+# generated that can be used as input for Apple's Xcode 3 integrated development
+# environment (see: http://developer.apple.com/tools/xcode/), introduced with
+# OSX 10.5 (Leopard). To create a documentation set, doxygen will generate a
+# Makefile in the HTML output directory. Running make will produce the docset in
+# that directory and running make install will install the docset in
+# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at
+# startup. See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html
+# for more information.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_DOCSET = NO
+
+# This tag determines the name of the docset feed. A documentation feed provides
+# an umbrella under which multiple documentation sets from a single provider
+# (such as a company or product suite) can be grouped.
+# The default value is: Doxygen generated docs.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_FEEDNAME = "Doxygen generated docs"
+
+# This tag specifies a string that should uniquely identify the documentation
+# set bundle. This should be a reverse domain-name style string, e.g.
+# com.mycompany.MyDocSet. Doxygen will append .docset to the name.
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_BUNDLE_ID = org.doxygen.Project
+
+# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify
+# the documentation publisher. This should be a reverse domain-name style
+# string, e.g. com.mycompany.MyDocSet.documentation.
+# The default value is: org.doxygen.Publisher.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_PUBLISHER_ID = org.doxygen.Publisher
+
+# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher.
+# The default value is: Publisher.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_PUBLISHER_NAME = Publisher
+
+# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three
+# additional HTML index files: index.hhp, index.hhc, and index.hhk. The
+# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop
+# (see: http://www.microsoft.com/en-us/download/details.aspx?id=21138) on
+# Windows.
+#
+# The HTML Help Workshop contains a compiler that can convert all HTML output
+# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML
+# files are now used as the Windows 98 help format, and will replace the old
+# Windows help format (.hlp) on all Windows platforms in the future. Compressed
+# HTML files also contain an index, a table of contents, and you can search for
+# words in the documentation. The HTML workshop also contains a viewer for
+# compressed HTML files.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_HTMLHELP = NO
+
+# The CHM_FILE tag can be used to specify the file name of the resulting .chm
+# file. You can add a path in front of the file if the result should not be
+# written to the html output directory.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+CHM_FILE =
+
+# The HHC_LOCATION tag can be used to specify the location (absolute path
+# including file name) of the HTML help compiler (hhc.exe). If non-empty,
+# doxygen will try to run the HTML help compiler on the generated index.hhp.
+# The file has to be specified with full path.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+HHC_LOCATION =
+
+# The GENERATE_CHI flag controls if a separate .chi index file is generated
+# (YES) or that it should be included in the master .chm file (NO).
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+GENERATE_CHI = NO
+
+# The CHM_INDEX_ENCODING is used to encode HtmlHelp index (hhk), content (hhc)
+# and project file content.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+CHM_INDEX_ENCODING =
+
+# The BINARY_TOC flag controls whether a binary table of contents is generated
+# (YES) or a normal table of contents (NO) in the .chm file. Furthermore it
+# enables the Previous and Next buttons.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+BINARY_TOC = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members to
+# the table of contents of the HTML help documentation and to the tree view.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+TOC_EXPAND = NO
+
+# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and
+# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that
+# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help
+# (.qch) of the generated HTML documentation.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_QHP = NO
+
+# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify
+# the file name of the resulting .qch file. The path specified is relative to
+# the HTML output folder.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QCH_FILE =
+
+# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help
+# Project output. For more information please see Qt Help Project / Namespace
+# (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#namespace).
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_NAMESPACE = org.doxygen.Project
+
+# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt
+# Help Project output. For more information please see Qt Help Project / Virtual
+# Folders (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#virtual-
+# folders).
+# The default value is: doc.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_VIRTUAL_FOLDER = doc
+
+# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom
+# filter to add. For more information please see Qt Help Project / Custom
+# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-
+# filters).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_CUST_FILTER_NAME =
+
+# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the
+# custom filter to add. For more information please see Qt Help Project / Custom
+# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-
+# filters).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_CUST_FILTER_ATTRS =
+
+# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this
+# project's filter section matches. Qt Help Project / Filter Attributes (see:
+# http://qt-project.org/doc/qt-4.8/qthelpproject.html#filter-attributes).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_SECT_FILTER_ATTRS =
+
+# The QHG_LOCATION tag can be used to specify the location of Qt's
+# qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the
+# generated .qhp file.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHG_LOCATION =
+
+# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be
+# generated, together with the HTML files, they form an Eclipse help plugin. To
+# install this plugin and make it available under the help contents menu in
+# Eclipse, the contents of the directory containing the HTML and XML files needs
+# to be copied into the plugins directory of eclipse. The name of the directory
+# within the plugins directory should be the same as the ECLIPSE_DOC_ID value.
+# After copying Eclipse needs to be restarted before the help appears.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_ECLIPSEHELP = NO
+
+# A unique identifier for the Eclipse help plugin. When installing the plugin
+# the directory name containing the HTML and XML files should also have this
+# name. Each documentation set should have its own identifier.
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES.
+
+ECLIPSE_DOC_ID = org.doxygen.Project
+
+# If you want full control over the layout of the generated HTML pages it might
+# be necessary to disable the index and replace it with your own. The
+# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top
+# of each HTML page. A value of NO enables the index and the value YES disables
+# it. Since the tabs in the index contain the same information as the navigation
+# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+DISABLE_INDEX = NO
+
+# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
+# structure should be generated to display hierarchical information. If the tag
+# value is set to YES, a side panel will be generated containing a tree-like
+# index structure (just like the one that is generated for HTML Help). For this
+# to work a browser that supports JavaScript, DHTML, CSS and frames is required
+# (i.e. any modern browser). Windows users are probably better off using the
+# HTML help feature. Via custom stylesheets (see HTML_EXTRA_STYLESHEET) one can
+# further fine-tune the look of the index. As an example, the default style
+# sheet generated by doxygen has an example that shows how to put an image at
+# the root of the tree instead of the PROJECT_NAME. Since the tree basically has
+# the same information as the tab index, you could consider setting
+# DISABLE_INDEX to YES when enabling this option.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_TREEVIEW = NO
+
+# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that
+# doxygen will group on one line in the generated HTML documentation.
+#
+# Note that a value of 0 will completely suppress the enum values from appearing
+# in the overview section.
+# Minimum value: 0, maximum value: 20, default value: 4.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+ENUM_VALUES_PER_LINE = 4
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used
+# to set the initial width (in pixels) of the frame in which the tree is shown.
+# Minimum value: 0, maximum value: 1500, default value: 250.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+TREEVIEW_WIDTH = 250
+
+# If the EXT_LINKS_IN_WINDOW option is set to YES, doxygen will open links to
+# external symbols imported via tag files in a separate window.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+EXT_LINKS_IN_WINDOW = NO
+
+# Use this tag to change the font size of LaTeX formulas included as images in
+# the HTML documentation. When you change the font size after a successful
+# doxygen run you need to manually remove any form_*.png images from the HTML
+# output directory to force them to be regenerated.
+# Minimum value: 8, maximum value: 50, default value: 10.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+FORMULA_FONTSIZE = 10
+
+# Use the FORMULA_TRANPARENT tag to determine whether or not the images
+# generated for formulas are transparent PNGs. Transparent PNGs are not
+# supported properly for IE 6.0, but are supported on all modern browsers.
+#
+# Note that when changing this option you need to delete any form_*.png files in
+# the HTML output directory before the changes have effect.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+FORMULA_TRANSPARENT = YES
+
+# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see
+# http://www.mathjax.org) which uses client side Javascript for the rendering
+# instead of using pre-rendered bitmaps. Use this if you do not have LaTeX
+# installed or if you want to formulas look prettier in the HTML output. When
+# enabled you may also need to install MathJax separately and configure the path
+# to it using the MATHJAX_RELPATH option.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+USE_MATHJAX = NO
+
+# When MathJax is enabled you can set the default output format to be used for
+# the MathJax output. See the MathJax site (see:
+# http://docs.mathjax.org/en/latest/output.html) for more details.
+# Possible values are: HTML-CSS (which is slower, but has the best
+# compatibility), NativeMML (i.e. MathML) and SVG.
+# The default value is: HTML-CSS.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_FORMAT = HTML-CSS
+
+# When MathJax is enabled you need to specify the location relative to the HTML
+# output directory using the MATHJAX_RELPATH option. The destination directory
+# should contain the MathJax.js script. For instance, if the mathjax directory
+# is located at the same level as the HTML output directory, then
+# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax
+# Content Delivery Network so you can quickly see the result without installing
+# MathJax. However, it is strongly recommended to install a local copy of
+# MathJax from http://www.mathjax.org before deployment.
+# The default value is: http://cdn.mathjax.org/mathjax/latest.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest
+
+# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax
+# extension names that should be enabled during MathJax rendering. For example
+# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_EXTENSIONS =
+
+# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces
+# of code that will be used on startup of the MathJax code. See the MathJax site
+# (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an
+# example see the documentation.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_CODEFILE =
+
+# When the SEARCHENGINE tag is enabled doxygen will generate a search box for
+# the HTML output. The underlying search engine uses javascript and DHTML and
+# should work on any modern browser. Note that when using HTML help
+# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET)
+# there is already a search function so this one should typically be disabled.
+# For large projects the javascript based search engine can be slow, then
+# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to
+# search using the keyboard; to jump to the search box use <access key> + S
+# (what the <access key> is depends on the OS and browser, but it is typically
+# <CTRL>, <ALT>/<option>, or both). Inside the search box use the <cursor down
+# key> to jump into the search results window, the results can be navigated
+# using the <cursor keys>. Press <Enter> to select an item or <escape> to cancel
+# the search. The filter options can be selected when the cursor is inside the
+# search box by pressing <Shift>+<cursor down>. Also here use the <cursor keys>
+# to select a filter and <Enter> or <escape> to activate or cancel the filter
+# option.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+SEARCHENGINE = YES
+
+# When the SERVER_BASED_SEARCH tag is enabled the search engine will be
+# implemented using a web server instead of a web client using Javascript. There
+# are two flavors of web server based searching depending on the EXTERNAL_SEARCH
+# setting. When disabled, doxygen will generate a PHP script for searching and
+# an index file used by the script. When EXTERNAL_SEARCH is enabled the indexing
+# and searching needs to be provided by external tools. See the section
+# "External Indexing and Searching" for details.
+# The default value is: NO.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SERVER_BASED_SEARCH = NO
+
+# When EXTERNAL_SEARCH tag is enabled doxygen will no longer generate the PHP
+# script for searching. Instead the search results are written to an XML file
+# which needs to be processed by an external indexer. Doxygen will invoke an
+# external search engine pointed to by the SEARCHENGINE_URL option to obtain the
+# search results.
+#
+# Doxygen ships with an example indexer (doxyindexer) and search engine
+# (doxysearch.cgi) which are based on the open source search engine library
+# Xapian (see: http://xapian.org/).
+#
+# See the section "External Indexing and Searching" for details.
+# The default value is: NO.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTERNAL_SEARCH = NO
+
+# The SEARCHENGINE_URL should point to a search engine hosted by a web server
+# which will return the search results when EXTERNAL_SEARCH is enabled.
+#
+# Doxygen ships with an example indexer (doxyindexer) and search engine
+# (doxysearch.cgi) which are based on the open source search engine library
+# Xapian (see: http://xapian.org/). See the section "External Indexing and
+# Searching" for details.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SEARCHENGINE_URL =
+
+# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the unindexed
+# search data is written to a file for indexing by an external tool. With the
+# SEARCHDATA_FILE tag the name of this file can be specified.
+# The default file is: searchdata.xml.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SEARCHDATA_FILE = searchdata.xml
+
+# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the
+# EXTERNAL_SEARCH_ID tag can be used as an identifier for the project. This is
+# useful in combination with EXTRA_SEARCH_MAPPINGS to search through multiple
+# projects and redirect the results back to the right project.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTERNAL_SEARCH_ID =
+
+# The EXTRA_SEARCH_MAPPINGS tag can be used to enable searching through doxygen
+# projects other than the one defined by this configuration file, but that are
+# all added to the same external search index. Each project needs to have a
+# unique id set via EXTERNAL_SEARCH_ID. The search mapping then maps the id of
+# to a relative location where the documentation can be found. The format is:
+# EXTRA_SEARCH_MAPPINGS = tagname1=loc1 tagname2=loc2 ...
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTRA_SEARCH_MAPPINGS =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES, doxygen will generate LaTeX output.
+# The default value is: YES.
+
+GENERATE_LATEX = NO
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: latex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_OUTPUT = latex
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
+# invoked.
+#
+# Note that when enabling USE_PDFLATEX this option is only used for generating
+# bitmaps for formulas in the HTML output, but not in the Makefile that is
+# written to the output directory.
+# The default file is: latex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_CMD_NAME = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to generate
+# index for LaTeX.
+# The default file is: makeindex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+MAKEINDEX_CMD_NAME = makeindex
+
+# If the COMPACT_LATEX tag is set to YES, doxygen generates more compact LaTeX
+# documents. This may be useful for small projects and may help to save some
+# trees in general.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+COMPACT_LATEX = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used by the
+# printer.
+# Possible values are: a4 (210 x 297 mm), letter (8.5 x 11 inches), legal (8.5 x
+# 14 inches) and executive (7.25 x 10.5 inches).
+# The default value is: a4.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+PAPER_TYPE = a4
+
+# The EXTRA_PACKAGES tag can be used to specify one or more LaTeX package names
+# that should be included in the LaTeX output. To get the times font for
+# instance you can specify
+# EXTRA_PACKAGES=times
+# If left blank no extra packages will be included.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+EXTRA_PACKAGES =
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for the
+# generated LaTeX document. The header should contain everything until the first
+# chapter. If it is left blank doxygen will generate a standard header. See
+# section "Doxygen usage" for information on how to let doxygen write the
+# default header to a separate file.
+#
+# Note: Only use a user-defined header if you know what you are doing! The
+# following commands have a special meaning inside the header: $title,
+# $datetime, $date, $doxygenversion, $projectname, $projectnumber,
+# $projectbrief, $projectlogo. Doxygen will replace $title with the empty
+# string, for the replacement values of the other commands the user is referred
+# to HTML_HEADER.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_HEADER =
+
+# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for the
+# generated LaTeX document. The footer should contain everything after the last
+# chapter. If it is left blank doxygen will generate a standard footer. See
+# LATEX_HEADER for more information on how to generate a default footer and what
+# special commands can be used inside the footer.
+#
+# Note: Only use a user-defined footer if you know what you are doing!
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_FOOTER =
+
+# The LATEX_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the LATEX_OUTPUT output
+# directory. Note that the files will be copied as-is; there are no commands or
+# markers available.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_EXTRA_FILES =
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated is
+# prepared for conversion to PDF (using ps2pdf or pdflatex). The PDF file will
+# contain links (just like the HTML output) instead of page references. This
+# makes the output suitable for online browsing using a PDF viewer.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+PDF_HYPERLINKS = YES
+
+# If the USE_PDFLATEX tag is set to YES, doxygen will use pdflatex to generate
+# the PDF file directly from the LaTeX files. Set this option to YES, to get a
+# higher quality PDF documentation.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+USE_PDFLATEX = YES
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \batchmode
+# command to the generated LaTeX files. This will instruct LaTeX to keep running
+# if errors occur, instead of asking the user for help. This option is also used
+# when generating formulas in HTML.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_BATCHMODE = NO
+
+# If the LATEX_HIDE_INDICES tag is set to YES then doxygen will not include the
+# index chapters (such as File Index, Compound Index, etc.) in the output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_HIDE_INDICES = NO
+
+# If the LATEX_SOURCE_CODE tag is set to YES then doxygen will include source
+# code with syntax highlighting in the LaTeX output.
+#
+# Note that which sources are shown also depends on other settings such as
+# SOURCE_BROWSER.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_SOURCE_CODE = NO
+
+# The LATEX_BIB_STYLE tag can be used to specify the style to use for the
+# bibliography, e.g. plainnat, or ieeetr. See
+# http://en.wikipedia.org/wiki/BibTeX and \cite for more info.
+# The default value is: plain.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_BIB_STYLE = plain
+
+#---------------------------------------------------------------------------
+# Configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES, doxygen will generate RTF output. The
+# RTF output is optimized for Word 97 and may not look too pretty with other RTF
+# readers/editors.
+# The default value is: NO.
+
+GENERATE_RTF = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: rtf.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_OUTPUT = rtf
+
+# If the COMPACT_RTF tag is set to YES, doxygen generates more compact RTF
+# documents. This may be useful for small projects and may help to save some
+# trees in general.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+COMPACT_RTF = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated will
+# contain hyperlink fields. The RTF file will contain links (just like the HTML
+# output) instead of page references. This makes the output suitable for online
+# browsing using Word or some other Word compatible readers that support those
+# fields.
+#
+# Note: WordPad (write) and others do not support links.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_HYPERLINKS = NO
+
+# Load stylesheet definitions from file. Syntax is similar to doxygen's config
+# file, i.e. a series of assignments. You only have to provide replacements,
+# missing definitions are set to their default value.
+#
+# See also section "Doxygen usage" for information on how to generate the
+# default style sheet that doxygen normally uses.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_STYLESHEET_FILE =
+
+# Set optional variables used in the generation of an RTF document. Syntax is
+# similar to doxygen's config file. A template extensions file can be generated
+# using doxygen -e rtf extensionFile.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_EXTENSIONS_FILE =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES, doxygen will generate man pages for
+# classes and files.
+# The default value is: NO.
+
+GENERATE_MAN = NO
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it. A directory man3 will be created inside the directory specified by
+# MAN_OUTPUT.
+# The default directory is: man.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_OUTPUT = man
+
+# The MAN_EXTENSION tag determines the extension that is added to the generated
+# man pages. In case the manual section does not start with a number, the number
+# 3 is prepended. The dot (.) at the beginning of the MAN_EXTENSION tag is
+# optional.
+# The default value is: .3.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_EXTENSION = .3
+
+# The MAN_SUBDIR tag determines the name of the directory created within
+# MAN_OUTPUT in which the man pages are placed. If defaults to man followed by
+# MAN_EXTENSION with the initial . removed.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_SUBDIR =
+
+# If the MAN_LINKS tag is set to YES and doxygen generates man output, then it
+# will generate one additional man file for each entity documented in the real
+# man page(s). These additional files only source the real man page, but without
+# them the man command would be unable to find the correct page.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_LINKS = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES, doxygen will generate an XML file that
+# captures the structure of the code including all documentation.
+# The default value is: NO.
+
+GENERATE_XML = YES
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: xml.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_OUTPUT = xml
+
+# If the XML_PROGRAMLISTING tag is set to YES, doxygen will dump the program
+# listings (including syntax highlighting and cross-referencing information) to
+# the XML output. Note that enabling this will significantly increase the size
+# of the XML output.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_PROGRAMLISTING = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the DOCBOOK output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_DOCBOOK tag is set to YES, doxygen will generate Docbook files
+# that can be used to generate PDF.
+# The default value is: NO.
+
+GENERATE_DOCBOOK = NO
+
+# The DOCBOOK_OUTPUT tag is used to specify where the Docbook pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be put in
+# front of it.
+# The default directory is: docbook.
+# This tag requires that the tag GENERATE_DOCBOOK is set to YES.
+
+DOCBOOK_OUTPUT = docbook
+
+# If the DOCBOOK_PROGRAMLISTING tag is set to YES, doxygen will include the
+# program listings (including syntax highlighting and cross-referencing
+# information) to the DOCBOOK output. Note that enabling this will significantly
+# increase the size of the DOCBOOK output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_DOCBOOK is set to YES.
+
+DOCBOOK_PROGRAMLISTING = NO
+
+#---------------------------------------------------------------------------
+# Configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES, doxygen will generate an
+# AutoGen Definitions (see http://autogen.sf.net) file that captures the
+# structure of the code including all documentation. Note that this feature is
+# still experimental and incomplete at the moment.
+# The default value is: NO.
+
+GENERATE_AUTOGEN_DEF = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES, doxygen will generate a Perl module
+# file that captures the structure of the code including all documentation.
+#
+# Note that this feature is still experimental and incomplete at the moment.
+# The default value is: NO.
+
+GENERATE_PERLMOD = NO
+
+# If the PERLMOD_LATEX tag is set to YES, doxygen will generate the necessary
+# Makefile rules, Perl scripts and LaTeX code to be able to generate PDF and DVI
+# output from the Perl module output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_LATEX = NO
+
+# If the PERLMOD_PRETTY tag is set to YES, the Perl module output will be nicely
+# formatted so it can be parsed by a human reader. This is useful if you want to
+# understand what is going on. On the other hand, if this tag is set to NO, the
+# size of the Perl module output will be much smaller and Perl will parse it
+# just the same.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_PRETTY = YES
+
+# The names of the make variables in the generated doxyrules.make file are
+# prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. This is useful
+# so different doxyrules.make files included by the same Makefile don't
+# overwrite each other's variables.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_MAKEVAR_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES, doxygen will evaluate all
+# C-preprocessor directives found in the sources and include files.
+# The default value is: YES.
+
+ENABLE_PREPROCESSING = YES
+
+# If the MACRO_EXPANSION tag is set to YES, doxygen will expand all macro names
+# in the source code. If set to NO, only conditional compilation will be
+# performed. Macro expansion can be done in a controlled way by setting
+# EXPAND_ONLY_PREDEF to YES.
+# The default value is: NO.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+MACRO_EXPANSION = NO
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES then
+# the macro expansion is limited to the macros specified with the PREDEFINED and
+# EXPAND_AS_DEFINED tags.
+# The default value is: NO.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+EXPAND_ONLY_PREDEF = NO
+
+# If the SEARCH_INCLUDES tag is set to YES, the include files in the
+# INCLUDE_PATH will be searched if a #include is found.
+# The default value is: YES.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+SEARCH_INCLUDES = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that
+# contain include files that are not input files but should be processed by the
+# preprocessor.
+# This tag requires that the tag SEARCH_INCLUDES is set to YES.
+
+INCLUDE_PATH =
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
+# patterns (like *.h and *.hpp) to filter out the header-files in the
+# directories. If left blank, the patterns specified with FILE_PATTERNS will be
+# used.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+INCLUDE_FILE_PATTERNS =
+
+# The PREDEFINED tag can be used to specify one or more macro names that are
+# defined before the preprocessor is started (similar to the -D option of e.g.
+# gcc). The argument of the tag is a list of macros of the form: name or
+# name=definition (no spaces). If the definition and the "=" are omitted, "=1"
+# is assumed. To prevent a macro definition from being undefined via #undef or
+# recursively expanded use the := operator instead of the = operator.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+PREDEFINED =
+
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this
+# tag can be used to specify a list of macro names that should be expanded. The
+# macro definition that is found in the sources will be used. Use the PREDEFINED
+# tag if you want to use a different macro definition that overrules the
+# definition found in the source code.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+EXPAND_AS_DEFINED =
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES then doxygen's preprocessor will
+# remove all references to function-like macros that are alone on a line, have
+# an all uppercase name, and do not end with a semicolon. Such function macros
+# are typically used for boiler-plate code, and will confuse the parser if not
+# removed.
+# The default value is: YES.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+SKIP_FUNCTION_MACROS = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to external references
+#---------------------------------------------------------------------------
+
+# The TAGFILES tag can be used to specify one or more tag files. For each tag
+# file the location of the external documentation should be added. The format of
+# a tag file without this location is as follows:
+# TAGFILES = file1 file2 ...
+# Adding location for the tag files is done as follows:
+# TAGFILES = file1=loc1 "file2 = loc2" ...
+# where loc1 and loc2 can be relative or absolute paths or URLs. See the
+# section "Linking to external documentation" for more information about the use
+# of tag files.
+# Note: Each tag file must have a unique name (where the name does NOT include
+# the path). If a tag file is not located in the directory in which doxygen is
+# run, you must also specify the path to the tagfile here.
+
+TAGFILES =
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create a
+# tag file that is based on the input files it reads. See section "Linking to
+# external documentation" for more information about the usage of tag files.
+
+GENERATE_TAGFILE =
+
+# If the ALLEXTERNALS tag is set to YES, all external class will be listed in
+# the class index. If set to NO, only the inherited external classes will be
+# listed.
+# The default value is: NO.
+
+ALLEXTERNALS = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES, all external groups will be listed
+# in the modules index. If set to NO, only the current project's groups will be
+# listed.
+# The default value is: YES.
+
+EXTERNAL_GROUPS = YES
+
+# If the EXTERNAL_PAGES tag is set to YES, all external pages will be listed in
+# the related pages index. If set to NO, only the current project's pages will
+# be listed.
+# The default value is: YES.
+
+EXTERNAL_PAGES = YES
+
+# The PERL_PATH should be the absolute path and name of the perl script
+# interpreter (i.e. the result of 'which perl').
+# The default file (with absolute path) is: /usr/bin/perl.
+
+PERL_PATH = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES, doxygen will generate a class diagram
+# (in HTML and LaTeX) for classes with base or super classes. Setting the tag to
+# NO turns the diagrams off. Note that this option also works with HAVE_DOT
+# disabled, but it is recommended to install and use dot, since it yields more
+# powerful graphs.
+# The default value is: YES.
+
+CLASS_DIAGRAMS = YES
+
+# You can define message sequence charts within doxygen comments using the \msc
+# command. Doxygen will then run the mscgen tool (see:
+# http://www.mcternan.me.uk/mscgen/)) to produce the chart and insert it in the
+# documentation. The MSCGEN_PATH tag allows you to specify the directory where
+# the mscgen tool resides. If left empty the tool is assumed to be found in the
+# default search path.
+
+MSCGEN_PATH =
+
+# You can include diagrams made with dia in doxygen documentation. Doxygen will
+# then run dia to produce the diagram and insert it in the documentation. The
+# DIA_PATH tag allows you to specify the directory where the dia binary resides.
+# If left empty dia is assumed to be found in the default search path.
+
+DIA_PATH =
+
+# If set to YES the inheritance and collaboration graphs will hide inheritance
+# and usage relations if the target is undocumented or is not a class.
+# The default value is: YES.
+
+HIDE_UNDOC_RELATIONS = YES
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
+# available from the path. This tool is part of Graphviz (see:
+# http://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent
+# Bell Labs. The other options in this section have no effect if this option is
+# set to NO
+# The default value is: NO.
+
+HAVE_DOT = NO
+
+# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is allowed
+# to run in parallel. When set to 0 doxygen will base this on the number of
+# processors available in the system. You can set it explicitly to a value
+# larger than 0 to get control over the balance between CPU load and processing
+# speed.
+# Minimum value: 0, maximum value: 32, default value: 0.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_NUM_THREADS = 0
+
+# When you want a differently looking font in the dot files that doxygen
+# generates you can specify the font name using DOT_FONTNAME. You need to make
+# sure dot is able to find the font, which can be done by putting it in a
+# standard location or by setting the DOTFONTPATH environment variable or by
+# setting DOT_FONTPATH to the directory containing the font.
+# The default value is: Helvetica.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTNAME = Helvetica
+
+# The DOT_FONTSIZE tag can be used to set the size (in points) of the font of
+# dot graphs.
+# Minimum value: 4, maximum value: 24, default value: 10.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTSIZE = 10
+
+# By default doxygen will tell dot to use the default font as specified with
+# DOT_FONTNAME. If you specify a different font using DOT_FONTNAME you can set
+# the path where dot can find it using this tag.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTPATH =
+
+# If the CLASS_GRAPH tag is set to YES then doxygen will generate a graph for
+# each documented class showing the direct and indirect inheritance relations.
+# Setting this tag to YES will force the CLASS_DIAGRAMS tag to NO.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CLASS_GRAPH = YES
+
+# If the COLLABORATION_GRAPH tag is set to YES then doxygen will generate a
+# graph for each documented class showing the direct and indirect implementation
+# dependencies (inheritance, containment, and class references variables) of the
+# class with other documented classes.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+COLLABORATION_GRAPH = YES
+
+# If the GROUP_GRAPHS tag is set to YES then doxygen will generate a graph for
+# groups, showing the direct groups dependencies.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GROUP_GRAPHS = YES
+
+# If the UML_LOOK tag is set to YES, doxygen will generate inheritance and
+# collaboration diagrams in a style similar to the OMG's Unified Modeling
+# Language.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+UML_LOOK = NO
+
+# If the UML_LOOK tag is enabled, the fields and methods are shown inside the
+# class node. If there are many fields or methods and many nodes the graph may
+# become too big to be useful. The UML_LIMIT_NUM_FIELDS threshold limits the
+# number of items for each type to make the size more manageable. Set this to 0
+# for no limit. Note that the threshold may be exceeded by 50% before the limit
+# is enforced. So when you set the threshold to 10, up to 15 fields may appear,
+# but if the number exceeds 15, the total amount of fields shown is limited to
+# 10.
+# Minimum value: 0, maximum value: 100, default value: 10.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+UML_LIMIT_NUM_FIELDS = 10
+
+# If the TEMPLATE_RELATIONS tag is set to YES then the inheritance and
+# collaboration graphs will show the relations between templates and their
+# instances.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+TEMPLATE_RELATIONS = NO
+
+# If the INCLUDE_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are set to
+# YES then doxygen will generate a graph for each documented file showing the
+# direct and indirect include dependencies of the file with other documented
+# files.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INCLUDE_GRAPH = YES
+
+# If the INCLUDED_BY_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are
+# set to YES then doxygen will generate a graph for each documented file showing
+# the direct and indirect include dependencies of the file with other documented
+# files.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INCLUDED_BY_GRAPH = YES
+
+# If the CALL_GRAPH tag is set to YES then doxygen will generate a call
+# dependency graph for every global function or class method.
+#
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable call graphs for selected
+# functions only using the \callgraph command.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CALL_GRAPH = NO
+
+# If the CALLER_GRAPH tag is set to YES then doxygen will generate a caller
+# dependency graph for every global function or class method.
+#
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable caller graphs for selected
+# functions only using the \callergraph command.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CALLER_GRAPH = NO
+
+# If the GRAPHICAL_HIERARCHY tag is set to YES then doxygen will graphical
+# hierarchy of all classes instead of a textual one.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GRAPHICAL_HIERARCHY = YES
+
+# If the DIRECTORY_GRAPH tag is set to YES then doxygen will show the
+# dependencies a directory has on other directories in a graphical way. The
+# dependency relations are determined by the #include relations between the
+# files in the directories.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DIRECTORY_GRAPH = YES
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
+# generated by dot.
+# Note: If you choose svg you need to set HTML_FILE_EXTENSION to xhtml in order
+# to make the SVG files visible in IE 9+ (other browsers do not have this
+# requirement).
+# Possible values are: png, jpg, gif and svg.
+# The default value is: png.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_IMAGE_FORMAT = png
+
+# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to
+# enable generation of interactive SVG images that allow zooming and panning.
+#
+# Note that this requires a modern browser other than Internet Explorer. Tested
+# and working are Firefox, Chrome, Safari, and Opera.
+# Note: For IE 9+ you need to set HTML_FILE_EXTENSION to xhtml in order to make
+# the SVG files visible. Older versions of IE do not have SVG support.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INTERACTIVE_SVG = NO
+
+# The DOT_PATH tag can be used to specify the path where the dot tool can be
+# found. If left blank, it is assumed the dot tool can be found in the path.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_PATH =
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that
+# contain dot files that are included in the documentation (see the \dotfile
+# command).
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOTFILE_DIRS =
+
+# The MSCFILE_DIRS tag can be used to specify one or more directories that
+# contain msc files that are included in the documentation (see the \mscfile
+# command).
+
+MSCFILE_DIRS =
+
+# The DIAFILE_DIRS tag can be used to specify one or more directories that
+# contain dia files that are included in the documentation (see the \diafile
+# command).
+
+DIAFILE_DIRS =
+
+# When using plantuml, the PLANTUML_JAR_PATH tag should be used to specify the
+# path where java can find the plantuml.jar file. If left blank, it is assumed
+# PlantUML is not used or called during a preprocessing step. Doxygen will
+# generate a warning when it encounters a \startuml command in this case and
+# will not generate output for the diagram.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+PLANTUML_JAR_PATH =
+
+# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of nodes
+# that will be shown in the graph. If the number of nodes in a graph becomes
+# larger than this value, doxygen will truncate the graph, which is visualized
+# by representing a node as a red box. Note that doxygen if the number of direct
+# children of the root node in a graph is already larger than
+# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note that
+# the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
+# Minimum value: 0, maximum value: 10000, default value: 50.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_GRAPH_MAX_NODES = 50
+
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the graphs
+# generated by dot. A depth value of 3 means that only nodes reachable from the
+# root by following a path via at most 3 edges will be shown. Nodes that lay
+# further from the root node will be omitted. Note that setting this option to 1
+# or 2 may greatly reduce the computation time needed for large code bases. Also
+# note that the size of a graph can be further restricted by
+# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
+# Minimum value: 0, maximum value: 1000, default value: 0.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+MAX_DOT_GRAPH_DEPTH = 0
+
+# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
+# background. This is disabled by default, because dot on Windows does not seem
+# to support this out of the box.
+#
+# Warning: Depending on the platform used, enabling this option may lead to
+# badly anti-aliased labels on the edges of a graph (i.e. they become hard to
+# read).
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_TRANSPARENT = NO
+
+# Set the DOT_MULTI_TARGETS tag to YES to allow dot to generate multiple output
+# files in one run (i.e. multiple -o and -T options on the command line). This
+# makes dot run faster, but since only newer versions of dot (>1.8.10) support
+# this, this feature is disabled by default.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_MULTI_TARGETS = NO
+
+# If the GENERATE_LEGEND tag is set to YES doxygen will generate a legend page
+# explaining the meaning of the various boxes and arrows in the dot generated
+# graphs.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GENERATE_LEGEND = YES
+
+# If the DOT_CLEANUP tag is set to YES, doxygen will remove the intermediate dot
+# files that are used to generate the various graphs.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_CLEANUP = YES
--- /dev/null
+This directory contains a dummy Java project for testing purposes.
+
+To regenerate the XML output located in `xml`, run `make`. If the `Makefile`
+does not exists, you can regenerate it by running `make bootstrap` in the parent
+directory.
--- /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.
+ */
+
+/**
+ * A class with an inner class.
+ */
+public class OuterClass {
+ /**
+ * An instance (non-static) inner class.
+ */
+ public class InnerClass {}
+}
--- /dev/null
+<?xml version='1.0' encoding='UTF-8' standalone='no'?>
+<doxygen xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="compound.xsd" version="1.8.8">
+ <compounddef id="_outer_class_8java" kind="file">
+ <compoundname>OuterClass.java</compoundname>
+ <innerclass refid="class_outer_class" prot="public">OuterClass</innerclass>
+ <innerclass refid="class_outer_class_1_1_inner_class" prot="public">OuterClass::InnerClass</innerclass>
+ <briefdescription>
+ </briefdescription>
+ <detaileddescription>
+ </detaileddescription>
+ <location file="%SOURCE_DIRECTORY%/OuterClass.java"/>
+ </compounddef>
+</doxygen>
--- /dev/null
+<?xml version='1.0' encoding='UTF-8' standalone='no'?>
+<doxygen xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="compound.xsd" version="1.8.8">
+ <compounddef id="class_outer_class" kind="class" prot="public">
+ <compoundname>OuterClass</compoundname>
+ <innerclass refid="class_outer_class_1_1_inner_class" prot="public">OuterClass::InnerClass</innerclass>
+ <briefdescription>
+ </briefdescription>
+ <detaileddescription>
+<para>A class with an inner class. </para> </detaileddescription>
+ <location file="%SOURCE_DIRECTORY%/OuterClass.java" line="19" column="1" bodyfile="%SOURCE_DIRECTORY%/OuterClass.java" bodystart="19" bodyend="24"/>
+ <listofallmembers>
+ </listofallmembers>
+ </compounddef>
+</doxygen>
--- /dev/null
+<?xml version='1.0' encoding='UTF-8' standalone='no'?>
+<doxygen xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="compound.xsd" version="1.8.8">
+ <compounddef id="class_outer_class_1_1_inner_class" kind="class" prot="public">
+ <compoundname>OuterClass::InnerClass</compoundname>
+ <briefdescription>
+ </briefdescription>
+ <detaileddescription>
+<para>An instance (non-static) inner class. </para> </detaileddescription>
+ <location file="%SOURCE_DIRECTORY%/OuterClass.java" line="23" column="1" bodyfile="%SOURCE_DIRECTORY%/OuterClass.java" bodystart="23" bodyend="23"/>
+ <listofallmembers>
+ </listofallmembers>
+ </compounddef>
+</doxygen>
--- /dev/null
+<!-- XSLT script to combine the generated output into a single file.
+ If you have xsltproc you could use:
+ xsltproc combine.xslt index.xml >all.xml
+-->
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
+ <xsl:output method="xml" version="1.0" indent="no" standalone="yes" />
+ <xsl:template match="/">
+ <doxygen version="{doxygenindex/@version}">
+ <!-- Load all doxgen generated xml files -->
+ <xsl:for-each select="doxygenindex/compound">
+ <xsl:copy-of select="document( concat( @refid, '.xml' ) )/doxygen/*" />
+ </xsl:for-each>
+ </doxygen>
+ </xsl:template>
+</xsl:stylesheet>
--- /dev/null
+<?xml version='1.0' encoding='utf-8' ?>
+<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
+ <xsd:element name="doxygen" type="DoxygenType"/>
+
+ <!-- Complex types -->
+
+ <xsd:complexType name="DoxygenType">
+ <xsd:sequence maxOccurs="unbounded">
+ <xsd:element name="compounddef" type="compounddefType" minOccurs="0" />
+ </xsd:sequence>
+ <xsd:attribute name="version" type="DoxVersionNumber" use="required" />
+ </xsd:complexType>
+
+ <xsd:complexType name="compounddefType">
+ <xsd:sequence>
+ <xsd:element name="compoundname" type="xsd:string"/>
+ <xsd:element name="title" type="xsd:string" minOccurs="0" />
+ <xsd:element name="basecompoundref" type="compoundRefType" minOccurs="0" maxOccurs="unbounded" />
+ <xsd:element name="derivedcompoundref" type="compoundRefType" minOccurs="0" maxOccurs="unbounded" />
+ <xsd:element name="includes" type="incType" minOccurs="0" maxOccurs="unbounded" />
+ <xsd:element name="includedby" type="incType" minOccurs="0" maxOccurs="unbounded" />
+ <xsd:element name="incdepgraph" type="graphType" minOccurs="0" />
+ <xsd:element name="invincdepgraph" type="graphType" minOccurs="0" />
+ <xsd:element name="innerdir" type="refType" minOccurs="0" maxOccurs="unbounded" />
+ <xsd:element name="innerfile" type="refType" minOccurs="0" maxOccurs="unbounded" />
+ <xsd:element name="innerclass" type="refType" minOccurs="0" maxOccurs="unbounded" />
+ <xsd:element name="innernamespace" type="refType" minOccurs="0" maxOccurs="unbounded" />
+ <xsd:element name="innerpage" type="refType" minOccurs="0" maxOccurs="unbounded" />
+ <xsd:element name="innergroup" type="refType" minOccurs="0" maxOccurs="unbounded" />
+ <xsd:element name="templateparamlist" type="templateparamlistType" minOccurs="0" />
+ <xsd:element name="sectiondef" type="sectiondefType" minOccurs="0" maxOccurs="unbounded" />
+ <xsd:element name="briefdescription" type="descriptionType" minOccurs="0" />
+ <xsd:element name="detaileddescription" type="descriptionType" minOccurs="0" />
+ <xsd:element name="inheritancegraph" type="graphType" minOccurs="0" />
+ <xsd:element name="collaborationgraph" type="graphType" minOccurs="0" />
+ <xsd:element name="programlisting" type="listingType" minOccurs="0" />
+ <xsd:element name="location" type="locationType" minOccurs="0" />
+ <xsd:element name="listofallmembers" type="listofallmembersType" minOccurs="0" />
+ </xsd:sequence>
+ <xsd:attribute name="id" type="xsd:string" />
+ <xsd:attribute name="kind" type="DoxCompoundKind" />
+ <xsd:attribute name="prot" type="DoxProtectionKind" />
+ <xsd:attribute name="final" type="DoxBool" use="optional"/>
+ <xsd:attribute name="sealed" type="DoxBool" use="optional"/>
+ <xsd:attribute name="abstract" type="DoxBool" use="optional"/>
+ </xsd:complexType>
+
+ <xsd:complexType name="listofallmembersType">
+ <xsd:sequence>
+ <xsd:element name="member" type="memberRefType" minOccurs="0" maxOccurs="unbounded" />
+ </xsd:sequence>
+ </xsd:complexType>
+
+ <xsd:complexType name="memberRefType">
+ <xsd:sequence>
+ <xsd:element name="scope" />
+ <xsd:element name="name" />
+ </xsd:sequence>
+ <xsd:attribute name="refid" type="xsd:string" />
+ <xsd:attribute name="prot" type="DoxProtectionKind" />
+ <xsd:attribute name="virt" type="DoxVirtualKind" />
+ <xsd:attribute name="ambiguityscope" type="xsd:string" />
+ </xsd:complexType>
+
+ <xsd:complexType name="compoundRefType">
+ <xsd:simpleContent>
+ <xsd:extension base="xsd:string">
+ <xsd:attribute name="refid" type="xsd:string" use="optional" />
+ <xsd:attribute name="prot" type="DoxProtectionKind" />
+ <xsd:attribute name="virt" type="DoxVirtualKind" />
+ </xsd:extension>
+ </xsd:simpleContent>
+ </xsd:complexType>
+
+ <xsd:complexType name="reimplementType">
+ <xsd:simpleContent>
+ <xsd:extension base="xsd:string">
+ <xsd:attribute name="refid" type="xsd:string" />
+ </xsd:extension>
+ </xsd:simpleContent>
+ </xsd:complexType>
+
+ <xsd:complexType name="incType">
+ <xsd:simpleContent>
+ <xsd:extension base="xsd:string">
+ <xsd:attribute name="refid" type="xsd:string" />
+ <xsd:attribute name="local" type="DoxBool" />
+ </xsd:extension>
+ </xsd:simpleContent>
+ </xsd:complexType>
+
+ <xsd:complexType name="refType">
+ <xsd:simpleContent>
+ <xsd:extension base="xsd:string">
+ <xsd:attribute name="refid" type="xsd:string" />
+ <xsd:attribute name="prot" type="DoxProtectionKind" use="optional"/>
+ </xsd:extension>
+ </xsd:simpleContent>
+ </xsd:complexType>
+
+ <xsd:complexType name="refTextType">
+ <xsd:simpleContent>
+ <xsd:extension base="xsd:string">
+ <xsd:attribute name="refid" type="xsd:string" />
+ <xsd:attribute name="kindref" type="DoxRefKind" />
+ <xsd:attribute name="external" type="xsd:string" use="optional"/>
+ <xsd:attribute name="tooltip" type="xsd:string" use="optional"/>
+ </xsd:extension>
+ </xsd:simpleContent>
+ </xsd:complexType>
+
+ <xsd:complexType name="sectiondefType">
+ <xsd:sequence>
+ <xsd:element name="header" type="xsd:string" minOccurs="0" />
+ <xsd:element name="description" type="descriptionType" minOccurs="0" />
+ <xsd:element name="memberdef" type="memberdefType" maxOccurs="unbounded" />
+ </xsd:sequence>
+ <xsd:attribute name="kind" type="DoxSectionKind" />
+ </xsd:complexType>
+
+ <xsd:complexType name="memberdefType">
+ <xsd:sequence>
+ <xsd:element name="templateparamlist" type="templateparamlistType" minOccurs="0" />
+ <xsd:element name="type" type="linkedTextType" minOccurs="0" />
+ <xsd:element name="definition" minOccurs="0" />
+ <xsd:element name="argsstring" minOccurs="0" />
+ <xsd:element name="name" />
+ <xsd:element name="read" minOccurs="0" />
+ <xsd:element name="write" minOccurs="0" />
+ <xsd:element name="bitfield" minOccurs="0" />
+ <xsd:element name="reimplements" type="reimplementType" minOccurs="0" maxOccurs="unbounded" />
+ <xsd:element name="reimplementedby" type="reimplementType" minOccurs="0" maxOccurs="unbounded" />
+ <xsd:element name="param" type="paramType" minOccurs="0" maxOccurs="unbounded" />
+ <xsd:element name="enumvalue" type="enumvalueType" minOccurs="0" maxOccurs="unbounded" />
+ <xsd:element name="initializer" type="linkedTextType" minOccurs="0" />
+ <xsd:element name="exceptions" type="linkedTextType" minOccurs="0" />
+ <xsd:element name="briefdescription" type="descriptionType" minOccurs="0" />
+ <xsd:element name="detaileddescription" type="descriptionType" minOccurs="0" />
+ <xsd:element name="inbodydescription" type="descriptionType" minOccurs="0" />
+ <xsd:element name="location" type="locationType" />
+ <xsd:element name="references" type="referenceType" minOccurs="0" maxOccurs="unbounded" />
+ <xsd:element name="referencedby" type="referenceType" minOccurs="0" maxOccurs="unbounded" />
+ </xsd:sequence>
+ <xsd:attribute name="kind" type="DoxMemberKind" />
+ <xsd:attribute name="id" type="xsd:string" />
+ <xsd:attribute name="prot" type="DoxProtectionKind" />
+ <xsd:attribute name="static" type="DoxBool" />
+ <xsd:attribute name="const" type="DoxBool" use="optional"/>
+ <xsd:attribute name="explicit" type="DoxBool" use="optional"/>
+ <xsd:attribute name="inline" type="DoxBool" use="optional"/>
+ <xsd:attribute name="virt" type="DoxVirtualKind" use="optional"/>
+ <xsd:attribute name="volatile" type="DoxBool" use="optional"/>
+ <xsd:attribute name="mutable" type="DoxBool" use="optional"/>
+ <!-- Qt property -->
+ <xsd:attribute name="readable" type="DoxBool" use="optional"/>
+ <xsd:attribute name="writable" type="DoxBool" use="optional"/>
+ <!-- C++/CLI variable -->
+ <xsd:attribute name="initonly" type="DoxBool" use="optional"/>
+ <!-- C++/CLI and C# property -->
+ <xsd:attribute name="settable" type="DoxBool" use="optional"/>
+ <xsd:attribute name="gettable" type="DoxBool" use="optional"/>
+ <!-- C++/CLI function -->
+ <xsd:attribute name="final" type="DoxBool" use="optional"/>
+ <xsd:attribute name="sealed" type="DoxBool" use="optional"/>
+ <xsd:attribute name="new" type="DoxBool" use="optional"/>
+ <!-- C++/CLI event -->
+ <xsd:attribute name="add" type="DoxBool" use="optional"/>
+ <xsd:attribute name="remove" type="DoxBool" use="optional"/>
+ <xsd:attribute name="raise" type="DoxBool" use="optional"/>
+ <!-- Objective-C 2.0 protocol method -->
+ <xsd:attribute name="optional" type="DoxBool" use="optional"/>
+ <xsd:attribute name="required" type="DoxBool" use="optional"/>
+ <!-- Objective-C 2.0 property accessor -->
+ <xsd:attribute name="accessor" type="DoxAccessor" use="optional"/>
+ <!-- UNO IDL -->
+ <xsd:attribute name="attribute" type="DoxBool" use="optional"/>
+ <xsd:attribute name="property" type="DoxBool" use="optional"/>
+ <xsd:attribute name="readonly" type="DoxBool" use="optional"/>
+ <xsd:attribute name="bound" type="DoxBool" use="optional"/>
+ <xsd:attribute name="removable" type="DoxBool" use="optional"/>
+ <xsd:attribute name="contrained" type="DoxBool" use="optional"/>
+ <xsd:attribute name="transient" type="DoxBool" use="optional"/>
+ <xsd:attribute name="maybevoid" type="DoxBool" use="optional"/>
+ <xsd:attribute name="maybedefault" type="DoxBool" use="optional"/>
+ <xsd:attribute name="maybeambiguous" type="DoxBool" use="optional"/>
+
+ </xsd:complexType>
+
+ <xsd:complexType name="descriptionType" mixed="true">
+ <xsd:sequence>
+ <xsd:element name="title" type="xsd:string" minOccurs="0"/>
+ <xsd:element name="para" type="docParaType" minOccurs="0" maxOccurs="unbounded" />
+ <xsd:element name="sect1" type="docSect1Type" minOccurs="0" maxOccurs="unbounded" />
+ <xsd:element name="internal" type="docInternalType" minOccurs="0" />
+ </xsd:sequence>
+ </xsd:complexType>
+
+ <xsd:complexType name="enumvalueType" mixed="true">
+ <xsd:sequence>
+ <xsd:element name="name" />
+ <xsd:element name="initializer" type="linkedTextType" minOccurs="0" />
+ <xsd:element name="briefdescription" type="descriptionType" minOccurs="0" />
+ <xsd:element name="detaileddescription" type="descriptionType" minOccurs="0" />
+ </xsd:sequence>
+ <xsd:attribute name="id" type="xsd:string" />
+ <xsd:attribute name="prot" type="DoxProtectionKind" />
+ </xsd:complexType>
+
+ <xsd:complexType name="templateparamlistType">
+ <xsd:sequence>
+ <xsd:element name="param" type="paramType" minOccurs="0" maxOccurs="unbounded" />
+ </xsd:sequence>
+ </xsd:complexType>
+
+ <xsd:complexType name="paramType">
+ <xsd:sequence>
+ <xsd:element name="type" type="linkedTextType" minOccurs="0" />
+ <xsd:element name="declname" minOccurs="0" />
+ <xsd:element name="defname" minOccurs="0" />
+ <xsd:element name="array" minOccurs="0" />
+ <xsd:element name="defval" type="linkedTextType" minOccurs="0" />
+ <xsd:element name="briefdescription" type="descriptionType" minOccurs="0" />
+ </xsd:sequence>
+ </xsd:complexType>
+
+ <xsd:complexType name="linkedTextType" mixed="true">
+ <xsd:sequence>
+ <xsd:element name="ref" type="refTextType" minOccurs="0" maxOccurs="unbounded" />
+ </xsd:sequence>
+ </xsd:complexType>
+
+ <xsd:complexType name="graphType">
+ <xsd:sequence>
+ <xsd:element name="node" type="nodeType" maxOccurs="unbounded" />
+ </xsd:sequence>
+ </xsd:complexType>
+
+ <xsd:complexType name="nodeType">
+ <xsd:sequence>
+ <xsd:element name="label" />
+ <xsd:element name="link" type="linkType" minOccurs="0" />
+ <xsd:element name="childnode" type="childnodeType" minOccurs="0" maxOccurs="unbounded" />
+ </xsd:sequence>
+ <xsd:attribute name="id" type="xsd:string" />
+ </xsd:complexType>
+
+ <xsd:complexType name="childnodeType">
+ <xsd:sequence>
+ <xsd:element name="edgelabel" minOccurs="0" maxOccurs="unbounded"/>
+ </xsd:sequence>
+ <xsd:attribute name="refid" type="xsd:string" />
+ <xsd:attribute name="relation" type="DoxGraphRelation" />
+ </xsd:complexType>
+
+ <xsd:complexType name="linkType">
+ <xsd:attribute name="refid" type="xsd:string" />
+ <xsd:attribute name="external" type="xsd:string" use="optional"/>
+ </xsd:complexType>
+
+ <xsd:complexType name="listingType">
+ <xsd:sequence>
+ <xsd:element name="codeline" type="codelineType" minOccurs="0" maxOccurs="unbounded" />
+ </xsd:sequence>
+ </xsd:complexType>
+
+ <xsd:complexType name="codelineType">
+ <xsd:sequence>
+ <xsd:element name="highlight" type="highlightType" minOccurs="0" maxOccurs="unbounded" />
+ </xsd:sequence>
+ <xsd:attribute name="lineno" type="xsd:integer" />
+ <xsd:attribute name="refid" type="xsd:string" />
+ <xsd:attribute name="refkind" type="DoxRefKind" />
+ <xsd:attribute name="external" type="DoxBool" />
+ </xsd:complexType>
+
+ <xsd:complexType name="highlightType" mixed="true">
+ <xsd:choice minOccurs="0" maxOccurs="unbounded">
+ <xsd:element name="sp" />
+ <xsd:element name="ref" type="refTextType" />
+ </xsd:choice>
+ <xsd:attribute name="class" type="DoxHighlightClass" />
+ </xsd:complexType>
+
+ <xsd:complexType name="referenceType" mixed="true">
+ <xsd:attribute name="refid" type="xsd:string" />
+ <xsd:attribute name="compoundref" type="xsd:string" use="optional" />
+ <xsd:attribute name="startline" type="xsd:integer" />
+ <xsd:attribute name="endline" type="xsd:integer" />
+ </xsd:complexType>
+
+ <xsd:complexType name="locationType">
+ <xsd:attribute name="file" type="xsd:string" />
+ <xsd:attribute name="line" type="xsd:integer" />
+ <xsd:attribute name="column" type="xsd:integer" use="optional"/>
+ <xsd:attribute name="bodyfile" type="xsd:string" />
+ <xsd:attribute name="bodystart" type="xsd:integer" />
+ <xsd:attribute name="bodyend" type="xsd:integer" />
+ </xsd:complexType>
+
+ <xsd:complexType name="docSect1Type" mixed="true">
+ <xsd:sequence>
+ <xsd:element name="title" type="xsd:string" />
+ <xsd:element name="para" type="docParaType" minOccurs="0" maxOccurs="unbounded" />
+ <xsd:element name="sect2" type="docSect2Type" minOccurs="0" maxOccurs="unbounded" />
+ <xsd:element name="internal" type="docInternalS1Type" minOccurs="0" />
+ </xsd:sequence>
+ <xsd:attribute name="id" type="xsd:string" />
+ </xsd:complexType>
+
+ <xsd:complexType name="docSect2Type" mixed="true">
+ <xsd:sequence>
+ <xsd:element name="title" type="xsd:string" />
+ <xsd:element name="para" type="docParaType" minOccurs="0" maxOccurs="unbounded" />
+ <xsd:element name="sect3" type="docSect3Type" minOccurs="0" maxOccurs="unbounded" />
+ <xsd:element name="internal" type="docInternalS2Type" minOccurs="0" />
+ </xsd:sequence>
+ <xsd:attribute name="id" type="xsd:string" />
+ </xsd:complexType>
+
+ <xsd:complexType name="docSect3Type" mixed="true">
+ <xsd:sequence>
+ <xsd:element name="title" type="xsd:string" />
+ <xsd:element name="para" type="docParaType" minOccurs="0" maxOccurs="unbounded" />
+ <xsd:element name="sect4" type="docSect4Type" minOccurs="0" maxOccurs="unbounded" />
+ <xsd:element name="internal" type="docInternalS3Type" minOccurs="0" />
+ </xsd:sequence>
+ <xsd:attribute name="id" type="xsd:string" />
+ </xsd:complexType>
+
+ <xsd:complexType name="docSect4Type" mixed="true">
+ <xsd:sequence>
+ <xsd:element name="title" type="xsd:string" />
+ <xsd:element name="para" type="docParaType" minOccurs="0" maxOccurs="unbounded" />
+ <xsd:element name="internal" type="docInternalS4Type" minOccurs="0" />
+ </xsd:sequence>
+ <xsd:attribute name="id" type="xsd:string" />
+ </xsd:complexType>
+
+ <xsd:complexType name="docInternalType" mixed="true">
+ <xsd:sequence>
+ <xsd:element name="para" type="docParaType" minOccurs="0" maxOccurs="unbounded" />
+ <xsd:element name="sect1" type="docSect1Type" minOccurs="0" maxOccurs="unbounded" />
+ </xsd:sequence>
+ </xsd:complexType>
+
+ <xsd:complexType name="docInternalS1Type" mixed="true">
+ <xsd:sequence>
+ <xsd:element name="para" type="docParaType" minOccurs="0" maxOccurs="unbounded" />
+ <xsd:element name="sect2" type="docSect2Type" minOccurs="0" maxOccurs="unbounded" />
+ </xsd:sequence>
+ </xsd:complexType>
+
+ <xsd:complexType name="docInternalS2Type" mixed="true">
+ <xsd:sequence>
+ <xsd:element name="para" type="docParaType" minOccurs="0" maxOccurs="unbounded" />
+ <xsd:element name="sect3" type="docSect3Type" minOccurs="0" maxOccurs="unbounded" />
+ </xsd:sequence>
+ </xsd:complexType>
+
+ <xsd:complexType name="docInternalS3Type" mixed="true">
+ <xsd:sequence>
+ <xsd:element name="para" type="docParaType" minOccurs="0" maxOccurs="unbounded" />
+ <xsd:element name="sect3" type="docSect4Type" minOccurs="0" maxOccurs="unbounded" />
+ </xsd:sequence>
+ </xsd:complexType>
+
+ <xsd:complexType name="docInternalS4Type" mixed="true">
+ <xsd:sequence>
+ <xsd:element name="para" type="docParaType" minOccurs="0" maxOccurs="unbounded" />
+ </xsd:sequence>
+ </xsd:complexType>
+
+ <xsd:group name="docTitleCmdGroup">
+ <xsd:choice>
+ <xsd:element name="ulink" type="docURLLink" />
+ <xsd:element name="bold" type="docMarkupType" />
+ <xsd:element name="emphasis" type="docMarkupType" />
+ <xsd:element name="computeroutput" type="docMarkupType" />
+ <xsd:element name="subscript" type="docMarkupType" />
+ <xsd:element name="superscript" type="docMarkupType" />
+ <xsd:element name="center" type="docMarkupType" />
+ <xsd:element name="small" type="docMarkupType" />
+ <xsd:element name="htmlonly" type="xsd:string" />
+ <xsd:element name="manonly" type="xsd:string" />
+ <xsd:element name="xmlonly" type="xsd:string" />
+ <xsd:element name="rtfonly" type="xsd:string" />
+ <xsd:element name="latexonly" type="xsd:string" />
+ <xsd:element name="dot" type="xsd:string" />
+ <xsd:element name="plantuml" type="xsd:string" />
+ <xsd:element name="anchor" type="docAnchorType" />
+ <xsd:element name="formula" type="docFormulaType" />
+ <xsd:element name="ref" type="docRefTextType" />
+ <xsd:element name="nonbreakablespace" type="docEmptyType" />
+ <xsd:element name="iexcl" type="docEmptyType" />
+ <xsd:element name="cent" type="docEmptyType" />
+ <xsd:element name="pound" type="docEmptyType" />
+ <xsd:element name="curren" type="docEmptyType" />
+ <xsd:element name="yen" type="docEmptyType" />
+ <xsd:element name="brvbar" type="docEmptyType" />
+ <xsd:element name="sect" type="docEmptyType" />
+ <xsd:element name="umlaut" type="docEmptyType" />
+ <xsd:element name="copy" type="docEmptyType" />
+ <xsd:element name="ordf" type="docEmptyType" />
+ <xsd:element name="laquo" type="docEmptyType" />
+ <xsd:element name="not" type="docEmptyType" />
+ <xsd:element name="shy" type="docEmptyType" />
+ <xsd:element name="registered" type="docEmptyType" />
+ <xsd:element name="macr" type="docEmptyType" />
+ <xsd:element name="deg" type="docEmptyType" />
+ <xsd:element name="plusmn" type="docEmptyType" />
+ <xsd:element name="sup2" type="docEmptyType" />
+ <xsd:element name="sup3" type="docEmptyType" />
+ <xsd:element name="acute" type="docEmptyType" />
+ <xsd:element name="micro" type="docEmptyType" />
+ <xsd:element name="para" type="docEmptyType" />
+ <xsd:element name="middot" type="docEmptyType" />
+ <xsd:element name="cedil" type="docEmptyType" />
+ <xsd:element name="sup1" type="docEmptyType" />
+ <xsd:element name="ordm" type="docEmptyType" />
+ <xsd:element name="raquo" type="docEmptyType" />
+ <xsd:element name="frac14" type="docEmptyType" />
+ <xsd:element name="frac12" type="docEmptyType" />
+ <xsd:element name="frac34" type="docEmptyType" />
+ <xsd:element name="iquest" type="docEmptyType" />
+ <xsd:element name="Agrave" type="docEmptyType" />
+ <xsd:element name="Aacute" type="docEmptyType" />
+ <xsd:element name="Acirc" type="docEmptyType" />
+ <xsd:element name="Atilde" type="docEmptyType" />
+ <xsd:element name="Aumlaut" type="docEmptyType" />
+ <xsd:element name="Aring" type="docEmptyType" />
+ <xsd:element name="AElig" type="docEmptyType" />
+ <xsd:element name="Ccedil" type="docEmptyType" />
+ <xsd:element name="Egrave" type="docEmptyType" />
+ <xsd:element name="Eacute" type="docEmptyType" />
+ <xsd:element name="Ecirc" type="docEmptyType" />
+ <xsd:element name="Eumlaut" type="docEmptyType" />
+ <xsd:element name="Igrave" type="docEmptyType" />
+ <xsd:element name="Iacute" type="docEmptyType" />
+ <xsd:element name="Icirc" type="docEmptyType" />
+ <xsd:element name="Iumlaut" type="docEmptyType" />
+ <xsd:element name="ETH" type="docEmptyType" />
+ <xsd:element name="Ntilde" type="docEmptyType" />
+ <xsd:element name="Ograve" type="docEmptyType" />
+ <xsd:element name="Oacute" type="docEmptyType" />
+ <xsd:element name="Ocirc" type="docEmptyType" />
+ <xsd:element name="Otilde" type="docEmptyType" />
+ <xsd:element name="Oumlaut" type="docEmptyType" />
+ <xsd:element name="times" type="docEmptyType" />
+ <xsd:element name="Oslash" type="docEmptyType" />
+ <xsd:element name="Ugrave" type="docEmptyType" />
+ <xsd:element name="Uacute" type="docEmptyType" />
+ <xsd:element name="Ucirc" type="docEmptyType" />
+ <xsd:element name="Uumlaut" type="docEmptyType" />
+ <xsd:element name="Yacute" type="docEmptyType" />
+ <xsd:element name="THORN" type="docEmptyType" />
+ <xsd:element name="szlig" type="docEmptyType" />
+ <xsd:element name="agrave" type="docEmptyType" />
+ <xsd:element name="aacute" type="docEmptyType" />
+ <xsd:element name="acirc" type="docEmptyType" />
+ <xsd:element name="atilde" type="docEmptyType" />
+ <xsd:element name="aumlaut" type="docEmptyType" />
+ <xsd:element name="aring" type="docEmptyType" />
+ <xsd:element name="aelig" type="docEmptyType" />
+ <xsd:element name="ccedil" type="docEmptyType" />
+ <xsd:element name="egrave" type="docEmptyType" />
+ <xsd:element name="eacute" type="docEmptyType" />
+ <xsd:element name="ecirc" type="docEmptyType" />
+ <xsd:element name="eumlaut" type="docEmptyType" />
+ <xsd:element name="igrave" type="docEmptyType" />
+ <xsd:element name="iacute" type="docEmptyType" />
+ <xsd:element name="icirc" type="docEmptyType" />
+ <xsd:element name="iumlaut" type="docEmptyType" />
+ <xsd:element name="eth" type="docEmptyType" />
+ <xsd:element name="ntilde" type="docEmptyType" />
+ <xsd:element name="ograve" type="docEmptyType" />
+ <xsd:element name="oacute" type="docEmptyType" />
+ <xsd:element name="ocirc" type="docEmptyType" />
+ <xsd:element name="otilde" type="docEmptyType" />
+ <xsd:element name="oumlaut" type="docEmptyType" />
+ <xsd:element name="divide" type="docEmptyType" />
+ <xsd:element name="oslash" type="docEmptyType" />
+ <xsd:element name="ugrave" type="docEmptyType" />
+ <xsd:element name="uacute" type="docEmptyType" />
+ <xsd:element name="ucirc" type="docEmptyType" />
+ <xsd:element name="uumlaut" type="docEmptyType" />
+ <xsd:element name="yacute" type="docEmptyType" />
+ <xsd:element name="thorn" type="docEmptyType" />
+ <xsd:element name="yumlaut" type="docEmptyType" />
+ <xsd:element name="fnof" type="docEmptyType" />
+ <xsd:element name="Alpha" type="docEmptyType" />
+ <xsd:element name="Beta" type="docEmptyType" />
+ <xsd:element name="Gamma" type="docEmptyType" />
+ <xsd:element name="Delta" type="docEmptyType" />
+ <xsd:element name="Epsilon" type="docEmptyType" />
+ <xsd:element name="Zeta" type="docEmptyType" />
+ <xsd:element name="Eta" type="docEmptyType" />
+ <xsd:element name="Theta" type="docEmptyType" />
+ <xsd:element name="Iota" type="docEmptyType" />
+ <xsd:element name="Kappa" type="docEmptyType" />
+ <xsd:element name="Lambda" type="docEmptyType" />
+ <xsd:element name="Mu" type="docEmptyType" />
+ <xsd:element name="Nu" type="docEmptyType" />
+ <xsd:element name="Xi" type="docEmptyType" />
+ <xsd:element name="Omicron" type="docEmptyType" />
+ <xsd:element name="Pi" type="docEmptyType" />
+ <xsd:element name="Rho" type="docEmptyType" />
+ <xsd:element name="Sigma" type="docEmptyType" />
+ <xsd:element name="Tau" type="docEmptyType" />
+ <xsd:element name="Upsilon" type="docEmptyType" />
+ <xsd:element name="Phi" type="docEmptyType" />
+ <xsd:element name="Chi" type="docEmptyType" />
+ <xsd:element name="Psi" type="docEmptyType" />
+ <xsd:element name="Omega" type="docEmptyType" />
+ <xsd:element name="alpha" type="docEmptyType" />
+ <xsd:element name="beta" type="docEmptyType" />
+ <xsd:element name="gamma" type="docEmptyType" />
+ <xsd:element name="delta" type="docEmptyType" />
+ <xsd:element name="epsilon" type="docEmptyType" />
+ <xsd:element name="zeta" type="docEmptyType" />
+ <xsd:element name="eta" type="docEmptyType" />
+ <xsd:element name="theta" type="docEmptyType" />
+ <xsd:element name="iota" type="docEmptyType" />
+ <xsd:element name="kappa" type="docEmptyType" />
+ <xsd:element name="lambda" type="docEmptyType" />
+ <xsd:element name="mu" type="docEmptyType" />
+ <xsd:element name="nu" type="docEmptyType" />
+ <xsd:element name="xi" type="docEmptyType" />
+ <xsd:element name="omicron" type="docEmptyType" />
+ <xsd:element name="pi" type="docEmptyType" />
+ <xsd:element name="rho" type="docEmptyType" />
+ <xsd:element name="sigmaf" type="docEmptyType" />
+ <xsd:element name="sigma" type="docEmptyType" />
+ <xsd:element name="tau" type="docEmptyType" />
+ <xsd:element name="upsilon" type="docEmptyType" />
+ <xsd:element name="phi" type="docEmptyType" />
+ <xsd:element name="chi" type="docEmptyType" />
+ <xsd:element name="psi" type="docEmptyType" />
+ <xsd:element name="omega" type="docEmptyType" />
+ <xsd:element name="thetasym" type="docEmptyType" />
+ <xsd:element name="upsih" type="docEmptyType" />
+ <xsd:element name="piv" type="docEmptyType" />
+ <xsd:element name="bull" type="docEmptyType" />
+ <xsd:element name="hellip" type="docEmptyType" />
+ <xsd:element name="prime" type="docEmptyType" />
+ <xsd:element name="Prime" type="docEmptyType" />
+ <xsd:element name="oline" type="docEmptyType" />
+ <xsd:element name="frasl" type="docEmptyType" />
+ <xsd:element name="weierp" type="docEmptyType" />
+ <xsd:element name="image" type="docEmptyType" />
+ <xsd:element name="real" type="docEmptyType" />
+ <xsd:element name="trademark" type="docEmptyType" />
+ <xsd:element name="alefsym" type="docEmptyType" />
+ <xsd:element name="larr" type="docEmptyType" />
+ <xsd:element name="uarr" type="docEmptyType" />
+ <xsd:element name="rarr" type="docEmptyType" />
+ <xsd:element name="darr" type="docEmptyType" />
+ <xsd:element name="harr" type="docEmptyType" />
+ <xsd:element name="crarr" type="docEmptyType" />
+ <xsd:element name="lArr" type="docEmptyType" />
+ <xsd:element name="uArr" type="docEmptyType" />
+ <xsd:element name="rArr" type="docEmptyType" />
+ <xsd:element name="dArr" type="docEmptyType" />
+ <xsd:element name="hArr" type="docEmptyType" />
+ <xsd:element name="forall" type="docEmptyType" />
+ <xsd:element name="part" type="docEmptyType" />
+ <xsd:element name="exist" type="docEmptyType" />
+ <xsd:element name="empty" type="docEmptyType" />
+ <xsd:element name="nabla" type="docEmptyType" />
+ <xsd:element name="isin" type="docEmptyType" />
+ <xsd:element name="notin" type="docEmptyType" />
+ <xsd:element name="ni" type="docEmptyType" />
+ <xsd:element name="prod" type="docEmptyType" />
+ <xsd:element name="sum" type="docEmptyType" />
+ <xsd:element name="minus" type="docEmptyType" />
+ <xsd:element name="lowast" type="docEmptyType" />
+ <xsd:element name="radic" type="docEmptyType" />
+ <xsd:element name="prop" type="docEmptyType" />
+ <xsd:element name="infin" type="docEmptyType" />
+ <xsd:element name="ang" type="docEmptyType" />
+ <xsd:element name="and" type="docEmptyType" />
+ <xsd:element name="or" type="docEmptyType" />
+ <xsd:element name="cap" type="docEmptyType" />
+ <xsd:element name="cup" type="docEmptyType" />
+ <xsd:element name="int" type="docEmptyType" />
+ <xsd:element name="there4" type="docEmptyType" />
+ <xsd:element name="sim" type="docEmptyType" />
+ <xsd:element name="cong" type="docEmptyType" />
+ <xsd:element name="asymp" type="docEmptyType" />
+ <xsd:element name="ne" type="docEmptyType" />
+ <xsd:element name="equiv" type="docEmptyType" />
+ <xsd:element name="le" type="docEmptyType" />
+ <xsd:element name="ge" type="docEmptyType" />
+ <xsd:element name="sub" type="docEmptyType" />
+ <xsd:element name="sup" type="docEmptyType" />
+ <xsd:element name="nsub" type="docEmptyType" />
+ <xsd:element name="sube" type="docEmptyType" />
+ <xsd:element name="supe" type="docEmptyType" />
+ <xsd:element name="oplus" type="docEmptyType" />
+ <xsd:element name="otimes" type="docEmptyType" />
+ <xsd:element name="perp" type="docEmptyType" />
+ <xsd:element name="sdot" type="docEmptyType" />
+ <xsd:element name="lceil" type="docEmptyType" />
+ <xsd:element name="rceil" type="docEmptyType" />
+ <xsd:element name="lfloor" type="docEmptyType" />
+ <xsd:element name="rfloor" type="docEmptyType" />
+ <xsd:element name="lang" type="docEmptyType" />
+ <xsd:element name="rang" type="docEmptyType" />
+ <xsd:element name="loz" type="docEmptyType" />
+ <xsd:element name="spades" type="docEmptyType" />
+ <xsd:element name="clubs" type="docEmptyType" />
+ <xsd:element name="hearts" type="docEmptyType" />
+ <xsd:element name="diams" type="docEmptyType" />
+ <xsd:element name="OElig" type="docEmptyType" />
+ <xsd:element name="oelig" type="docEmptyType" />
+ <xsd:element name="Scaron" type="docEmptyType" />
+ <xsd:element name="scaron" type="docEmptyType" />
+ <xsd:element name="Yumlaut" type="docEmptyType" />
+ <xsd:element name="circ" type="docEmptyType" />
+ <xsd:element name="tilde" type="docEmptyType" />
+ <xsd:element name="ensp" type="docEmptyType" />
+ <xsd:element name="emsp" type="docEmptyType" />
+ <xsd:element name="thinsp" type="docEmptyType" />
+ <xsd:element name="zwnj" type="docEmptyType" />
+ <xsd:element name="zwj" type="docEmptyType" />
+ <xsd:element name="lrm" type="docEmptyType" />
+ <xsd:element name="rlm" type="docEmptyType" />
+ <xsd:element name="ndash" type="docEmptyType" />
+ <xsd:element name="mdash" type="docEmptyType" />
+ <xsd:element name="lsquo" type="docEmptyType" />
+ <xsd:element name="rsquo" type="docEmptyType" />
+ <xsd:element name="sbquo" type="docEmptyType" />
+ <xsd:element name="ldquo" type="docEmptyType" />
+ <xsd:element name="rdquo" type="docEmptyType" />
+ <xsd:element name="bdquo" type="docEmptyType" />
+ <xsd:element name="dagger" type="docEmptyType" />
+ <xsd:element name="Dagger" type="docEmptyType" />
+ <xsd:element name="permil" type="docEmptyType" />
+ <xsd:element name="lsaquo" type="docEmptyType" />
+ <xsd:element name="rsaquo" type="docEmptyType" />
+ <xsd:element name="euro" type="docEmptyType" />
+ <xsd:element name="trademark" type="docEmptyType" />
+ </xsd:choice>
+ </xsd:group>
+
+ <xsd:complexType name="docTitleType" mixed="true">
+ <xsd:group ref="docTitleCmdGroup" minOccurs="0" maxOccurs="unbounded" />
+ </xsd:complexType>
+
+ <xsd:group name="docCmdGroup">
+ <xsd:choice>
+ <xsd:group ref="docTitleCmdGroup"/>
+ <xsd:element name="linebreak" type="docEmptyType" />
+ <xsd:element name="hruler" type="docEmptyType" />
+ <xsd:element name="preformatted" type="docMarkupType" />
+ <xsd:element name="programlisting" type="listingType" />
+ <xsd:element name="verbatim" type="xsd:string" />
+ <xsd:element name="indexentry" type="docIndexEntryType" />
+ <xsd:element name="orderedlist" type="docListType" />
+ <xsd:element name="itemizedlist" type="docListType" />
+ <xsd:element name="simplesect" type="docSimpleSectType" />
+ <xsd:element name="title" type="docTitleType" />
+ <xsd:element name="variablelist" type="docVariableListType" />
+ <xsd:element name="table" type="docTableType" />
+ <xsd:element name="heading" type="docHeadingType" />
+ <xsd:element name="image" type="docImageType" />
+ <xsd:element name="dotfile" type="docFileType" />
+ <xsd:element name="mscfile" type="docFileType" />
+ <xsd:element name="diafile" type="docFileType" />
+ <xsd:element name="toclist" type="docTocListType" />
+ <xsd:element name="language" type="docLanguageType" />
+ <xsd:element name="parameterlist" type="docParamListType" />
+ <xsd:element name="xrefsect" type="docXRefSectType" />
+ <xsd:element name="copydoc" type="docCopyType" />
+ <xsd:element name="blockquote" type="docBlockQuoteType" />
+ <xsd:element name="parblock" type="docParBlockType" />
+ </xsd:choice>
+ </xsd:group>
+
+ <xsd:complexType name="docParaType" mixed="true">
+ <xsd:group ref="docCmdGroup" minOccurs="0" maxOccurs="unbounded" />
+ </xsd:complexType>
+
+ <xsd:complexType name="docMarkupType" mixed="true">
+ <xsd:group ref="docCmdGroup" minOccurs="0" maxOccurs="unbounded" />
+ </xsd:complexType>
+
+ <xsd:complexType name="docURLLink" mixed="true">
+ <xsd:group ref="docTitleCmdGroup" minOccurs="0" maxOccurs="unbounded" />
+ <xsd:attribute name="url" type="xsd:string" />
+ </xsd:complexType>
+
+ <xsd:complexType name="docAnchorType" mixed="true">
+ <xsd:attribute name="id" type="xsd:string" />
+ </xsd:complexType>
+
+ <xsd:complexType name="docFormulaType" mixed="true">
+ <xsd:attribute name="id" type="xsd:string" />
+ </xsd:complexType>
+
+ <xsd:complexType name="docIndexEntryType">
+ <xsd:sequence>
+ <xsd:element name="primaryie" type="xsd:string" />
+ <xsd:element name="secondaryie" type="xsd:string" />
+ </xsd:sequence>
+ </xsd:complexType>
+
+ <xsd:complexType name="docListType">
+ <xsd:sequence>
+ <xsd:element name="listitem" type="docListItemType" maxOccurs="unbounded" />
+ </xsd:sequence>
+ </xsd:complexType>
+
+ <xsd:complexType name="docListItemType">
+ <xsd:sequence>
+ <xsd:element name="para" type="docParaType" minOccurs="0" maxOccurs="unbounded" />
+ </xsd:sequence>
+ </xsd:complexType>
+
+ <xsd:complexType name="docSimpleSectType">
+ <xsd:sequence>
+ <xsd:element name="title" type="docTitleType" minOccurs="0" />
+ <xsd:sequence minOccurs="0" maxOccurs="unbounded">
+ <xsd:element name="para" type="docParaType" minOccurs="1" maxOccurs="unbounded" />
+ </xsd:sequence>
+ </xsd:sequence>
+ <xsd:attribute name="kind" type="DoxSimpleSectKind" />
+ </xsd:complexType>
+
+ <xsd:complexType name="docVarListEntryType">
+ <xsd:sequence>
+ <xsd:element name="term" type="docTitleType" />
+ </xsd:sequence>
+ </xsd:complexType>
+
+ <xsd:group name="docVariableListGroup">
+ <xsd:sequence>
+ <xsd:element name="varlistentry" type="docVarListEntryType" />
+ <xsd:element name="listitem" type="docListItemType" />
+ </xsd:sequence>
+ </xsd:group>
+
+ <xsd:complexType name="docVariableListType">
+ <xsd:sequence>
+ <xsd:group ref="docVariableListGroup" maxOccurs="unbounded" />
+ </xsd:sequence>
+ </xsd:complexType>
+
+ <xsd:complexType name="docRefTextType" mixed="true">
+ <xsd:group ref="docTitleCmdGroup" minOccurs="0" maxOccurs="unbounded" />
+ <xsd:attribute name="refid" type="xsd:string" />
+ <xsd:attribute name="kindref" type="DoxRefKind" />
+ <xsd:attribute name="external" type="xsd:string" />
+ </xsd:complexType>
+
+ <xsd:complexType name="docTableType">
+ <xsd:sequence>
+ <xsd:element name="row" type="docRowType" minOccurs="0" maxOccurs="unbounded" />
+ <xsd:element name="caption" type="docCaptionType" minOccurs="0" />
+ </xsd:sequence>
+ <xsd:attribute name="rows" type="xsd:integer" />
+ <xsd:attribute name="cols" type="xsd:integer" />
+ </xsd:complexType>
+
+ <xsd:complexType name="docRowType">
+ <xsd:sequence>
+ <xsd:element name="entry" type="docEntryType" minOccurs="0" maxOccurs="unbounded" />
+ </xsd:sequence>
+ </xsd:complexType>
+
+ <xsd:complexType name="docEntryType">
+ <xsd:sequence>
+ <xsd:element name="para" type="docParaType" minOccurs="0" maxOccurs="unbounded" />
+ </xsd:sequence>
+ <xsd:attribute name="thead" type="DoxBool" />
+ </xsd:complexType>
+
+ <xsd:complexType name="docCaptionType" mixed="true">
+ <xsd:group ref="docTitleCmdGroup" minOccurs="0" maxOccurs="unbounded" />
+ </xsd:complexType>
+
+ <xsd:complexType name="docHeadingType" mixed="true">
+ <xsd:group ref="docTitleCmdGroup" minOccurs="0" maxOccurs="unbounded" />
+ <xsd:attribute name="level" type="xsd:integer" /> <!-- todo: range 1-6 -->
+ </xsd:complexType>
+
+ <xsd:complexType name="docImageType" mixed="true">
+ <xsd:group ref="docTitleCmdGroup" minOccurs="0" maxOccurs="unbounded" />
+ <xsd:attribute name="type" type="DoxImageKind" />
+ <xsd:attribute name="name" type="xsd:string" />
+ <xsd:attribute name="width" type="xsd:string" />
+ <xsd:attribute name="height" type="xsd:string" />
+ </xsd:complexType>
+
+ <xsd:complexType name="docFileType" mixed="true">
+ <xsd:group ref="docTitleCmdGroup" minOccurs="0" maxOccurs="unbounded" />
+ <xsd:attribute name="name" type="xsd:string" />
+ </xsd:complexType>
+
+ <xsd:complexType name="docTocItemType" mixed="true">
+ <xsd:group ref="docTitleCmdGroup" minOccurs="0" maxOccurs="unbounded" />
+ <xsd:attribute name="id" type="xsd:string" />
+ </xsd:complexType>
+
+ <xsd:complexType name="docTocListType">
+ <xsd:sequence>
+ <xsd:element name="tocitem" type="docTocItemType" minOccurs="0" maxOccurs="unbounded" />
+ </xsd:sequence>
+ </xsd:complexType>
+
+ <xsd:complexType name="docLanguageType">
+ <xsd:sequence>
+ <xsd:element name="para" type="docParaType" minOccurs="0" maxOccurs="unbounded" />
+ </xsd:sequence>
+ <xsd:attribute name="langid" type="xsd:string" />
+ </xsd:complexType>
+
+ <xsd:complexType name="docParamListType">
+ <xsd:sequence>
+ <xsd:element name="parameteritem" type="docParamListItem" minOccurs="0" maxOccurs="unbounded" />
+ </xsd:sequence>
+ <xsd:attribute name="kind" type="DoxParamListKind" />
+ </xsd:complexType>
+
+ <xsd:complexType name="docParamListItem">
+ <xsd:sequence>
+ <xsd:element name="parameternamelist" type="docParamNameList" minOccurs="0" maxOccurs="unbounded" />
+ <xsd:element name="parameterdescription" type="descriptionType" />
+ </xsd:sequence>
+ </xsd:complexType>
+
+ <xsd:complexType name="docParamNameList">
+ <xsd:sequence>
+ <xsd:element name="parametertype" type="docParamType" minOccurs="0" maxOccurs="unbounded" />
+ <xsd:element name="parametername" type="docParamName" minOccurs="0" maxOccurs="unbounded" />
+ </xsd:sequence>
+ </xsd:complexType>
+
+ <xsd:complexType name="docParamType" mixed="true">
+ <xsd:sequence>
+ <xsd:element name="ref" type="refTextType" minOccurs="0" maxOccurs="1" />
+ </xsd:sequence>
+ </xsd:complexType>
+
+ <xsd:complexType name="docParamName" mixed="true">
+ <xsd:sequence>
+ <xsd:element name="ref" type="refTextType" minOccurs="0" maxOccurs="1" />
+ </xsd:sequence>
+ <xsd:attribute name="direction" type="DoxParamDir" use="optional" />
+ </xsd:complexType>
+
+ <xsd:complexType name="docXRefSectType">
+ <xsd:sequence>
+ <xsd:element name="xreftitle" type="xsd:string" minOccurs="0" maxOccurs="unbounded" />
+ <xsd:element name="xrefdescription" type="descriptionType" />
+ </xsd:sequence>
+ <xsd:attribute name="id" type="xsd:string" />
+ </xsd:complexType>
+
+ <xsd:complexType name="docCopyType">
+ <xsd:sequence>
+ <xsd:element name="para" type="docParaType" minOccurs="0" maxOccurs="unbounded" />
+ <xsd:element name="sect1" type="docSect1Type" minOccurs="0" maxOccurs="unbounded" />
+ <xsd:element name="internal" type="docInternalType" minOccurs="0" />
+ </xsd:sequence>
+ <xsd:attribute name="link" type="xsd:string" />
+ </xsd:complexType>
+
+ <xsd:complexType name="docBlockQuoteType">
+ <xsd:sequence>
+ <xsd:element name="para" type="docParaType" minOccurs="0" maxOccurs="unbounded" />
+ </xsd:sequence>
+ </xsd:complexType>
+
+ <xsd:complexType name="docParBlockType">
+ <xsd:sequence>
+ <xsd:element name="para" type="docParaType" minOccurs="0" maxOccurs="unbounded" />
+ </xsd:sequence>
+ </xsd:complexType>
+
+ <xsd:complexType name="docEmptyType"/>
+
+ <!-- Simple types -->
+
+ <xsd:simpleType name="DoxBool">
+ <xsd:restriction base="xsd:string">
+ <xsd:enumeration value="yes" />
+ <xsd:enumeration value="no" />
+ </xsd:restriction>
+ </xsd:simpleType>
+
+ <xsd:simpleType name="DoxGraphRelation">
+ <xsd:restriction base="xsd:string">
+ <xsd:enumeration value="include" />
+ <xsd:enumeration value="usage" />
+ <xsd:enumeration value="template-instance" />
+ <xsd:enumeration value="public-inheritance" />
+ <xsd:enumeration value="protected-inheritance" />
+ <xsd:enumeration value="private-inheritance" />
+ </xsd:restriction>
+ </xsd:simpleType>
+
+ <xsd:simpleType name="DoxRefKind">
+ <xsd:restriction base="xsd:string">
+ <xsd:enumeration value="compound" />
+ <xsd:enumeration value="member" />
+ </xsd:restriction>
+ </xsd:simpleType>
+
+ <xsd:simpleType name="DoxMemberKind">
+ <xsd:restriction base="xsd:string">
+ <xsd:enumeration value="define" />
+ <xsd:enumeration value="property" />
+ <xsd:enumeration value="event" />
+ <xsd:enumeration value="variable" />
+ <xsd:enumeration value="typedef" />
+ <xsd:enumeration value="enum" />
+ <xsd:enumeration value="function" />
+ <xsd:enumeration value="signal" />
+ <xsd:enumeration value="prototype" />
+ <xsd:enumeration value="friend" />
+ <xsd:enumeration value="dcop" />
+ <xsd:enumeration value="slot" />
+ <xsd:enumeration value="interface" />
+ <xsd:enumeration value="service" />
+ </xsd:restriction>
+ </xsd:simpleType>
+
+ <xsd:simpleType name="DoxProtectionKind">
+ <xsd:restriction base="xsd:string">
+ <xsd:enumeration value="public" />
+ <xsd:enumeration value="protected" />
+ <xsd:enumeration value="private" />
+ <xsd:enumeration value="package" />
+ </xsd:restriction>
+ </xsd:simpleType>
+
+ <xsd:simpleType name="DoxVirtualKind">
+ <xsd:restriction base="xsd:string">
+ <xsd:enumeration value="non-virtual" />
+ <xsd:enumeration value="virtual" />
+ <xsd:enumeration value="pure-virtual" />
+ </xsd:restriction>
+ </xsd:simpleType>
+
+ <xsd:simpleType name="DoxCompoundKind">
+ <xsd:restriction base="xsd:string">
+ <xsd:enumeration value="class" />
+ <xsd:enumeration value="struct" />
+ <xsd:enumeration value="union" />
+ <xsd:enumeration value="interface" />
+ <xsd:enumeration value="protocol" />
+ <xsd:enumeration value="category" />
+ <xsd:enumeration value="exception" />
+ <xsd:enumeration value="service" />
+ <xsd:enumeration value="singleton" />
+ <xsd:enumeration value="module" />
+ <xsd:enumeration value="type" />
+ <xsd:enumeration value="file" />
+ <xsd:enumeration value="namespace" />
+ <xsd:enumeration value="group" />
+ <xsd:enumeration value="page" />
+ <xsd:enumeration value="example" />
+ <xsd:enumeration value="dir" />
+ </xsd:restriction>
+ </xsd:simpleType>
+
+ <xsd:simpleType name="DoxSectionKind">
+ <xsd:restriction base="xsd:string">
+ <xsd:enumeration value="user-defined" />
+ <xsd:enumeration value="public-type" />
+ <xsd:enumeration value="public-func" />
+ <xsd:enumeration value="public-attrib" />
+ <xsd:enumeration value="public-slot" />
+ <xsd:enumeration value="signal" />
+ <xsd:enumeration value="dcop-func" />
+ <xsd:enumeration value="property" />
+ <xsd:enumeration value="event" />
+ <xsd:enumeration value="public-static-func" />
+ <xsd:enumeration value="public-static-attrib" />
+ <xsd:enumeration value="protected-type" />
+ <xsd:enumeration value="protected-func" />
+ <xsd:enumeration value="protected-attrib" />
+ <xsd:enumeration value="protected-slot" />
+ <xsd:enumeration value="protected-static-func" />
+ <xsd:enumeration value="protected-static-attrib" />
+ <xsd:enumeration value="package-type" />
+ <xsd:enumeration value="package-func" />
+ <xsd:enumeration value="package-attrib" />
+ <xsd:enumeration value="package-static-func" />
+ <xsd:enumeration value="package-static-attrib" />
+ <xsd:enumeration value="private-type" />
+ <xsd:enumeration value="private-func" />
+ <xsd:enumeration value="private-attrib" />
+ <xsd:enumeration value="private-slot" />
+ <xsd:enumeration value="private-static-func" />
+ <xsd:enumeration value="private-static-attrib" />
+ <xsd:enumeration value="friend" />
+ <xsd:enumeration value="related" />
+ <xsd:enumeration value="define" />
+ <xsd:enumeration value="prototype" />
+ <xsd:enumeration value="typedef" />
+ <xsd:enumeration value="enum" />
+ <xsd:enumeration value="func" />
+ <xsd:enumeration value="var" />
+ </xsd:restriction>
+ </xsd:simpleType>
+
+ <xsd:simpleType name="DoxHighlightClass">
+ <xsd:restriction base="xsd:string">
+ <xsd:enumeration value="comment" />
+ <xsd:enumeration value="normal" />
+ <xsd:enumeration value="preprocessor" />
+ <xsd:enumeration value="keyword" />
+ <xsd:enumeration value="keywordtype" />
+ <xsd:enumeration value="keywordflow" />
+ <xsd:enumeration value="stringliteral" />
+ <xsd:enumeration value="charliteral" />
+ </xsd:restriction>
+ </xsd:simpleType>
+
+ <xsd:simpleType name="DoxSimpleSectKind">
+ <xsd:restriction base="xsd:string">
+ <xsd:enumeration value="see" />
+ <xsd:enumeration value="return" />
+ <xsd:enumeration value="author" />
+ <xsd:enumeration value="authors" />
+ <xsd:enumeration value="version" />
+ <xsd:enumeration value="since" />
+ <xsd:enumeration value="date" />
+ <xsd:enumeration value="note" />
+ <xsd:enumeration value="warning" />
+ <xsd:enumeration value="pre" />
+ <xsd:enumeration value="post" />
+ <xsd:enumeration value="copyright" />
+ <xsd:enumeration value="invariant" />
+ <xsd:enumeration value="remark" />
+ <xsd:enumeration value="attention" />
+ <xsd:enumeration value="par" />
+ <xsd:enumeration value="rcs" />
+ </xsd:restriction>
+ </xsd:simpleType>
+
+ <xsd:simpleType name="DoxVersionNumber">
+ <xsd:restriction base="xsd:string">
+ <xsd:pattern value="\d+\.\d+.*" />
+ </xsd:restriction>
+ </xsd:simpleType>
+
+ <xsd:simpleType name="DoxImageKind">
+ <xsd:restriction base="xsd:string">
+ <xsd:enumeration value="html" />
+ <xsd:enumeration value="latex" />
+ <xsd:enumeration value="rtf" />
+ </xsd:restriction>
+ </xsd:simpleType>
+
+ <xsd:simpleType name="DoxParamListKind">
+ <xsd:restriction base="xsd:string">
+ <xsd:enumeration value="param" />
+ <xsd:enumeration value="retval" />
+ <xsd:enumeration value="exception" />
+ <xsd:enumeration value="templateparam" />
+ </xsd:restriction>
+ </xsd:simpleType>
+
+ <xsd:simpleType name="DoxCharRange">
+ <xsd:restriction base="xsd:string">
+ <xsd:pattern value="[aeiouncAEIOUNC]" />
+ </xsd:restriction>
+ </xsd:simpleType>
+
+ <xsd:simpleType name="DoxParamDir">
+ <xsd:restriction base="xsd:string">
+ <xsd:enumeration value="in"/>
+ <xsd:enumeration value="out"/>
+ <xsd:enumeration value="inout"/>
+ </xsd:restriction>
+ </xsd:simpleType>
+
+ <xsd:simpleType name="DoxAccessor">
+ <xsd:restriction base="xsd:string">
+ <xsd:enumeration value="retain"/>
+ <xsd:enumeration value="copy"/>
+ <xsd:enumeration value="assign"/>
+ <xsd:enumeration value="weak"/>
+ <xsd:enumeration value="strong"/>
+ <xsd:enumeration value="unretained"/>
+ </xsd:restriction>
+ </xsd:simpleType>
+
+</xsd:schema>
+
--- /dev/null
+<?xml version='1.0' encoding='UTF-8' standalone='no'?>
+<doxygen xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="compound.xsd" version="1.8.8">
+ <compounddef id="dir_68267d1309a1af8e8297ef4c3efbcdba" kind="dir">
+ <compoundname>src</compoundname>
+ <innerfile refid="_outer_class_8java">OuterClass.java</innerfile>
+ <briefdescription>
+ </briefdescription>
+ <detaileddescription>
+ </detaileddescription>
+ <location file="%SOURCE_DIRECTORY%/"/>
+ </compounddef>
+</doxygen>
--- /dev/null
+<?xml version='1.0' encoding='UTF-8' standalone='no'?>
+<doxygenindex xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="index.xsd" version="1.8.8">
+ <compound refid="class_outer_class_1_1_inner_class" kind="class"><name>OuterClass::InnerClass</name>
+ </compound>
+ <compound refid="class_outer_class" kind="class"><name>OuterClass</name>
+ </compound>
+ <compound refid="_outer_class_8java" kind="file"><name>OuterClass.java</name>
+ </compound>
+ <compound refid="dir_68267d1309a1af8e8297ef4c3efbcdba" kind="dir"><name>src</name>
+ </compound>
+</doxygenindex>
--- /dev/null
+<?xml version='1.0' encoding='utf-8' ?>
+<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
+ <xsd:element name="doxygenindex" type="DoxygenType"/>
+
+ <xsd:complexType name="DoxygenType">
+ <xsd:sequence>
+ <xsd:element name="compound" type="CompoundType" minOccurs="0" maxOccurs="unbounded"/>
+ </xsd:sequence>
+ <xsd:attribute name="version" type="xsd:string" use="required"/>
+ </xsd:complexType>
+
+ <xsd:complexType name="CompoundType">
+ <xsd:sequence>
+ <xsd:element name="name" type="xsd:string"/>
+ <xsd:element name="member" type="MemberType" minOccurs="0" maxOccurs="unbounded"/>
+ </xsd:sequence>
+ <xsd:attribute name="refid" type="xsd:string" use="required"/>
+ <xsd:attribute name="kind" type="CompoundKind" use="required"/>
+ </xsd:complexType>
+
+ <xsd:complexType name="MemberType">
+ <xsd:sequence>
+ <xsd:element name="name" type="xsd:string"/>
+ </xsd:sequence>
+ <xsd:attribute name="refid" type="xsd:string" use="required"/>
+ <xsd:attribute name="kind" type="MemberKind" use="required"/>
+ </xsd:complexType>
+
+ <xsd:simpleType name="CompoundKind">
+ <xsd:restriction base="xsd:string">
+ <xsd:enumeration value="class"/>
+ <xsd:enumeration value="struct"/>
+ <xsd:enumeration value="union"/>
+ <xsd:enumeration value="interface"/>
+ <xsd:enumeration value="protocol"/>
+ <xsd:enumeration value="category"/>
+ <xsd:enumeration value="exception"/>
+ <xsd:enumeration value="file"/>
+ <xsd:enumeration value="namespace"/>
+ <xsd:enumeration value="group"/>
+ <xsd:enumeration value="page"/>
+ <xsd:enumeration value="example"/>
+ <xsd:enumeration value="dir"/>
+ </xsd:restriction>
+ </xsd:simpleType>
+
+ <xsd:simpleType name="MemberKind">
+ <xsd:restriction base="xsd:string">
+ <xsd:enumeration value="define"/>
+ <xsd:enumeration value="property"/>
+ <xsd:enumeration value="event"/>
+ <xsd:enumeration value="variable"/>
+ <xsd:enumeration value="typedef"/>
+ <xsd:enumeration value="enum"/>
+ <xsd:enumeration value="enumvalue"/>
+ <xsd:enumeration value="function"/>
+ <xsd:enumeration value="signal"/>
+ <xsd:enumeration value="prototype"/>
+ <xsd:enumeration value="friend"/>
+ <xsd:enumeration value="dcop"/>
+ <xsd:enumeration value="slot"/>
+ </xsd:restriction>
+ </xsd:simpleType>
+
+</xsd:schema>
+
--- /dev/null
+# Doxyfile 1.8.8
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project.
+#
+# All text after a double hash (##) is considered a comment and is placed in
+# front of the TAG it is preceding.
+#
+# All text after a single hash (#) is considered a comment and will be ignored.
+# The format is:
+# TAG = value [value, ...]
+# For lists, items can also be appended using:
+# TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (\" \").
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# This tag specifies the encoding used for all characters in the config file
+# that follow. The default is UTF-8 which is also the encoding used for all text
+# before the first occurrence of this tag. Doxygen uses libiconv (or the iconv
+# built into libc) for the transcoding. See http://www.gnu.org/software/libiconv
+# for the list of possible encodings.
+# The default value is: UTF-8.
+
+DOXYFILE_ENCODING = UTF-8
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by
+# double-quotes, unless you are using Doxywizard) that should identify the
+# project for which the documentation is generated. This name is used in the
+# title of most generated pages and in a few other places.
+# The default value is: My Project.
+
+PROJECT_NAME = "Test Project"
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number. This
+# could be handy for archiving the generated documentation or if some version
+# control system is used.
+
+PROJECT_NUMBER =
+
+# Using the PROJECT_BRIEF tag one can provide an optional one line description
+# for a project that appears at the top of each page and should give viewer a
+# quick idea about the purpose of the project. Keep the description short.
+
+PROJECT_BRIEF =
+
+# With the PROJECT_LOGO tag one can specify a logo or an icon that is included
+# in the documentation. The maximum height of the logo should not exceed 55
+# pixels and the maximum width should not exceed 200 pixels. Doxygen will copy
+# the logo to the output directory.
+
+PROJECT_LOGO =
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path
+# into which the generated documentation will be written. If a relative path is
+# entered, it will be relative to the location where doxygen was started. If
+# left blank the current directory will be used.
+
+OUTPUT_DIRECTORY =
+
+# If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub-
+# directories (in 2 levels) under the output directory of each output format and
+# will distribute the generated files over these directories. Enabling this
+# option can be useful when feeding doxygen a huge amount of source files, where
+# putting all generated files in the same directory would otherwise causes
+# performance problems for the file system.
+# The default value is: NO.
+
+CREATE_SUBDIRS = NO
+
+# If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII
+# characters to appear in the names of generated files. If set to NO, non-ASCII
+# characters will be escaped, for example _xE3_x81_x84 will be used for Unicode
+# U+3044.
+# The default value is: NO.
+
+ALLOW_UNICODE_NAMES = NO
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all
+# documentation generated by doxygen is written. Doxygen will use this
+# information to generate all constant output in the proper language.
+# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese,
+# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States),
+# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian,
+# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages),
+# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian,
+# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian,
+# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish,
+# Ukrainian and Vietnamese.
+# The default value is: English.
+
+OUTPUT_LANGUAGE = English
+
+# If the BRIEF_MEMBER_DESC tag is set to YES, doxygen will include brief member
+# descriptions after the members that are listed in the file and class
+# documentation (similar to Javadoc). Set to NO to disable this.
+# The default value is: YES.
+
+BRIEF_MEMBER_DESC = YES
+
+# If the REPEAT_BRIEF tag is set to YES, doxygen will prepend the brief
+# description of a member or function before the detailed description
+#
+# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
+# brief descriptions will be completely suppressed.
+# The default value is: YES.
+
+REPEAT_BRIEF = YES
+
+# This tag implements a quasi-intelligent brief description abbreviator that is
+# used to form the text in various listings. Each string in this list, if found
+# as the leading text of the brief description, will be stripped from the text
+# and the result, after processing the whole list, is used as the annotated
+# text. Otherwise, the brief description is used as-is. If left blank, the
+# following values are used ($name is automatically replaced with the name of
+# the entity):The $name class, The $name widget, The $name file, is, provides,
+# specifies, contains, represents, a, an and the.
+
+ABBREVIATE_BRIEF = "The $name class" \
+ "The $name widget" \
+ "The $name file" \
+ is \
+ provides \
+ specifies \
+ contains \
+ represents \
+ a \
+ an \
+ the
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
+# doxygen will generate a detailed section even if there is only a brief
+# description.
+# The default value is: NO.
+
+ALWAYS_DETAILED_SEC = NO
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
+# inherited members of a class in the documentation of that class as if those
+# members were ordinary class members. Constructors, destructors and assignment
+# operators of the base classes will not be shown.
+# The default value is: NO.
+
+INLINE_INHERITED_MEMB = NO
+
+# If the FULL_PATH_NAMES tag is set to YES, doxygen will prepend the full path
+# before files name in the file list and in the header files. If set to NO the
+# shortest path that makes the file name unique will be used
+# The default value is: YES.
+
+FULL_PATH_NAMES = YES
+
+# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path.
+# Stripping is only done if one of the specified strings matches the left-hand
+# part of the path. The tag can be used to show relative paths in the file list.
+# If left blank the directory from which doxygen is run is used as the path to
+# strip.
+#
+# Note that you can specify absolute paths here, but also relative paths, which
+# will be relative from the directory where doxygen is started.
+# This tag requires that the tag FULL_PATH_NAMES is set to YES.
+
+STRIP_FROM_PATH =
+
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the
+# path mentioned in the documentation of a class, which tells the reader which
+# header file to include in order to use a class. If left blank only the name of
+# the header file containing the class definition is used. Otherwise one should
+# specify the list of include paths that are normally passed to the compiler
+# using the -I flag.
+
+STRIP_FROM_INC_PATH =
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but
+# less readable) file names. This can be useful is your file systems doesn't
+# support long names like on DOS, Mac, or CD-ROM.
+# The default value is: NO.
+
+SHORT_NAMES = NO
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the
+# first line (until the first dot) of a Javadoc-style comment as the brief
+# description. If set to NO, the Javadoc-style will behave just like regular Qt-
+# style comments (thus requiring an explicit @brief command for a brief
+# description.)
+# The default value is: NO.
+
+JAVADOC_AUTOBRIEF = NO
+
+# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first
+# line (until the first dot) of a Qt-style comment as the brief description. If
+# set to NO, the Qt-style will behave just like regular Qt-style comments (thus
+# requiring an explicit \brief command for a brief description.)
+# The default value is: NO.
+
+QT_AUTOBRIEF = NO
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a
+# multi-line C++ special comment block (i.e. a block of //! or /// comments) as
+# a brief description. This used to be the default behavior. The new default is
+# to treat a multi-line C++ comment block as a detailed description. Set this
+# tag to YES if you prefer the old behavior instead.
+#
+# Note that setting this tag to YES also means that rational rose comments are
+# not recognized any more.
+# The default value is: NO.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the
+# documentation from any documented member that it re-implements.
+# The default value is: YES.
+
+INHERIT_DOCS = YES
+
+# If the SEPARATE_MEMBER_PAGES tag is set to YES then doxygen will produce a new
+# page for each member. If set to NO, the documentation of a member will be part
+# of the file/class/namespace that contains it.
+# The default value is: NO.
+
+SEPARATE_MEMBER_PAGES = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen
+# uses this value to replace tabs by spaces in code fragments.
+# Minimum value: 1, maximum value: 16, default value: 4.
+
+TAB_SIZE = 4
+
+# This tag can be used to specify a number of aliases that act as commands in
+# the documentation. An alias has the form:
+# name=value
+# For example adding
+# "sideeffect=@par Side Effects:\n"
+# will allow you to put the command \sideeffect (or @sideeffect) in the
+# documentation, which will result in a user-defined paragraph with heading
+# "Side Effects:". You can put \n's in the value part of an alias to insert
+# newlines.
+
+ALIASES =
+
+# This tag can be used to specify a number of word-keyword mappings (TCL only).
+# A mapping has the form "name=value". For example adding "class=itcl::class"
+# will allow you to use the command class in the itcl::class meaning.
+
+TCL_SUBST =
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources
+# only. Doxygen will then generate output that is more tailored for C. For
+# instance, some of the names that are used will be different. The list of all
+# members will be omitted, etc.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_FOR_C = NO
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or
+# Python sources only. Doxygen will then generate output that is more tailored
+# for that language. For instance, namespaces will be presented as packages,
+# qualified scopes will look different, etc.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_JAVA = YES
+
+# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran
+# sources. Doxygen will then generate output that is tailored for Fortran.
+# The default value is: NO.
+
+OPTIMIZE_FOR_FORTRAN = NO
+
+# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL
+# sources. Doxygen will then generate output that is tailored for VHDL.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_VHDL = NO
+
+# Doxygen selects the parser to use depending on the extension of the files it
+# parses. With this tag you can assign which parser to use for a given
+# extension. Doxygen has a built-in mapping, but you can override or extend it
+# using this tag. The format is ext=language, where ext is a file extension, and
+# language is one of the parsers supported by doxygen: IDL, Java, Javascript,
+# C#, C, C++, D, PHP, Objective-C, Python, Fortran (fixed format Fortran:
+# FortranFixed, free formatted Fortran: FortranFree, unknown formatted Fortran:
+# Fortran. In the later case the parser tries to guess whether the code is fixed
+# or free formatted code, this is the default for Fortran type files), VHDL. For
+# instance to make doxygen treat .inc files as Fortran files (default is PHP),
+# and .f files as C (default is Fortran), use: inc=Fortran f=C.
+#
+# Note: For files without extension you can use no_extension as a placeholder.
+#
+# Note that for custom extensions you also need to set FILE_PATTERNS otherwise
+# the files are not read by doxygen.
+
+EXTENSION_MAPPING =
+
+# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments
+# according to the Markdown format, which allows for more readable
+# documentation. See http://daringfireball.net/projects/markdown/ for details.
+# The output of markdown processing is further processed by doxygen, so you can
+# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in
+# case of backward compatibilities issues.
+# The default value is: YES.
+
+MARKDOWN_SUPPORT = YES
+
+# When enabled doxygen tries to link words that correspond to documented
+# classes, or namespaces to their corresponding documentation. Such a link can
+# be prevented in individual cases by putting a % sign in front of the word or
+# globally by setting AUTOLINK_SUPPORT to NO.
+# The default value is: YES.
+
+AUTOLINK_SUPPORT = YES
+
+# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
+# to include (a tag file for) the STL sources as input, then you should set this
+# tag to YES in order to let doxygen match functions declarations and
+# definitions whose arguments contain STL classes (e.g. func(std::string);
+# versus func(std::string) {}). This also make the inheritance and collaboration
+# diagrams that involve STL classes more complete and accurate.
+# The default value is: NO.
+
+BUILTIN_STL_SUPPORT = NO
+
+# If you use Microsoft's C++/CLI language, you should set this option to YES to
+# enable parsing support.
+# The default value is: NO.
+
+CPP_CLI_SUPPORT = NO
+
+# Set the SIP_SUPPORT tag to YES if your project consists of sip (see:
+# http://www.riverbankcomputing.co.uk/software/sip/intro) sources only. Doxygen
+# will parse them like normal C++ but will assume all classes use public instead
+# of private inheritance when no explicit protection keyword is present.
+# The default value is: NO.
+
+SIP_SUPPORT = NO
+
+# For Microsoft's IDL there are propget and propput attributes to indicate
+# getter and setter methods for a property. Setting this option to YES will make
+# doxygen to replace the get and set methods by a property in the documentation.
+# This will only work if the methods are indeed getting or setting a simple
+# type. If this is not the case, or you want to show the methods anyway, you
+# should set this option to NO.
+# The default value is: YES.
+
+IDL_PROPERTY_SUPPORT = YES
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
+# tag is set to YES then doxygen will reuse the documentation of the first
+# member in the group (if any) for the other members of the group. By default
+# all members of a group must be documented explicitly.
+# The default value is: NO.
+
+DISTRIBUTE_GROUP_DOC = NO
+
+# Set the SUBGROUPING tag to YES to allow class member groups of the same type
+# (for instance a group of public functions) to be put as a subgroup of that
+# type (e.g. under the Public Functions section). Set it to NO to prevent
+# subgrouping. Alternatively, this can be done per class using the
+# \nosubgrouping command.
+# The default value is: YES.
+
+SUBGROUPING = YES
+
+# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions
+# are shown inside the group in which they are included (e.g. using \ingroup)
+# instead of on a separate page (for HTML and Man pages) or section (for LaTeX
+# and RTF).
+#
+# Note that this feature does not work in combination with
+# SEPARATE_MEMBER_PAGES.
+# The default value is: NO.
+
+INLINE_GROUPED_CLASSES = NO
+
+# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions
+# with only public data fields or simple typedef fields will be shown inline in
+# the documentation of the scope in which they are defined (i.e. file,
+# namespace, or group documentation), provided this scope is documented. If set
+# to NO, structs, classes, and unions are shown on a separate page (for HTML and
+# Man pages) or section (for LaTeX and RTF).
+# The default value is: NO.
+
+INLINE_SIMPLE_STRUCTS = NO
+
+# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or
+# enum is documented as struct, union, or enum with the name of the typedef. So
+# typedef struct TypeS {} TypeT, will appear in the documentation as a struct
+# with name TypeT. When disabled the typedef will appear as a member of a file,
+# namespace, or class. And the struct will be named TypeS. This can typically be
+# useful for C code in case the coding convention dictates that all compound
+# types are typedef'ed and only the typedef is referenced, never the tag name.
+# The default value is: NO.
+
+TYPEDEF_HIDES_STRUCT = NO
+
+# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This
+# cache is used to resolve symbols given their name and scope. Since this can be
+# an expensive process and often the same symbol appears multiple times in the
+# code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small
+# doxygen will become slower. If the cache is too large, memory is wasted. The
+# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range
+# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536
+# symbols. At the end of a run doxygen will report the cache usage and suggest
+# the optimal cache size from a speed point of view.
+# Minimum value: 0, maximum value: 9, default value: 0.
+
+LOOKUP_CACHE_SIZE = 0
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# If the EXTRACT_ALL tag is set to YES, doxygen will assume all entities in
+# documentation are documented, even if no documentation was available. Private
+# class members and static file members will be hidden unless the
+# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES.
+# Note: This will also disable the warnings about undocumented members that are
+# normally produced when WARNINGS is set to YES.
+# The default value is: NO.
+
+EXTRACT_ALL = NO
+
+# If the EXTRACT_PRIVATE tag is set to YES, all private members of a class will
+# be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PRIVATE = NO
+
+# If the EXTRACT_PACKAGE tag is set to YES, all members with package or internal
+# scope will be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PACKAGE = NO
+
+# If the EXTRACT_STATIC tag is set to YES, all static members of a file will be
+# included in the documentation.
+# The default value is: NO.
+
+EXTRACT_STATIC = NO
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES, classes (and structs) defined
+# locally in source files will be included in the documentation. If set to NO,
+# only classes defined in header files are included. Does not have any effect
+# for Java sources.
+# The default value is: YES.
+
+EXTRACT_LOCAL_CLASSES = YES
+
+# This flag is only useful for Objective-C code. If set to YES, local methods,
+# which are defined in the implementation section but not in the interface are
+# included in the documentation. If set to NO, only methods in the interface are
+# included.
+# The default value is: NO.
+
+EXTRACT_LOCAL_METHODS = NO
+
+# If this flag is set to YES, the members of anonymous namespaces will be
+# extracted and appear in the documentation as a namespace called
+# 'anonymous_namespace{file}', where file will be replaced with the base name of
+# the file that contains the anonymous namespace. By default anonymous namespace
+# are hidden.
+# The default value is: NO.
+
+EXTRACT_ANON_NSPACES = NO
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all
+# undocumented members inside documented classes or files. If set to NO these
+# members will be included in the various overviews, but no documentation
+# section is generated. This option has no effect if EXTRACT_ALL is enabled.
+# The default value is: NO.
+
+HIDE_UNDOC_MEMBERS = NO
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all
+# undocumented classes that are normally visible in the class hierarchy. If set
+# to NO, these classes will be included in the various overviews. This option
+# has no effect if EXTRACT_ALL is enabled.
+# The default value is: NO.
+
+HIDE_UNDOC_CLASSES = NO
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend
+# (class|struct|union) declarations. If set to NO, these declarations will be
+# included in the documentation.
+# The default value is: NO.
+
+HIDE_FRIEND_COMPOUNDS = NO
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any
+# documentation blocks found inside the body of a function. If set to NO, these
+# blocks will be appended to the function's detailed documentation block.
+# The default value is: NO.
+
+HIDE_IN_BODY_DOCS = NO
+
+# The INTERNAL_DOCS tag determines if documentation that is typed after a
+# \internal command is included. If the tag is set to NO then the documentation
+# will be excluded. Set it to YES to include the internal documentation.
+# The default value is: NO.
+
+INTERNAL_DOCS = NO
+
+# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file
+# names in lower-case letters. If set to YES, upper-case letters are also
+# allowed. This is useful if you have classes or files whose names only differ
+# in case and if your file system supports case sensitive file names. Windows
+# and Mac users are advised to set this option to NO.
+# The default value is: system dependent.
+
+CASE_SENSE_NAMES = NO
+
+# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with
+# their full class and namespace scopes in the documentation. If set to YES, the
+# scope will be hidden.
+# The default value is: NO.
+
+HIDE_SCOPE_NAMES = NO
+
+# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of
+# the files that are included by a file in the documentation of that file.
+# The default value is: YES.
+
+SHOW_INCLUDE_FILES = YES
+
+# If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each
+# grouped member an include statement to the documentation, telling the reader
+# which file to include in order to use the member.
+# The default value is: NO.
+
+SHOW_GROUPED_MEMB_INC = NO
+
+# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include
+# files with double quotes in the documentation rather than with sharp brackets.
+# The default value is: NO.
+
+FORCE_LOCAL_INCLUDES = NO
+
+# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the
+# documentation for inline members.
+# The default value is: YES.
+
+INLINE_INFO = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the
+# (detailed) documentation of file and class members alphabetically by member
+# name. If set to NO, the members will appear in declaration order.
+# The default value is: YES.
+
+SORT_MEMBER_DOCS = YES
+
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief
+# descriptions of file, namespace and class members alphabetically by member
+# name. If set to NO, the members will appear in declaration order. Note that
+# this will also influence the order of the classes in the class list.
+# The default value is: NO.
+
+SORT_BRIEF_DOCS = NO
+
+# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the
+# (brief and detailed) documentation of class members so that constructors and
+# destructors are listed first. If set to NO the constructors will appear in the
+# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS.
+# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief
+# member documentation.
+# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting
+# detailed member documentation.
+# The default value is: NO.
+
+SORT_MEMBERS_CTORS_1ST = NO
+
+# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy
+# of group names into alphabetical order. If set to NO the group names will
+# appear in their defined order.
+# The default value is: NO.
+
+SORT_GROUP_NAMES = NO
+
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by
+# fully-qualified names, including namespaces. If set to NO, the class list will
+# be sorted only by class name, not including the namespace part.
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
+# Note: This option applies only to the class list, not to the alphabetical
+# list.
+# The default value is: NO.
+
+SORT_BY_SCOPE_NAME = NO
+
+# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper
+# type resolution of all parameters of a function it will reject a match between
+# the prototype and the implementation of a member function even if there is
+# only one candidate or it is obvious which candidate to choose by doing a
+# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still
+# accept a match between prototype and implementation in such cases.
+# The default value is: NO.
+
+STRICT_PROTO_MATCHING = NO
+
+# The GENERATE_TODOLIST tag can be used to enable (YES) or disable (NO) the todo
+# list. This list is created by putting \todo commands in the documentation.
+# The default value is: YES.
+
+GENERATE_TODOLIST = YES
+
+# The GENERATE_TESTLIST tag can be used to enable (YES) or disable (NO) the test
+# list. This list is created by putting \test commands in the documentation.
+# The default value is: YES.
+
+GENERATE_TESTLIST = YES
+
+# The GENERATE_BUGLIST tag can be used to enable (YES) or disable (NO) the bug
+# list. This list is created by putting \bug commands in the documentation.
+# The default value is: YES.
+
+GENERATE_BUGLIST = YES
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or disable (NO)
+# the deprecated list. This list is created by putting \deprecated commands in
+# the documentation.
+# The default value is: YES.
+
+GENERATE_DEPRECATEDLIST= YES
+
+# The ENABLED_SECTIONS tag can be used to enable conditional documentation
+# sections, marked by \if <section_label> ... \endif and \cond <section_label>
+# ... \endcond blocks.
+
+ENABLED_SECTIONS =
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the
+# initial value of a variable or macro / define can have for it to appear in the
+# documentation. If the initializer consists of more lines than specified here
+# it will be hidden. Use a value of 0 to hide initializers completely. The
+# appearance of the value of individual variables and macros / defines can be
+# controlled using \showinitializer or \hideinitializer command in the
+# documentation regardless of this setting.
+# Minimum value: 0, maximum value: 10000, default value: 30.
+
+MAX_INITIALIZER_LINES = 30
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at
+# the bottom of the documentation of classes and structs. If set to YES, the
+# list will mention the files that were used to generate the documentation.
+# The default value is: YES.
+
+SHOW_USED_FILES = YES
+
+# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This
+# will remove the Files entry from the Quick Index and from the Folder Tree View
+# (if specified).
+# The default value is: YES.
+
+SHOW_FILES = YES
+
+# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces
+# page. This will remove the Namespaces entry from the Quick Index and from the
+# Folder Tree View (if specified).
+# The default value is: YES.
+
+SHOW_NAMESPACES = YES
+
+# The FILE_VERSION_FILTER tag can be used to specify a program or script that
+# doxygen should invoke to get the current version for each file (typically from
+# the version control system). Doxygen will invoke the program by executing (via
+# popen()) the command command input-file, where command is the value of the
+# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided
+# by doxygen. Whatever the program writes to standard output is used as the file
+# version. For an example see the documentation.
+
+FILE_VERSION_FILTER =
+
+# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed
+# by doxygen. The layout file controls the global structure of the generated
+# output files in an output format independent way. To create the layout file
+# that represents doxygen's defaults, run doxygen with the -l option. You can
+# optionally specify a file name after the option, if omitted DoxygenLayout.xml
+# will be used as the name of the layout file.
+#
+# Note that if you run doxygen from a directory containing a file called
+# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE
+# tag is left empty.
+
+LAYOUT_FILE =
+
+# The CITE_BIB_FILES tag can be used to specify one or more bib files containing
+# the reference definitions. This must be a list of .bib files. The .bib
+# extension is automatically appended if omitted. This requires the bibtex tool
+# to be installed. See also http://en.wikipedia.org/wiki/BibTeX for more info.
+# For LaTeX the style of the bibliography can be controlled using
+# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the
+# search path. See also \cite for info how to create references.
+
+CITE_BIB_FILES =
+
+#---------------------------------------------------------------------------
+# Configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated to
+# standard output by doxygen. If QUIET is set to YES this implies that the
+# messages are off.
+# The default value is: NO.
+
+QUIET = NO
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are
+# generated to standard error (stderr) by doxygen. If WARNINGS is set to YES
+# this implies that the warnings are on.
+#
+# Tip: Turn warnings on while writing the documentation.
+# The default value is: YES.
+
+WARNINGS = YES
+
+# If the WARN_IF_UNDOCUMENTED tag is set to YES then doxygen will generate
+# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag
+# will automatically be disabled.
+# The default value is: YES.
+
+WARN_IF_UNDOCUMENTED = YES
+
+# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for
+# potential errors in the documentation, such as not documenting some parameters
+# in a documented function, or documenting parameters that don't exist or using
+# markup commands wrongly.
+# The default value is: YES.
+
+WARN_IF_DOC_ERROR = YES
+
+# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that
+# are documented, but have no documentation for their parameters or return
+# value. If set to NO, doxygen will only warn about wrong or incomplete
+# parameter documentation, but not about the absence of documentation.
+# The default value is: NO.
+
+WARN_NO_PARAMDOC = NO
+
+# The WARN_FORMAT tag determines the format of the warning messages that doxygen
+# can produce. The string should contain the $file, $line, and $text tags, which
+# will be replaced by the file and line number from which the warning originated
+# and the warning text. Optionally the format may contain $version, which will
+# be replaced by the version of the file (if it could be obtained via
+# FILE_VERSION_FILTER)
+# The default value is: $file:$line: $text.
+
+WARN_FORMAT = "$file:$line: $text"
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning and error
+# messages should be written. If left blank the output is written to standard
+# error (stderr).
+
+WARN_LOGFILE =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag is used to specify the files and/or directories that contain
+# documented source files. You may enter file names like myfile.cpp or
+# directories like /usr/src/myproject. Separate the files or directories with
+# spaces.
+# Note: If this tag is empty the current directory is searched.
+
+INPUT = src
+
+# This tag can be used to specify the character encoding of the source files
+# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
+# libiconv (or the iconv built into libc) for the transcoding. See the libiconv
+# documentation (see: http://www.gnu.org/software/libiconv) for the list of
+# possible encodings.
+# The default value is: UTF-8.
+
+INPUT_ENCODING = UTF-8
+
+# If the value of the INPUT tag contains directories, you can use the
+# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and
+# *.h) to filter out the source-files in the directories. If left blank the
+# following patterns are tested:*.c, *.cc, *.cxx, *.cpp, *.c++, *.java, *.ii,
+# *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, *.hh, *.hxx, *.hpp,
+# *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, *.m, *.markdown,
+# *.md, *.mm, *.dox, *.py, *.f90, *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf,
+# *.qsf, *.as and *.js.
+
+FILE_PATTERNS = *.c \
+ *.cc \
+ *.cxx \
+ *.cpp \
+ *.c++ \
+ *.java \
+ *.ii \
+ *.ixx \
+ *.ipp \
+ *.i++ \
+ *.inl \
+ *.idl \
+ *.ddl \
+ *.odl \
+ *.h \
+ *.hh \
+ *.hxx \
+ *.hpp \
+ *.h++ \
+ *.cs \
+ *.d \
+ *.php \
+ *.php4 \
+ *.php5 \
+ *.phtml \
+ *.inc \
+ *.m \
+ *.markdown \
+ *.md \
+ *.mm \
+ *.dox \
+ *.py \
+ *.f90 \
+ *.f \
+ *.for \
+ *.tcl \
+ *.vhd \
+ *.vhdl \
+ *.ucf \
+ *.qsf \
+ *.as \
+ *.js
+
+# The RECURSIVE tag can be used to specify whether or not subdirectories should
+# be searched for input files as well.
+# The default value is: NO.
+
+RECURSIVE = YES
+
+# The EXCLUDE tag can be used to specify files and/or directories that should be
+# excluded from the INPUT source files. This way you can easily exclude a
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+#
+# Note that relative paths are relative to the directory from which doxygen is
+# run.
+
+EXCLUDE =
+
+# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or
+# directories that are symbolic links (a Unix file system feature) are excluded
+# from the input.
+# The default value is: NO.
+
+EXCLUDE_SYMLINKS = NO
+
+# If the value of the INPUT tag contains directories, you can use the
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
+# certain files from those directories.
+#
+# Note that the wildcards are matched against the file with absolute path, so to
+# exclude all test directories for example use the pattern */test/*
+
+EXCLUDE_PATTERNS =
+
+# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
+# (namespaces, classes, functions, etc.) that should be excluded from the
+# output. The symbol name can be a fully qualified name, a word, or if the
+# wildcard * is used, a substring. Examples: ANamespace, AClass,
+# AClass::ANamespace, ANamespace::*Test
+#
+# Note that the wildcards are matched against the file with absolute path, so to
+# exclude all test directories use the pattern */test/*
+
+EXCLUDE_SYMBOLS =
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or directories
+# that contain example code fragments that are included (see the \include
+# command).
+
+EXAMPLE_PATH =
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and
+# *.h) to filter out the source-files in the directories. If left blank all
+# files are included.
+
+EXAMPLE_PATTERNS = *
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
+# searched for input files to be used with the \include or \dontinclude commands
+# irrespective of the value of the RECURSIVE tag.
+# The default value is: NO.
+
+EXAMPLE_RECURSIVE = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or directories
+# that contain images that are to be included in the documentation (see the
+# \image command).
+
+IMAGE_PATH =
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should
+# invoke to filter for each input file. Doxygen will invoke the filter program
+# by executing (via popen()) the command:
+#
+# <filter> <input-file>
+#
+# where <filter> is the value of the INPUT_FILTER tag, and <input-file> is the
+# name of an input file. Doxygen will then use the output that the filter
+# program writes to standard output. If FILTER_PATTERNS is specified, this tag
+# will be ignored.
+#
+# Note that the filter must not add or remove lines; it is applied before the
+# code is scanned, but not when the output code is generated. If lines are added
+# or removed, the anchors will not be placed correctly.
+
+INPUT_FILTER =
+
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
+# basis. Doxygen will compare the file name with each pattern and apply the
+# filter if there is a match. The filters are a list of the form: pattern=filter
+# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how
+# filters are used. If the FILTER_PATTERNS tag is empty or if none of the
+# patterns match the file name, INPUT_FILTER is applied.
+
+FILTER_PATTERNS =
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
+# INPUT_FILTER) will also be used to filter the input files that are used for
+# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES).
+# The default value is: NO.
+
+FILTER_SOURCE_FILES = NO
+
+# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file
+# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and
+# it is also possible to disable source filtering for a specific pattern using
+# *.ext= (so without naming a filter).
+# This tag requires that the tag FILTER_SOURCE_FILES is set to YES.
+
+FILTER_SOURCE_PATTERNS =
+
+# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that
+# is part of the input, its contents will be placed on the main page
+# (index.html). This can be useful if you have a project on for instance GitHub
+# and want to reuse the introduction page also for the doxygen output.
+
+USE_MDFILE_AS_MAINPAGE =
+
+#---------------------------------------------------------------------------
+# Configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will be
+# generated. Documented entities will be cross-referenced with these sources.
+#
+# Note: To get rid of all source code in the generated output, make sure that
+# also VERBATIM_HEADERS is set to NO.
+# The default value is: NO.
+
+SOURCE_BROWSER = NO
+
+# Setting the INLINE_SOURCES tag to YES will include the body of functions,
+# classes and enums directly into the documentation.
+# The default value is: NO.
+
+INLINE_SOURCES = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any
+# special comment blocks from generated source code fragments. Normal C, C++ and
+# Fortran comments will always remain visible.
+# The default value is: YES.
+
+STRIP_CODE_COMMENTS = YES
+
+# If the REFERENCED_BY_RELATION tag is set to YES then for each documented
+# function all documented functions referencing it will be listed.
+# The default value is: NO.
+
+REFERENCED_BY_RELATION = NO
+
+# If the REFERENCES_RELATION tag is set to YES then for each documented function
+# all documented entities called/used by that function will be listed.
+# The default value is: NO.
+
+REFERENCES_RELATION = NO
+
+# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set
+# to YES then the hyperlinks from functions in REFERENCES_RELATION and
+# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will
+# link to the documentation.
+# The default value is: YES.
+
+REFERENCES_LINK_SOURCE = YES
+
+# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the
+# source code will show a tooltip with additional information such as prototype,
+# brief description and links to the definition and documentation. Since this
+# will make the HTML file larger and loading of large files a bit slower, you
+# can opt to disable this feature.
+# The default value is: YES.
+# This tag requires that the tag SOURCE_BROWSER is set to YES.
+
+SOURCE_TOOLTIPS = YES
+
+# If the USE_HTAGS tag is set to YES then the references to source code will
+# point to the HTML generated by the htags(1) tool instead of doxygen built-in
+# source browser. The htags tool is part of GNU's global source tagging system
+# (see http://www.gnu.org/software/global/global.html). You will need version
+# 4.8.6 or higher.
+#
+# To use it do the following:
+# - Install the latest version of global
+# - Enable SOURCE_BROWSER and USE_HTAGS in the config file
+# - Make sure the INPUT points to the root of the source tree
+# - Run doxygen as normal
+#
+# Doxygen will invoke htags (and that will in turn invoke gtags), so these
+# tools must be available from the command line (i.e. in the search path).
+#
+# The result: instead of the source browser generated by doxygen, the links to
+# source code will now point to the output of htags.
+# The default value is: NO.
+# This tag requires that the tag SOURCE_BROWSER is set to YES.
+
+USE_HTAGS = NO
+
+# If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a
+# verbatim copy of the header file for each class for which an include is
+# specified. Set to NO to disable this.
+# See also: Section \class.
+# The default value is: YES.
+
+VERBATIM_HEADERS = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all
+# compounds will be generated. Enable this if the project contains a lot of
+# classes, structs, unions or interfaces.
+# The default value is: YES.
+
+ALPHABETICAL_INDEX = YES
+
+# The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in
+# which the alphabetical index list will be split.
+# Minimum value: 1, maximum value: 20, default value: 5.
+# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
+
+COLS_IN_ALPHA_INDEX = 5
+
+# In case all classes in a project start with a common prefix, all classes will
+# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag
+# can be used to specify a prefix (or a list of prefixes) that should be ignored
+# while generating the index headers.
+# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
+
+IGNORE_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES, doxygen will generate HTML output
+# The default value is: YES.
+
+GENERATE_HTML = NO
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: html.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_OUTPUT = html
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each
+# generated HTML page (for example: .htm, .php, .asp).
+# The default value is: .html.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_FILE_EXTENSION = .html
+
+# The HTML_HEADER tag can be used to specify a user-defined HTML header file for
+# each generated HTML page. If the tag is left blank doxygen will generate a
+# standard header.
+#
+# To get valid HTML the header file that includes any scripts and style sheets
+# that doxygen needs, which is dependent on the configuration options used (e.g.
+# the setting GENERATE_TREEVIEW). It is highly recommended to start with a
+# default header using
+# doxygen -w html new_header.html new_footer.html new_stylesheet.css
+# YourConfigFile
+# and then modify the file new_header.html. See also section "Doxygen usage"
+# for information on how to generate the default header that doxygen normally
+# uses.
+# Note: The header is subject to change so you typically have to regenerate the
+# default header when upgrading to a newer version of doxygen. For a description
+# of the possible markers and block names see the documentation.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_HEADER =
+
+# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each
+# generated HTML page. If the tag is left blank doxygen will generate a standard
+# footer. See HTML_HEADER for more information on how to generate a default
+# footer and what special commands can be used inside the footer. See also
+# section "Doxygen usage" for information on how to generate the default footer
+# that doxygen normally uses.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_FOOTER =
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style
+# sheet that is used by each HTML page. It can be used to fine-tune the look of
+# the HTML output. If left blank doxygen will generate a default style sheet.
+# See also section "Doxygen usage" for information on how to generate the style
+# sheet that doxygen normally uses.
+# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as
+# it is more robust and this tag (HTML_STYLESHEET) will in the future become
+# obsolete.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_STYLESHEET =
+
+# The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined
+# cascading style sheets that are included after the standard style sheets
+# created by doxygen. Using this option one can overrule certain style aspects.
+# This is preferred over using HTML_STYLESHEET since it does not replace the
+# standard style sheet and is therefore more robust against future updates.
+# Doxygen will copy the style sheet files to the output directory.
+# Note: The order of the extra stylesheet files is of importance (e.g. the last
+# stylesheet in the list overrules the setting of the previous ones in the
+# list). For an example see the documentation.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_EXTRA_STYLESHEET =
+
+# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the HTML output directory. Note
+# that these files will be copied to the base HTML output directory. Use the
+# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these
+# files. In the HTML_STYLESHEET file, use the file name only. Also note that the
+# files will be copied as-is; there are no commands or markers available.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_EXTRA_FILES =
+
+# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen
+# will adjust the colors in the stylesheet and background images according to
+# this color. Hue is specified as an angle on a colorwheel, see
+# http://en.wikipedia.org/wiki/Hue for more information. For instance the value
+# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300
+# purple, and 360 is red again.
+# Minimum value: 0, maximum value: 359, default value: 220.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_HUE = 220
+
+# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors
+# in the HTML output. For a value of 0 the output will use grayscales only. A
+# value of 255 will produce the most vivid colors.
+# Minimum value: 0, maximum value: 255, default value: 100.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_SAT = 100
+
+# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the
+# luminance component of the colors in the HTML output. Values below 100
+# gradually make the output lighter, whereas values above 100 make the output
+# darker. The value divided by 100 is the actual gamma applied, so 80 represents
+# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not
+# change the gamma.
+# Minimum value: 40, maximum value: 240, default value: 80.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_GAMMA = 80
+
+# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML
+# page will contain the date and time when the page was generated. Setting this
+# to NO can help when comparing the output of multiple runs.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_TIMESTAMP = YES
+
+# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
+# documentation will contain sections that can be hidden and shown after the
+# page has loaded.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_DYNAMIC_SECTIONS = NO
+
+# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries
+# shown in the various tree structured indices initially; the user can expand
+# and collapse entries dynamically later on. Doxygen will expand the tree to
+# such a level that at most the specified number of entries are visible (unless
+# a fully collapsed tree already exceeds this amount). So setting the number of
+# entries 1 will produce a full collapsed tree by default. 0 is a special value
+# representing an infinite number of entries and will result in a full expanded
+# tree by default.
+# Minimum value: 0, maximum value: 9999, default value: 100.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_INDEX_NUM_ENTRIES = 100
+
+# If the GENERATE_DOCSET tag is set to YES, additional index files will be
+# generated that can be used as input for Apple's Xcode 3 integrated development
+# environment (see: http://developer.apple.com/tools/xcode/), introduced with
+# OSX 10.5 (Leopard). To create a documentation set, doxygen will generate a
+# Makefile in the HTML output directory. Running make will produce the docset in
+# that directory and running make install will install the docset in
+# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at
+# startup. See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html
+# for more information.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_DOCSET = NO
+
+# This tag determines the name of the docset feed. A documentation feed provides
+# an umbrella under which multiple documentation sets from a single provider
+# (such as a company or product suite) can be grouped.
+# The default value is: Doxygen generated docs.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_FEEDNAME = "Doxygen generated docs"
+
+# This tag specifies a string that should uniquely identify the documentation
+# set bundle. This should be a reverse domain-name style string, e.g.
+# com.mycompany.MyDocSet. Doxygen will append .docset to the name.
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_BUNDLE_ID = org.doxygen.Project
+
+# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify
+# the documentation publisher. This should be a reverse domain-name style
+# string, e.g. com.mycompany.MyDocSet.documentation.
+# The default value is: org.doxygen.Publisher.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_PUBLISHER_ID = org.doxygen.Publisher
+
+# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher.
+# The default value is: Publisher.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_PUBLISHER_NAME = Publisher
+
+# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three
+# additional HTML index files: index.hhp, index.hhc, and index.hhk. The
+# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop
+# (see: http://www.microsoft.com/en-us/download/details.aspx?id=21138) on
+# Windows.
+#
+# The HTML Help Workshop contains a compiler that can convert all HTML output
+# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML
+# files are now used as the Windows 98 help format, and will replace the old
+# Windows help format (.hlp) on all Windows platforms in the future. Compressed
+# HTML files also contain an index, a table of contents, and you can search for
+# words in the documentation. The HTML workshop also contains a viewer for
+# compressed HTML files.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_HTMLHELP = NO
+
+# The CHM_FILE tag can be used to specify the file name of the resulting .chm
+# file. You can add a path in front of the file if the result should not be
+# written to the html output directory.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+CHM_FILE =
+
+# The HHC_LOCATION tag can be used to specify the location (absolute path
+# including file name) of the HTML help compiler (hhc.exe). If non-empty,
+# doxygen will try to run the HTML help compiler on the generated index.hhp.
+# The file has to be specified with full path.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+HHC_LOCATION =
+
+# The GENERATE_CHI flag controls if a separate .chi index file is generated
+# (YES) or that it should be included in the master .chm file (NO).
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+GENERATE_CHI = NO
+
+# The CHM_INDEX_ENCODING is used to encode HtmlHelp index (hhk), content (hhc)
+# and project file content.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+CHM_INDEX_ENCODING =
+
+# The BINARY_TOC flag controls whether a binary table of contents is generated
+# (YES) or a normal table of contents (NO) in the .chm file. Furthermore it
+# enables the Previous and Next buttons.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+BINARY_TOC = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members to
+# the table of contents of the HTML help documentation and to the tree view.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+TOC_EXPAND = NO
+
+# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and
+# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that
+# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help
+# (.qch) of the generated HTML documentation.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_QHP = NO
+
+# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify
+# the file name of the resulting .qch file. The path specified is relative to
+# the HTML output folder.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QCH_FILE =
+
+# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help
+# Project output. For more information please see Qt Help Project / Namespace
+# (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#namespace).
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_NAMESPACE = org.doxygen.Project
+
+# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt
+# Help Project output. For more information please see Qt Help Project / Virtual
+# Folders (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#virtual-
+# folders).
+# The default value is: doc.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_VIRTUAL_FOLDER = doc
+
+# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom
+# filter to add. For more information please see Qt Help Project / Custom
+# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-
+# filters).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_CUST_FILTER_NAME =
+
+# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the
+# custom filter to add. For more information please see Qt Help Project / Custom
+# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-
+# filters).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_CUST_FILTER_ATTRS =
+
+# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this
+# project's filter section matches. Qt Help Project / Filter Attributes (see:
+# http://qt-project.org/doc/qt-4.8/qthelpproject.html#filter-attributes).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_SECT_FILTER_ATTRS =
+
+# The QHG_LOCATION tag can be used to specify the location of Qt's
+# qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the
+# generated .qhp file.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHG_LOCATION =
+
+# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be
+# generated, together with the HTML files, they form an Eclipse help plugin. To
+# install this plugin and make it available under the help contents menu in
+# Eclipse, the contents of the directory containing the HTML and XML files needs
+# to be copied into the plugins directory of eclipse. The name of the directory
+# within the plugins directory should be the same as the ECLIPSE_DOC_ID value.
+# After copying Eclipse needs to be restarted before the help appears.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_ECLIPSEHELP = NO
+
+# A unique identifier for the Eclipse help plugin. When installing the plugin
+# the directory name containing the HTML and XML files should also have this
+# name. Each documentation set should have its own identifier.
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES.
+
+ECLIPSE_DOC_ID = org.doxygen.Project
+
+# If you want full control over the layout of the generated HTML pages it might
+# be necessary to disable the index and replace it with your own. The
+# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top
+# of each HTML page. A value of NO enables the index and the value YES disables
+# it. Since the tabs in the index contain the same information as the navigation
+# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+DISABLE_INDEX = NO
+
+# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
+# structure should be generated to display hierarchical information. If the tag
+# value is set to YES, a side panel will be generated containing a tree-like
+# index structure (just like the one that is generated for HTML Help). For this
+# to work a browser that supports JavaScript, DHTML, CSS and frames is required
+# (i.e. any modern browser). Windows users are probably better off using the
+# HTML help feature. Via custom stylesheets (see HTML_EXTRA_STYLESHEET) one can
+# further fine-tune the look of the index. As an example, the default style
+# sheet generated by doxygen has an example that shows how to put an image at
+# the root of the tree instead of the PROJECT_NAME. Since the tree basically has
+# the same information as the tab index, you could consider setting
+# DISABLE_INDEX to YES when enabling this option.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_TREEVIEW = NO
+
+# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that
+# doxygen will group on one line in the generated HTML documentation.
+#
+# Note that a value of 0 will completely suppress the enum values from appearing
+# in the overview section.
+# Minimum value: 0, maximum value: 20, default value: 4.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+ENUM_VALUES_PER_LINE = 4
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used
+# to set the initial width (in pixels) of the frame in which the tree is shown.
+# Minimum value: 0, maximum value: 1500, default value: 250.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+TREEVIEW_WIDTH = 250
+
+# If the EXT_LINKS_IN_WINDOW option is set to YES, doxygen will open links to
+# external symbols imported via tag files in a separate window.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+EXT_LINKS_IN_WINDOW = NO
+
+# Use this tag to change the font size of LaTeX formulas included as images in
+# the HTML documentation. When you change the font size after a successful
+# doxygen run you need to manually remove any form_*.png images from the HTML
+# output directory to force them to be regenerated.
+# Minimum value: 8, maximum value: 50, default value: 10.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+FORMULA_FONTSIZE = 10
+
+# Use the FORMULA_TRANPARENT tag to determine whether or not the images
+# generated for formulas are transparent PNGs. Transparent PNGs are not
+# supported properly for IE 6.0, but are supported on all modern browsers.
+#
+# Note that when changing this option you need to delete any form_*.png files in
+# the HTML output directory before the changes have effect.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+FORMULA_TRANSPARENT = YES
+
+# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see
+# http://www.mathjax.org) which uses client side Javascript for the rendering
+# instead of using pre-rendered bitmaps. Use this if you do not have LaTeX
+# installed or if you want to formulas look prettier in the HTML output. When
+# enabled you may also need to install MathJax separately and configure the path
+# to it using the MATHJAX_RELPATH option.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+USE_MATHJAX = NO
+
+# When MathJax is enabled you can set the default output format to be used for
+# the MathJax output. See the MathJax site (see:
+# http://docs.mathjax.org/en/latest/output.html) for more details.
+# Possible values are: HTML-CSS (which is slower, but has the best
+# compatibility), NativeMML (i.e. MathML) and SVG.
+# The default value is: HTML-CSS.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_FORMAT = HTML-CSS
+
+# When MathJax is enabled you need to specify the location relative to the HTML
+# output directory using the MATHJAX_RELPATH option. The destination directory
+# should contain the MathJax.js script. For instance, if the mathjax directory
+# is located at the same level as the HTML output directory, then
+# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax
+# Content Delivery Network so you can quickly see the result without installing
+# MathJax. However, it is strongly recommended to install a local copy of
+# MathJax from http://www.mathjax.org before deployment.
+# The default value is: http://cdn.mathjax.org/mathjax/latest.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest
+
+# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax
+# extension names that should be enabled during MathJax rendering. For example
+# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_EXTENSIONS =
+
+# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces
+# of code that will be used on startup of the MathJax code. See the MathJax site
+# (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an
+# example see the documentation.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_CODEFILE =
+
+# When the SEARCHENGINE tag is enabled doxygen will generate a search box for
+# the HTML output. The underlying search engine uses javascript and DHTML and
+# should work on any modern browser. Note that when using HTML help
+# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET)
+# there is already a search function so this one should typically be disabled.
+# For large projects the javascript based search engine can be slow, then
+# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to
+# search using the keyboard; to jump to the search box use <access key> + S
+# (what the <access key> is depends on the OS and browser, but it is typically
+# <CTRL>, <ALT>/<option>, or both). Inside the search box use the <cursor down
+# key> to jump into the search results window, the results can be navigated
+# using the <cursor keys>. Press <Enter> to select an item or <escape> to cancel
+# the search. The filter options can be selected when the cursor is inside the
+# search box by pressing <Shift>+<cursor down>. Also here use the <cursor keys>
+# to select a filter and <Enter> or <escape> to activate or cancel the filter
+# option.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+SEARCHENGINE = YES
+
+# When the SERVER_BASED_SEARCH tag is enabled the search engine will be
+# implemented using a web server instead of a web client using Javascript. There
+# are two flavors of web server based searching depending on the EXTERNAL_SEARCH
+# setting. When disabled, doxygen will generate a PHP script for searching and
+# an index file used by the script. When EXTERNAL_SEARCH is enabled the indexing
+# and searching needs to be provided by external tools. See the section
+# "External Indexing and Searching" for details.
+# The default value is: NO.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SERVER_BASED_SEARCH = NO
+
+# When EXTERNAL_SEARCH tag is enabled doxygen will no longer generate the PHP
+# script for searching. Instead the search results are written to an XML file
+# which needs to be processed by an external indexer. Doxygen will invoke an
+# external search engine pointed to by the SEARCHENGINE_URL option to obtain the
+# search results.
+#
+# Doxygen ships with an example indexer (doxyindexer) and search engine
+# (doxysearch.cgi) which are based on the open source search engine library
+# Xapian (see: http://xapian.org/).
+#
+# See the section "External Indexing and Searching" for details.
+# The default value is: NO.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTERNAL_SEARCH = NO
+
+# The SEARCHENGINE_URL should point to a search engine hosted by a web server
+# which will return the search results when EXTERNAL_SEARCH is enabled.
+#
+# Doxygen ships with an example indexer (doxyindexer) and search engine
+# (doxysearch.cgi) which are based on the open source search engine library
+# Xapian (see: http://xapian.org/). See the section "External Indexing and
+# Searching" for details.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SEARCHENGINE_URL =
+
+# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the unindexed
+# search data is written to a file for indexing by an external tool. With the
+# SEARCHDATA_FILE tag the name of this file can be specified.
+# The default file is: searchdata.xml.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SEARCHDATA_FILE = searchdata.xml
+
+# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the
+# EXTERNAL_SEARCH_ID tag can be used as an identifier for the project. This is
+# useful in combination with EXTRA_SEARCH_MAPPINGS to search through multiple
+# projects and redirect the results back to the right project.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTERNAL_SEARCH_ID =
+
+# The EXTRA_SEARCH_MAPPINGS tag can be used to enable searching through doxygen
+# projects other than the one defined by this configuration file, but that are
+# all added to the same external search index. Each project needs to have a
+# unique id set via EXTERNAL_SEARCH_ID. The search mapping then maps the id of
+# to a relative location where the documentation can be found. The format is:
+# EXTRA_SEARCH_MAPPINGS = tagname1=loc1 tagname2=loc2 ...
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTRA_SEARCH_MAPPINGS =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES, doxygen will generate LaTeX output.
+# The default value is: YES.
+
+GENERATE_LATEX = NO
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: latex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_OUTPUT = latex
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
+# invoked.
+#
+# Note that when enabling USE_PDFLATEX this option is only used for generating
+# bitmaps for formulas in the HTML output, but not in the Makefile that is
+# written to the output directory.
+# The default file is: latex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_CMD_NAME = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to generate
+# index for LaTeX.
+# The default file is: makeindex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+MAKEINDEX_CMD_NAME = makeindex
+
+# If the COMPACT_LATEX tag is set to YES, doxygen generates more compact LaTeX
+# documents. This may be useful for small projects and may help to save some
+# trees in general.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+COMPACT_LATEX = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used by the
+# printer.
+# Possible values are: a4 (210 x 297 mm), letter (8.5 x 11 inches), legal (8.5 x
+# 14 inches) and executive (7.25 x 10.5 inches).
+# The default value is: a4.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+PAPER_TYPE = a4
+
+# The EXTRA_PACKAGES tag can be used to specify one or more LaTeX package names
+# that should be included in the LaTeX output. To get the times font for
+# instance you can specify
+# EXTRA_PACKAGES=times
+# If left blank no extra packages will be included.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+EXTRA_PACKAGES =
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for the
+# generated LaTeX document. The header should contain everything until the first
+# chapter. If it is left blank doxygen will generate a standard header. See
+# section "Doxygen usage" for information on how to let doxygen write the
+# default header to a separate file.
+#
+# Note: Only use a user-defined header if you know what you are doing! The
+# following commands have a special meaning inside the header: $title,
+# $datetime, $date, $doxygenversion, $projectname, $projectnumber,
+# $projectbrief, $projectlogo. Doxygen will replace $title with the empty
+# string, for the replacement values of the other commands the user is referred
+# to HTML_HEADER.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_HEADER =
+
+# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for the
+# generated LaTeX document. The footer should contain everything after the last
+# chapter. If it is left blank doxygen will generate a standard footer. See
+# LATEX_HEADER for more information on how to generate a default footer and what
+# special commands can be used inside the footer.
+#
+# Note: Only use a user-defined footer if you know what you are doing!
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_FOOTER =
+
+# The LATEX_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the LATEX_OUTPUT output
+# directory. Note that the files will be copied as-is; there are no commands or
+# markers available.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_EXTRA_FILES =
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated is
+# prepared for conversion to PDF (using ps2pdf or pdflatex). The PDF file will
+# contain links (just like the HTML output) instead of page references. This
+# makes the output suitable for online browsing using a PDF viewer.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+PDF_HYPERLINKS = YES
+
+# If the USE_PDFLATEX tag is set to YES, doxygen will use pdflatex to generate
+# the PDF file directly from the LaTeX files. Set this option to YES, to get a
+# higher quality PDF documentation.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+USE_PDFLATEX = YES
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \batchmode
+# command to the generated LaTeX files. This will instruct LaTeX to keep running
+# if errors occur, instead of asking the user for help. This option is also used
+# when generating formulas in HTML.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_BATCHMODE = NO
+
+# If the LATEX_HIDE_INDICES tag is set to YES then doxygen will not include the
+# index chapters (such as File Index, Compound Index, etc.) in the output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_HIDE_INDICES = NO
+
+# If the LATEX_SOURCE_CODE tag is set to YES then doxygen will include source
+# code with syntax highlighting in the LaTeX output.
+#
+# Note that which sources are shown also depends on other settings such as
+# SOURCE_BROWSER.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_SOURCE_CODE = NO
+
+# The LATEX_BIB_STYLE tag can be used to specify the style to use for the
+# bibliography, e.g. plainnat, or ieeetr. See
+# http://en.wikipedia.org/wiki/BibTeX and \cite for more info.
+# The default value is: plain.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_BIB_STYLE = plain
+
+#---------------------------------------------------------------------------
+# Configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES, doxygen will generate RTF output. The
+# RTF output is optimized for Word 97 and may not look too pretty with other RTF
+# readers/editors.
+# The default value is: NO.
+
+GENERATE_RTF = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: rtf.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_OUTPUT = rtf
+
+# If the COMPACT_RTF tag is set to YES, doxygen generates more compact RTF
+# documents. This may be useful for small projects and may help to save some
+# trees in general.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+COMPACT_RTF = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated will
+# contain hyperlink fields. The RTF file will contain links (just like the HTML
+# output) instead of page references. This makes the output suitable for online
+# browsing using Word or some other Word compatible readers that support those
+# fields.
+#
+# Note: WordPad (write) and others do not support links.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_HYPERLINKS = NO
+
+# Load stylesheet definitions from file. Syntax is similar to doxygen's config
+# file, i.e. a series of assignments. You only have to provide replacements,
+# missing definitions are set to their default value.
+#
+# See also section "Doxygen usage" for information on how to generate the
+# default style sheet that doxygen normally uses.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_STYLESHEET_FILE =
+
+# Set optional variables used in the generation of an RTF document. Syntax is
+# similar to doxygen's config file. A template extensions file can be generated
+# using doxygen -e rtf extensionFile.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_EXTENSIONS_FILE =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES, doxygen will generate man pages for
+# classes and files.
+# The default value is: NO.
+
+GENERATE_MAN = NO
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it. A directory man3 will be created inside the directory specified by
+# MAN_OUTPUT.
+# The default directory is: man.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_OUTPUT = man
+
+# The MAN_EXTENSION tag determines the extension that is added to the generated
+# man pages. In case the manual section does not start with a number, the number
+# 3 is prepended. The dot (.) at the beginning of the MAN_EXTENSION tag is
+# optional.
+# The default value is: .3.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_EXTENSION = .3
+
+# The MAN_SUBDIR tag determines the name of the directory created within
+# MAN_OUTPUT in which the man pages are placed. If defaults to man followed by
+# MAN_EXTENSION with the initial . removed.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_SUBDIR =
+
+# If the MAN_LINKS tag is set to YES and doxygen generates man output, then it
+# will generate one additional man file for each entity documented in the real
+# man page(s). These additional files only source the real man page, but without
+# them the man command would be unable to find the correct page.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_LINKS = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES, doxygen will generate an XML file that
+# captures the structure of the code including all documentation.
+# The default value is: NO.
+
+GENERATE_XML = YES
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: xml.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_OUTPUT = xml
+
+# If the XML_PROGRAMLISTING tag is set to YES, doxygen will dump the program
+# listings (including syntax highlighting and cross-referencing information) to
+# the XML output. Note that enabling this will significantly increase the size
+# of the XML output.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_PROGRAMLISTING = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the DOCBOOK output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_DOCBOOK tag is set to YES, doxygen will generate Docbook files
+# that can be used to generate PDF.
+# The default value is: NO.
+
+GENERATE_DOCBOOK = NO
+
+# The DOCBOOK_OUTPUT tag is used to specify where the Docbook pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be put in
+# front of it.
+# The default directory is: docbook.
+# This tag requires that the tag GENERATE_DOCBOOK is set to YES.
+
+DOCBOOK_OUTPUT = docbook
+
+# If the DOCBOOK_PROGRAMLISTING tag is set to YES, doxygen will include the
+# program listings (including syntax highlighting and cross-referencing
+# information) to the DOCBOOK output. Note that enabling this will significantly
+# increase the size of the DOCBOOK output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_DOCBOOK is set to YES.
+
+DOCBOOK_PROGRAMLISTING = NO
+
+#---------------------------------------------------------------------------
+# Configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES, doxygen will generate an
+# AutoGen Definitions (see http://autogen.sf.net) file that captures the
+# structure of the code including all documentation. Note that this feature is
+# still experimental and incomplete at the moment.
+# The default value is: NO.
+
+GENERATE_AUTOGEN_DEF = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES, doxygen will generate a Perl module
+# file that captures the structure of the code including all documentation.
+#
+# Note that this feature is still experimental and incomplete at the moment.
+# The default value is: NO.
+
+GENERATE_PERLMOD = NO
+
+# If the PERLMOD_LATEX tag is set to YES, doxygen will generate the necessary
+# Makefile rules, Perl scripts and LaTeX code to be able to generate PDF and DVI
+# output from the Perl module output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_LATEX = NO
+
+# If the PERLMOD_PRETTY tag is set to YES, the Perl module output will be nicely
+# formatted so it can be parsed by a human reader. This is useful if you want to
+# understand what is going on. On the other hand, if this tag is set to NO, the
+# size of the Perl module output will be much smaller and Perl will parse it
+# just the same.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_PRETTY = YES
+
+# The names of the make variables in the generated doxyrules.make file are
+# prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. This is useful
+# so different doxyrules.make files included by the same Makefile don't
+# overwrite each other's variables.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_MAKEVAR_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES, doxygen will evaluate all
+# C-preprocessor directives found in the sources and include files.
+# The default value is: YES.
+
+ENABLE_PREPROCESSING = YES
+
+# If the MACRO_EXPANSION tag is set to YES, doxygen will expand all macro names
+# in the source code. If set to NO, only conditional compilation will be
+# performed. Macro expansion can be done in a controlled way by setting
+# EXPAND_ONLY_PREDEF to YES.
+# The default value is: NO.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+MACRO_EXPANSION = NO
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES then
+# the macro expansion is limited to the macros specified with the PREDEFINED and
+# EXPAND_AS_DEFINED tags.
+# The default value is: NO.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+EXPAND_ONLY_PREDEF = NO
+
+# If the SEARCH_INCLUDES tag is set to YES, the include files in the
+# INCLUDE_PATH will be searched if a #include is found.
+# The default value is: YES.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+SEARCH_INCLUDES = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that
+# contain include files that are not input files but should be processed by the
+# preprocessor.
+# This tag requires that the tag SEARCH_INCLUDES is set to YES.
+
+INCLUDE_PATH =
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
+# patterns (like *.h and *.hpp) to filter out the header-files in the
+# directories. If left blank, the patterns specified with FILE_PATTERNS will be
+# used.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+INCLUDE_FILE_PATTERNS =
+
+# The PREDEFINED tag can be used to specify one or more macro names that are
+# defined before the preprocessor is started (similar to the -D option of e.g.
+# gcc). The argument of the tag is a list of macros of the form: name or
+# name=definition (no spaces). If the definition and the "=" are omitted, "=1"
+# is assumed. To prevent a macro definition from being undefined via #undef or
+# recursively expanded use the := operator instead of the = operator.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+PREDEFINED =
+
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this
+# tag can be used to specify a list of macro names that should be expanded. The
+# macro definition that is found in the sources will be used. Use the PREDEFINED
+# tag if you want to use a different macro definition that overrules the
+# definition found in the source code.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+EXPAND_AS_DEFINED =
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES then doxygen's preprocessor will
+# remove all references to function-like macros that are alone on a line, have
+# an all uppercase name, and do not end with a semicolon. Such function macros
+# are typically used for boiler-plate code, and will confuse the parser if not
+# removed.
+# The default value is: YES.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+SKIP_FUNCTION_MACROS = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to external references
+#---------------------------------------------------------------------------
+
+# The TAGFILES tag can be used to specify one or more tag files. For each tag
+# file the location of the external documentation should be added. The format of
+# a tag file without this location is as follows:
+# TAGFILES = file1 file2 ...
+# Adding location for the tag files is done as follows:
+# TAGFILES = file1=loc1 "file2 = loc2" ...
+# where loc1 and loc2 can be relative or absolute paths or URLs. See the
+# section "Linking to external documentation" for more information about the use
+# of tag files.
+# Note: Each tag file must have a unique name (where the name does NOT include
+# the path). If a tag file is not located in the directory in which doxygen is
+# run, you must also specify the path to the tagfile here.
+
+TAGFILES =
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create a
+# tag file that is based on the input files it reads. See section "Linking to
+# external documentation" for more information about the usage of tag files.
+
+GENERATE_TAGFILE =
+
+# If the ALLEXTERNALS tag is set to YES, all external class will be listed in
+# the class index. If set to NO, only the inherited external classes will be
+# listed.
+# The default value is: NO.
+
+ALLEXTERNALS = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES, all external groups will be listed
+# in the modules index. If set to NO, only the current project's groups will be
+# listed.
+# The default value is: YES.
+
+EXTERNAL_GROUPS = YES
+
+# If the EXTERNAL_PAGES tag is set to YES, all external pages will be listed in
+# the related pages index. If set to NO, only the current project's pages will
+# be listed.
+# The default value is: YES.
+
+EXTERNAL_PAGES = YES
+
+# The PERL_PATH should be the absolute path and name of the perl script
+# interpreter (i.e. the result of 'which perl').
+# The default file (with absolute path) is: /usr/bin/perl.
+
+PERL_PATH = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES, doxygen will generate a class diagram
+# (in HTML and LaTeX) for classes with base or super classes. Setting the tag to
+# NO turns the diagrams off. Note that this option also works with HAVE_DOT
+# disabled, but it is recommended to install and use dot, since it yields more
+# powerful graphs.
+# The default value is: YES.
+
+CLASS_DIAGRAMS = YES
+
+# You can define message sequence charts within doxygen comments using the \msc
+# command. Doxygen will then run the mscgen tool (see:
+# http://www.mcternan.me.uk/mscgen/)) to produce the chart and insert it in the
+# documentation. The MSCGEN_PATH tag allows you to specify the directory where
+# the mscgen tool resides. If left empty the tool is assumed to be found in the
+# default search path.
+
+MSCGEN_PATH =
+
+# You can include diagrams made with dia in doxygen documentation. Doxygen will
+# then run dia to produce the diagram and insert it in the documentation. The
+# DIA_PATH tag allows you to specify the directory where the dia binary resides.
+# If left empty dia is assumed to be found in the default search path.
+
+DIA_PATH =
+
+# If set to YES the inheritance and collaboration graphs will hide inheritance
+# and usage relations if the target is undocumented or is not a class.
+# The default value is: YES.
+
+HIDE_UNDOC_RELATIONS = YES
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
+# available from the path. This tool is part of Graphviz (see:
+# http://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent
+# Bell Labs. The other options in this section have no effect if this option is
+# set to NO
+# The default value is: NO.
+
+HAVE_DOT = NO
+
+# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is allowed
+# to run in parallel. When set to 0 doxygen will base this on the number of
+# processors available in the system. You can set it explicitly to a value
+# larger than 0 to get control over the balance between CPU load and processing
+# speed.
+# Minimum value: 0, maximum value: 32, default value: 0.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_NUM_THREADS = 0
+
+# When you want a differently looking font in the dot files that doxygen
+# generates you can specify the font name using DOT_FONTNAME. You need to make
+# sure dot is able to find the font, which can be done by putting it in a
+# standard location or by setting the DOTFONTPATH environment variable or by
+# setting DOT_FONTPATH to the directory containing the font.
+# The default value is: Helvetica.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTNAME = Helvetica
+
+# The DOT_FONTSIZE tag can be used to set the size (in points) of the font of
+# dot graphs.
+# Minimum value: 4, maximum value: 24, default value: 10.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTSIZE = 10
+
+# By default doxygen will tell dot to use the default font as specified with
+# DOT_FONTNAME. If you specify a different font using DOT_FONTNAME you can set
+# the path where dot can find it using this tag.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTPATH =
+
+# If the CLASS_GRAPH tag is set to YES then doxygen will generate a graph for
+# each documented class showing the direct and indirect inheritance relations.
+# Setting this tag to YES will force the CLASS_DIAGRAMS tag to NO.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CLASS_GRAPH = YES
+
+# If the COLLABORATION_GRAPH tag is set to YES then doxygen will generate a
+# graph for each documented class showing the direct and indirect implementation
+# dependencies (inheritance, containment, and class references variables) of the
+# class with other documented classes.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+COLLABORATION_GRAPH = YES
+
+# If the GROUP_GRAPHS tag is set to YES then doxygen will generate a graph for
+# groups, showing the direct groups dependencies.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GROUP_GRAPHS = YES
+
+# If the UML_LOOK tag is set to YES, doxygen will generate inheritance and
+# collaboration diagrams in a style similar to the OMG's Unified Modeling
+# Language.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+UML_LOOK = NO
+
+# If the UML_LOOK tag is enabled, the fields and methods are shown inside the
+# class node. If there are many fields or methods and many nodes the graph may
+# become too big to be useful. The UML_LIMIT_NUM_FIELDS threshold limits the
+# number of items for each type to make the size more manageable. Set this to 0
+# for no limit. Note that the threshold may be exceeded by 50% before the limit
+# is enforced. So when you set the threshold to 10, up to 15 fields may appear,
+# but if the number exceeds 15, the total amount of fields shown is limited to
+# 10.
+# Minimum value: 0, maximum value: 100, default value: 10.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+UML_LIMIT_NUM_FIELDS = 10
+
+# If the TEMPLATE_RELATIONS tag is set to YES then the inheritance and
+# collaboration graphs will show the relations between templates and their
+# instances.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+TEMPLATE_RELATIONS = NO
+
+# If the INCLUDE_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are set to
+# YES then doxygen will generate a graph for each documented file showing the
+# direct and indirect include dependencies of the file with other documented
+# files.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INCLUDE_GRAPH = YES
+
+# If the INCLUDED_BY_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are
+# set to YES then doxygen will generate a graph for each documented file showing
+# the direct and indirect include dependencies of the file with other documented
+# files.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INCLUDED_BY_GRAPH = YES
+
+# If the CALL_GRAPH tag is set to YES then doxygen will generate a call
+# dependency graph for every global function or class method.
+#
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable call graphs for selected
+# functions only using the \callgraph command.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CALL_GRAPH = NO
+
+# If the CALLER_GRAPH tag is set to YES then doxygen will generate a caller
+# dependency graph for every global function or class method.
+#
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable caller graphs for selected
+# functions only using the \callergraph command.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CALLER_GRAPH = NO
+
+# If the GRAPHICAL_HIERARCHY tag is set to YES then doxygen will graphical
+# hierarchy of all classes instead of a textual one.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GRAPHICAL_HIERARCHY = YES
+
+# If the DIRECTORY_GRAPH tag is set to YES then doxygen will show the
+# dependencies a directory has on other directories in a graphical way. The
+# dependency relations are determined by the #include relations between the
+# files in the directories.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DIRECTORY_GRAPH = YES
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
+# generated by dot.
+# Note: If you choose svg you need to set HTML_FILE_EXTENSION to xhtml in order
+# to make the SVG files visible in IE 9+ (other browsers do not have this
+# requirement).
+# Possible values are: png, jpg, gif and svg.
+# The default value is: png.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_IMAGE_FORMAT = png
+
+# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to
+# enable generation of interactive SVG images that allow zooming and panning.
+#
+# Note that this requires a modern browser other than Internet Explorer. Tested
+# and working are Firefox, Chrome, Safari, and Opera.
+# Note: For IE 9+ you need to set HTML_FILE_EXTENSION to xhtml in order to make
+# the SVG files visible. Older versions of IE do not have SVG support.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INTERACTIVE_SVG = NO
+
+# The DOT_PATH tag can be used to specify the path where the dot tool can be
+# found. If left blank, it is assumed the dot tool can be found in the path.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_PATH =
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that
+# contain dot files that are included in the documentation (see the \dotfile
+# command).
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOTFILE_DIRS =
+
+# The MSCFILE_DIRS tag can be used to specify one or more directories that
+# contain msc files that are included in the documentation (see the \mscfile
+# command).
+
+MSCFILE_DIRS =
+
+# The DIAFILE_DIRS tag can be used to specify one or more directories that
+# contain dia files that are included in the documentation (see the \diafile
+# command).
+
+DIAFILE_DIRS =
+
+# When using plantuml, the PLANTUML_JAR_PATH tag should be used to specify the
+# path where java can find the plantuml.jar file. If left blank, it is assumed
+# PlantUML is not used or called during a preprocessing step. Doxygen will
+# generate a warning when it encounters a \startuml command in this case and
+# will not generate output for the diagram.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+PLANTUML_JAR_PATH =
+
+# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of nodes
+# that will be shown in the graph. If the number of nodes in a graph becomes
+# larger than this value, doxygen will truncate the graph, which is visualized
+# by representing a node as a red box. Note that doxygen if the number of direct
+# children of the root node in a graph is already larger than
+# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note that
+# the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
+# Minimum value: 0, maximum value: 10000, default value: 50.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_GRAPH_MAX_NODES = 50
+
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the graphs
+# generated by dot. A depth value of 3 means that only nodes reachable from the
+# root by following a path via at most 3 edges will be shown. Nodes that lay
+# further from the root node will be omitted. Note that setting this option to 1
+# or 2 may greatly reduce the computation time needed for large code bases. Also
+# note that the size of a graph can be further restricted by
+# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
+# Minimum value: 0, maximum value: 1000, default value: 0.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+MAX_DOT_GRAPH_DEPTH = 0
+
+# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
+# background. This is disabled by default, because dot on Windows does not seem
+# to support this out of the box.
+#
+# Warning: Depending on the platform used, enabling this option may lead to
+# badly anti-aliased labels on the edges of a graph (i.e. they become hard to
+# read).
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_TRANSPARENT = NO
+
+# Set the DOT_MULTI_TARGETS tag to YES to allow dot to generate multiple output
+# files in one run (i.e. multiple -o and -T options on the command line). This
+# makes dot run faster, but since only newer versions of dot (>1.8.10) support
+# this, this feature is disabled by default.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_MULTI_TARGETS = NO
+
+# If the GENERATE_LEGEND tag is set to YES doxygen will generate a legend page
+# explaining the meaning of the various boxes and arrows in the dot generated
+# graphs.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GENERATE_LEGEND = YES
+
+# If the DOT_CLEANUP tag is set to YES, doxygen will remove the intermediate dot
+# files that are used to generate the various graphs.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_CLEANUP = YES
--- /dev/null
+This directory contains a dummy Java project for testing purposes.
+
+To regenerate the XML output located in `xml`, run `make`. If the `Makefile`
+does not exists, you can regenerate it by running `make bootstrap` in the parent
+directory.
--- /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.
+ */
+
+package org.example.foo;
+
+public abstract class A {
+ /**
+ * Does something...
+ */
+ public abstract boolean bar(int x, EmptyClass y);
+}
--- /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.
+ */
+
+package org.example.foo;
+
+public class B extends A implements C {
+ protected String qux = "quux";
+
+ public boolean bar(int x, EmptyClass y) {
+ return false;
+ }
+
+ /**
+ * Some overriden documentation.
+ */
+ public void baz() {}
+}
--- /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.
+ */
+
+package org.example.foo;
+
+/**
+ * An interface
+ */
+public interface C {
+ /**
+ * “Answer to the Ultimate Question of Life, the Universe, and Everything.“
+ */
+ public static final long THE_ANSWER = 42L;
+
+ /**
+ * A function with implicit modifiers.
+ */
+ void baz();
+}
--- /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.
+ */
+
+package org.example.foo;
+
+/**
+ * This class is empty and is only visible in this package.
+ */
+class EmptyClass {}
--- /dev/null
+<?xml version='1.0' encoding='UTF-8' standalone='no'?>
+<doxygen xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="compound.xsd" version="1.8.8">
+ <compounddef id="_a_8java" kind="file">
+ <compoundname>A.java</compoundname>
+ <innerclass refid="classorg_1_1example_1_1foo_1_1_a" prot="public">org::example::foo::A</innerclass>
+ <innernamespace refid="namespaceorg_1_1example_1_1foo">org::example::foo</innernamespace>
+ <briefdescription>
+ </briefdescription>
+ <detaileddescription>
+ </detaileddescription>
+ <location file="%SOURCE_DIRECTORY%/org/example/foo/A.java"/>
+ </compounddef>
+</doxygen>
--- /dev/null
+<?xml version='1.0' encoding='UTF-8' standalone='no'?>
+<doxygen xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="compound.xsd" version="1.8.8">
+ <compounddef id="_b_8java" kind="file">
+ <compoundname>B.java</compoundname>
+ <innerclass refid="classorg_1_1example_1_1foo_1_1_b" prot="public">org::example::foo::B</innerclass>
+ <innernamespace refid="namespaceorg_1_1example_1_1foo">org::example::foo</innernamespace>
+ <briefdescription>
+ </briefdescription>
+ <detaileddescription>
+ </detaileddescription>
+ <location file="%SOURCE_DIRECTORY%/org/example/foo/B.java"/>
+ </compounddef>
+</doxygen>
--- /dev/null
+<?xml version='1.0' encoding='UTF-8' standalone='no'?>
+<doxygen xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="compound.xsd" version="1.8.8">
+ <compounddef id="_c_8java" kind="file">
+ <compoundname>C.java</compoundname>
+ <innerclass refid="interfaceorg_1_1example_1_1foo_1_1_c" prot="public">org::example::foo::C</innerclass>
+ <innernamespace refid="namespaceorg_1_1example_1_1foo">org::example::foo</innernamespace>
+ <briefdescription>
+ </briefdescription>
+ <detaileddescription>
+ </detaileddescription>
+ <location file="%SOURCE_DIRECTORY%/org/example/foo/C.java"/>
+ </compounddef>
+</doxygen>
--- /dev/null
+<?xml version='1.0' encoding='UTF-8' standalone='no'?>
+<doxygen xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="compound.xsd" version="1.8.8">
+ <compounddef id="_empty_class_8java" kind="file">
+ <compoundname>EmptyClass.java</compoundname>
+ <innerclass refid="classorg_1_1example_1_1foo_1_1_empty_class" prot="package">org::example::foo::EmptyClass</innerclass>
+ <innernamespace refid="namespaceorg_1_1example_1_1foo">org::example::foo</innernamespace>
+ <briefdescription>
+ </briefdescription>
+ <detaileddescription>
+ </detaileddescription>
+ <location file="%SOURCE_DIRECTORY%/org/example/foo/EmptyClass.java"/>
+ </compounddef>
+</doxygen>
--- /dev/null
+<?xml version='1.0' encoding='UTF-8' standalone='no'?>
+<doxygen xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="compound.xsd" version="1.8.8">
+ <compounddef id="classorg_1_1example_1_1foo_1_1_a" kind="class" prot="public" abstract="yes">
+ <compoundname>org::example::foo::A</compoundname>
+ <derivedcompoundref refid="classorg_1_1example_1_1foo_1_1_b" prot="public" virt="non-virtual">org.example.foo.B</derivedcompoundref>
+ <sectiondef kind="public-func">
+ <memberdef kind="function" id="classorg_1_1example_1_1foo_1_1_a_1add415ae4129969055d678c7e7e048852" prot="public" static="no" const="no" explicit="no" inline="no" virt="non-virtual">
+ <type>abstract boolean</type>
+ <definition>abstract boolean org.example.foo.A.bar</definition>
+ <argsstring>(int x, EmptyClass y)</argsstring>
+ <name>bar</name>
+ <param>
+ <type>int</type>
+ <declname>x</declname>
+ </param>
+ <param>
+ <type>EmptyClass</type>
+ <declname>y</declname>
+ </param>
+ <briefdescription>
+ </briefdescription>
+ <detaileddescription>
+<para>Does something... </para> </detaileddescription>
+ <inbodydescription>
+ </inbodydescription>
+ <location file="%SOURCE_DIRECTORY%/org/example/foo/A.java" line="22" column="1"/>
+ </memberdef>
+ </sectiondef>
+ <briefdescription>
+ </briefdescription>
+ <detaileddescription>
+ </detaileddescription>
+ <inheritancegraph>
+ <node id="0">
+ <label>org.example.foo.A</label>
+ <link refid="classorg_1_1example_1_1foo_1_1_a"/>
+ </node>
+ <node id="1">
+ <label>org.example.foo.B</label>
+ <link refid="classorg_1_1example_1_1foo_1_1_b"/>
+ <childnode refid="0" relation="public-inheritance">
+ </childnode>
+ </node>
+ </inheritancegraph>
+ <location file="%SOURCE_DIRECTORY%/org/example/foo/A.java" line="18" column="1" bodyfile="%SOURCE_DIRECTORY%/org/example/foo/A.java" bodystart="18" bodyend="23"/>
+ <listofallmembers>
+ <member refid="classorg_1_1example_1_1foo_1_1_a_1add415ae4129969055d678c7e7e048852" prot="public" virt="non-virtual"><scope>org::example::foo::A</scope><name>bar</name></member>
+ </listofallmembers>
+ </compounddef>
+</doxygen>
--- /dev/null
+<?xml version='1.0' encoding='UTF-8' standalone='no'?>
+<doxygen xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="compound.xsd" version="1.8.8">
+ <compounddef id="classorg_1_1example_1_1foo_1_1_b" kind="class" prot="public">
+ <compoundname>org::example::foo::B</compoundname>
+ <basecompoundref refid="classorg_1_1example_1_1foo_1_1_a" prot="public" virt="non-virtual">org.example.foo.A</basecompoundref>
+ <basecompoundref refid="interfaceorg_1_1example_1_1foo_1_1_c" prot="public" virt="non-virtual">org.example.foo.C</basecompoundref>
+ <sectiondef kind="protected-attrib">
+ <memberdef kind="variable" id="classorg_1_1example_1_1foo_1_1_b_1ac6b627949b10b9357eefc0cafcae1d87" prot="protected" static="no" mutable="no">
+ <type>String</type>
+ <definition>String org.example.foo.B.qux</definition>
+ <argsstring></argsstring>
+ <name>qux</name>
+ <initializer>= "quux"</initializer>
+ <briefdescription>
+ </briefdescription>
+ <detaileddescription>
+ </detaileddescription>
+ <inbodydescription>
+ </inbodydescription>
+ <location file="%SOURCE_DIRECTORY%/org/example/foo/B.java" line="19" column="1" bodyfile="%SOURCE_DIRECTORY%/org/example/foo/B.java" bodystart="19" bodyend="-1"/>
+ </memberdef>
+ </sectiondef>
+ <sectiondef kind="public-func">
+ <memberdef kind="function" id="classorg_1_1example_1_1foo_1_1_b_1a11e157943665cc9e3a9be1502ebeb3b5" prot="public" static="no" const="no" explicit="no" inline="yes" virt="non-virtual">
+ <type>boolean</type>
+ <definition>boolean org.example.foo.B.bar</definition>
+ <argsstring>(int x, EmptyClass y)</argsstring>
+ <name>bar</name>
+ <param>
+ <type>int</type>
+ <declname>x</declname>
+ </param>
+ <param>
+ <type>EmptyClass</type>
+ <declname>y</declname>
+ </param>
+ <briefdescription>
+ </briefdescription>
+ <detaileddescription>
+ </detaileddescription>
+ <inbodydescription>
+ </inbodydescription>
+ <location file="%SOURCE_DIRECTORY%/org/example/foo/B.java" line="21" column="1" bodyfile="%SOURCE_DIRECTORY%/org/example/foo/B.java" bodystart="21" bodyend="23"/>
+ </memberdef>
+ <memberdef kind="function" id="classorg_1_1example_1_1foo_1_1_b_1a733f4e076f29c7d0c41ed258199ea1d9" prot="public" static="no" const="no" explicit="no" inline="yes" virt="non-virtual">
+ <type>void</type>
+ <definition>void org.example.foo.B.baz</definition>
+ <argsstring>()</argsstring>
+ <name>baz</name>
+ <reimplements refid="interfaceorg_1_1example_1_1foo_1_1_c_1a28ac7ce349ebb3e4a7747a8dd951582b">baz</reimplements>
+ <briefdescription>
+ </briefdescription>
+ <detaileddescription>
+<para>Some overriden documentation. </para> </detaileddescription>
+ <inbodydescription>
+ </inbodydescription>
+ <location file="%SOURCE_DIRECTORY%/org/example/foo/B.java" line="28" column="1" bodyfile="%SOURCE_DIRECTORY%/org/example/foo/B.java" bodystart="28" bodyend="28"/>
+ </memberdef>
+ </sectiondef>
+ <briefdescription>
+ </briefdescription>
+ <detaileddescription>
+ </detaileddescription>
+ <inheritancegraph>
+ <node id="4">
+ <label>org.example.foo.A</label>
+ <link refid="classorg_1_1example_1_1foo_1_1_a"/>
+ </node>
+ <node id="3">
+ <label>org.example.foo.B</label>
+ <link refid="classorg_1_1example_1_1foo_1_1_b"/>
+ <childnode refid="4" relation="public-inheritance">
+ </childnode>
+ <childnode refid="5" relation="public-inheritance">
+ </childnode>
+ </node>
+ <node id="5">
+ <label>org.example.foo.C</label>
+ <link refid="interfaceorg_1_1example_1_1foo_1_1_c"/>
+ </node>
+ </inheritancegraph>
+ <collaborationgraph>
+ <node id="7">
+ <label>org.example.foo.A</label>
+ <link refid="classorg_1_1example_1_1foo_1_1_a"/>
+ </node>
+ <node id="6">
+ <label>org.example.foo.B</label>
+ <link refid="classorg_1_1example_1_1foo_1_1_b"/>
+ <childnode refid="7" relation="public-inheritance">
+ </childnode>
+ <childnode refid="8" relation="public-inheritance">
+ </childnode>
+ </node>
+ <node id="8">
+ <label>org.example.foo.C</label>
+ <link refid="interfaceorg_1_1example_1_1foo_1_1_c"/>
+ </node>
+ </collaborationgraph>
+ <location file="%SOURCE_DIRECTORY%/org/example/foo/B.java" line="18" column="1" bodyfile="%SOURCE_DIRECTORY%/org/example/foo/B.java" bodystart="18" bodyend="29"/>
+ <listofallmembers>
+ <member refid="classorg_1_1example_1_1foo_1_1_b_1a11e157943665cc9e3a9be1502ebeb3b5" prot="public" virt="non-virtual"><scope>org::example::foo::B</scope><name>bar</name></member>
+ <member refid="classorg_1_1example_1_1foo_1_1_b_1a733f4e076f29c7d0c41ed258199ea1d9" prot="public" virt="non-virtual"><scope>org::example::foo::B</scope><name>baz</name></member>
+ <member refid="classorg_1_1example_1_1foo_1_1_b_1ac6b627949b10b9357eefc0cafcae1d87" prot="protected" virt="non-virtual"><scope>org::example::foo::B</scope><name>qux</name></member>
+ <member refid="interfaceorg_1_1example_1_1foo_1_1_c_1a4e97061eb40b045e820de05b33c43d21" prot="public" virt="non-virtual"><scope>org::example::foo::B</scope><name>THE_ANSWER</name></member>
+ </listofallmembers>
+ </compounddef>
+</doxygen>
--- /dev/null
+<?xml version='1.0' encoding='UTF-8' standalone='no'?>
+<doxygen xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="compound.xsd" version="1.8.8">
+ <compounddef id="classorg_1_1example_1_1foo_1_1_empty_class" kind="class" prot="package">
+ <compoundname>org::example::foo::EmptyClass</compoundname>
+ <briefdescription>
+ </briefdescription>
+ <detaileddescription>
+<para>This class is empty and is only visible in this package. </para> </detaileddescription>
+ <location file="%SOURCE_DIRECTORY%/org/example/foo/EmptyClass.java" line="21" column="1" bodyfile="%SOURCE_DIRECTORY%/org/example/foo/EmptyClass.java" bodystart="21" bodyend="21"/>
+ <listofallmembers>
+ </listofallmembers>
+ </compounddef>
+</doxygen>
--- /dev/null
+<!-- XSLT script to combine the generated output into a single file.
+ If you have xsltproc you could use:
+ xsltproc combine.xslt index.xml >all.xml
+-->
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
+ <xsl:output method="xml" version="1.0" indent="no" standalone="yes" />
+ <xsl:template match="/">
+ <doxygen version="{doxygenindex/@version}">
+ <!-- Load all doxgen generated xml files -->
+ <xsl:for-each select="doxygenindex/compound">
+ <xsl:copy-of select="document( concat( @refid, '.xml' ) )/doxygen/*" />
+ </xsl:for-each>
+ </doxygen>
+ </xsl:template>
+</xsl:stylesheet>
--- /dev/null
+<?xml version='1.0' encoding='utf-8' ?>
+<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
+ <xsd:element name="doxygen" type="DoxygenType"/>
+
+ <!-- Complex types -->
+
+ <xsd:complexType name="DoxygenType">
+ <xsd:sequence maxOccurs="unbounded">
+ <xsd:element name="compounddef" type="compounddefType" minOccurs="0" />
+ </xsd:sequence>
+ <xsd:attribute name="version" type="DoxVersionNumber" use="required" />
+ </xsd:complexType>
+
+ <xsd:complexType name="compounddefType">
+ <xsd:sequence>
+ <xsd:element name="compoundname" type="xsd:string"/>
+ <xsd:element name="title" type="xsd:string" minOccurs="0" />
+ <xsd:element name="basecompoundref" type="compoundRefType" minOccurs="0" maxOccurs="unbounded" />
+ <xsd:element name="derivedcompoundref" type="compoundRefType" minOccurs="0" maxOccurs="unbounded" />
+ <xsd:element name="includes" type="incType" minOccurs="0" maxOccurs="unbounded" />
+ <xsd:element name="includedby" type="incType" minOccurs="0" maxOccurs="unbounded" />
+ <xsd:element name="incdepgraph" type="graphType" minOccurs="0" />
+ <xsd:element name="invincdepgraph" type="graphType" minOccurs="0" />
+ <xsd:element name="innerdir" type="refType" minOccurs="0" maxOccurs="unbounded" />
+ <xsd:element name="innerfile" type="refType" minOccurs="0" maxOccurs="unbounded" />
+ <xsd:element name="innerclass" type="refType" minOccurs="0" maxOccurs="unbounded" />
+ <xsd:element name="innernamespace" type="refType" minOccurs="0" maxOccurs="unbounded" />
+ <xsd:element name="innerpage" type="refType" minOccurs="0" maxOccurs="unbounded" />
+ <xsd:element name="innergroup" type="refType" minOccurs="0" maxOccurs="unbounded" />
+ <xsd:element name="templateparamlist" type="templateparamlistType" minOccurs="0" />
+ <xsd:element name="sectiondef" type="sectiondefType" minOccurs="0" maxOccurs="unbounded" />
+ <xsd:element name="briefdescription" type="descriptionType" minOccurs="0" />
+ <xsd:element name="detaileddescription" type="descriptionType" minOccurs="0" />
+ <xsd:element name="inheritancegraph" type="graphType" minOccurs="0" />
+ <xsd:element name="collaborationgraph" type="graphType" minOccurs="0" />
+ <xsd:element name="programlisting" type="listingType" minOccurs="0" />
+ <xsd:element name="location" type="locationType" minOccurs="0" />
+ <xsd:element name="listofallmembers" type="listofallmembersType" minOccurs="0" />
+ </xsd:sequence>
+ <xsd:attribute name="id" type="xsd:string" />
+ <xsd:attribute name="kind" type="DoxCompoundKind" />
+ <xsd:attribute name="prot" type="DoxProtectionKind" />
+ <xsd:attribute name="final" type="DoxBool" use="optional"/>
+ <xsd:attribute name="sealed" type="DoxBool" use="optional"/>
+ <xsd:attribute name="abstract" type="DoxBool" use="optional"/>
+ </xsd:complexType>
+
+ <xsd:complexType name="listofallmembersType">
+ <xsd:sequence>
+ <xsd:element name="member" type="memberRefType" minOccurs="0" maxOccurs="unbounded" />
+ </xsd:sequence>
+ </xsd:complexType>
+
+ <xsd:complexType name="memberRefType">
+ <xsd:sequence>
+ <xsd:element name="scope" />
+ <xsd:element name="name" />
+ </xsd:sequence>
+ <xsd:attribute name="refid" type="xsd:string" />
+ <xsd:attribute name="prot" type="DoxProtectionKind" />
+ <xsd:attribute name="virt" type="DoxVirtualKind" />
+ <xsd:attribute name="ambiguityscope" type="xsd:string" />
+ </xsd:complexType>
+
+ <xsd:complexType name="compoundRefType">
+ <xsd:simpleContent>
+ <xsd:extension base="xsd:string">
+ <xsd:attribute name="refid" type="xsd:string" use="optional" />
+ <xsd:attribute name="prot" type="DoxProtectionKind" />
+ <xsd:attribute name="virt" type="DoxVirtualKind" />
+ </xsd:extension>
+ </xsd:simpleContent>
+ </xsd:complexType>
+
+ <xsd:complexType name="reimplementType">
+ <xsd:simpleContent>
+ <xsd:extension base="xsd:string">
+ <xsd:attribute name="refid" type="xsd:string" />
+ </xsd:extension>
+ </xsd:simpleContent>
+ </xsd:complexType>
+
+ <xsd:complexType name="incType">
+ <xsd:simpleContent>
+ <xsd:extension base="xsd:string">
+ <xsd:attribute name="refid" type="xsd:string" />
+ <xsd:attribute name="local" type="DoxBool" />
+ </xsd:extension>
+ </xsd:simpleContent>
+ </xsd:complexType>
+
+ <xsd:complexType name="refType">
+ <xsd:simpleContent>
+ <xsd:extension base="xsd:string">
+ <xsd:attribute name="refid" type="xsd:string" />
+ <xsd:attribute name="prot" type="DoxProtectionKind" use="optional"/>
+ </xsd:extension>
+ </xsd:simpleContent>
+ </xsd:complexType>
+
+ <xsd:complexType name="refTextType">
+ <xsd:simpleContent>
+ <xsd:extension base="xsd:string">
+ <xsd:attribute name="refid" type="xsd:string" />
+ <xsd:attribute name="kindref" type="DoxRefKind" />
+ <xsd:attribute name="external" type="xsd:string" use="optional"/>
+ <xsd:attribute name="tooltip" type="xsd:string" use="optional"/>
+ </xsd:extension>
+ </xsd:simpleContent>
+ </xsd:complexType>
+
+ <xsd:complexType name="sectiondefType">
+ <xsd:sequence>
+ <xsd:element name="header" type="xsd:string" minOccurs="0" />
+ <xsd:element name="description" type="descriptionType" minOccurs="0" />
+ <xsd:element name="memberdef" type="memberdefType" maxOccurs="unbounded" />
+ </xsd:sequence>
+ <xsd:attribute name="kind" type="DoxSectionKind" />
+ </xsd:complexType>
+
+ <xsd:complexType name="memberdefType">
+ <xsd:sequence>
+ <xsd:element name="templateparamlist" type="templateparamlistType" minOccurs="0" />
+ <xsd:element name="type" type="linkedTextType" minOccurs="0" />
+ <xsd:element name="definition" minOccurs="0" />
+ <xsd:element name="argsstring" minOccurs="0" />
+ <xsd:element name="name" />
+ <xsd:element name="read" minOccurs="0" />
+ <xsd:element name="write" minOccurs="0" />
+ <xsd:element name="bitfield" minOccurs="0" />
+ <xsd:element name="reimplements" type="reimplementType" minOccurs="0" maxOccurs="unbounded" />
+ <xsd:element name="reimplementedby" type="reimplementType" minOccurs="0" maxOccurs="unbounded" />
+ <xsd:element name="param" type="paramType" minOccurs="0" maxOccurs="unbounded" />
+ <xsd:element name="enumvalue" type="enumvalueType" minOccurs="0" maxOccurs="unbounded" />
+ <xsd:element name="initializer" type="linkedTextType" minOccurs="0" />
+ <xsd:element name="exceptions" type="linkedTextType" minOccurs="0" />
+ <xsd:element name="briefdescription" type="descriptionType" minOccurs="0" />
+ <xsd:element name="detaileddescription" type="descriptionType" minOccurs="0" />
+ <xsd:element name="inbodydescription" type="descriptionType" minOccurs="0" />
+ <xsd:element name="location" type="locationType" />
+ <xsd:element name="references" type="referenceType" minOccurs="0" maxOccurs="unbounded" />
+ <xsd:element name="referencedby" type="referenceType" minOccurs="0" maxOccurs="unbounded" />
+ </xsd:sequence>
+ <xsd:attribute name="kind" type="DoxMemberKind" />
+ <xsd:attribute name="id" type="xsd:string" />
+ <xsd:attribute name="prot" type="DoxProtectionKind" />
+ <xsd:attribute name="static" type="DoxBool" />
+ <xsd:attribute name="const" type="DoxBool" use="optional"/>
+ <xsd:attribute name="explicit" type="DoxBool" use="optional"/>
+ <xsd:attribute name="inline" type="DoxBool" use="optional"/>
+ <xsd:attribute name="virt" type="DoxVirtualKind" use="optional"/>
+ <xsd:attribute name="volatile" type="DoxBool" use="optional"/>
+ <xsd:attribute name="mutable" type="DoxBool" use="optional"/>
+ <!-- Qt property -->
+ <xsd:attribute name="readable" type="DoxBool" use="optional"/>
+ <xsd:attribute name="writable" type="DoxBool" use="optional"/>
+ <!-- C++/CLI variable -->
+ <xsd:attribute name="initonly" type="DoxBool" use="optional"/>
+ <!-- C++/CLI and C# property -->
+ <xsd:attribute name="settable" type="DoxBool" use="optional"/>
+ <xsd:attribute name="gettable" type="DoxBool" use="optional"/>
+ <!-- C++/CLI function -->
+ <xsd:attribute name="final" type="DoxBool" use="optional"/>
+ <xsd:attribute name="sealed" type="DoxBool" use="optional"/>
+ <xsd:attribute name="new" type="DoxBool" use="optional"/>
+ <!-- C++/CLI event -->
+ <xsd:attribute name="add" type="DoxBool" use="optional"/>
+ <xsd:attribute name="remove" type="DoxBool" use="optional"/>
+ <xsd:attribute name="raise" type="DoxBool" use="optional"/>
+ <!-- Objective-C 2.0 protocol method -->
+ <xsd:attribute name="optional" type="DoxBool" use="optional"/>
+ <xsd:attribute name="required" type="DoxBool" use="optional"/>
+ <!-- Objective-C 2.0 property accessor -->
+ <xsd:attribute name="accessor" type="DoxAccessor" use="optional"/>
+ <!-- UNO IDL -->
+ <xsd:attribute name="attribute" type="DoxBool" use="optional"/>
+ <xsd:attribute name="property" type="DoxBool" use="optional"/>
+ <xsd:attribute name="readonly" type="DoxBool" use="optional"/>
+ <xsd:attribute name="bound" type="DoxBool" use="optional"/>
+ <xsd:attribute name="removable" type="DoxBool" use="optional"/>
+ <xsd:attribute name="contrained" type="DoxBool" use="optional"/>
+ <xsd:attribute name="transient" type="DoxBool" use="optional"/>
+ <xsd:attribute name="maybevoid" type="DoxBool" use="optional"/>
+ <xsd:attribute name="maybedefault" type="DoxBool" use="optional"/>
+ <xsd:attribute name="maybeambiguous" type="DoxBool" use="optional"/>
+
+ </xsd:complexType>
+
+ <xsd:complexType name="descriptionType" mixed="true">
+ <xsd:sequence>
+ <xsd:element name="title" type="xsd:string" minOccurs="0"/>
+ <xsd:element name="para" type="docParaType" minOccurs="0" maxOccurs="unbounded" />
+ <xsd:element name="sect1" type="docSect1Type" minOccurs="0" maxOccurs="unbounded" />
+ <xsd:element name="internal" type="docInternalType" minOccurs="0" />
+ </xsd:sequence>
+ </xsd:complexType>
+
+ <xsd:complexType name="enumvalueType" mixed="true">
+ <xsd:sequence>
+ <xsd:element name="name" />
+ <xsd:element name="initializer" type="linkedTextType" minOccurs="0" />
+ <xsd:element name="briefdescription" type="descriptionType" minOccurs="0" />
+ <xsd:element name="detaileddescription" type="descriptionType" minOccurs="0" />
+ </xsd:sequence>
+ <xsd:attribute name="id" type="xsd:string" />
+ <xsd:attribute name="prot" type="DoxProtectionKind" />
+ </xsd:complexType>
+
+ <xsd:complexType name="templateparamlistType">
+ <xsd:sequence>
+ <xsd:element name="param" type="paramType" minOccurs="0" maxOccurs="unbounded" />
+ </xsd:sequence>
+ </xsd:complexType>
+
+ <xsd:complexType name="paramType">
+ <xsd:sequence>
+ <xsd:element name="type" type="linkedTextType" minOccurs="0" />
+ <xsd:element name="declname" minOccurs="0" />
+ <xsd:element name="defname" minOccurs="0" />
+ <xsd:element name="array" minOccurs="0" />
+ <xsd:element name="defval" type="linkedTextType" minOccurs="0" />
+ <xsd:element name="briefdescription" type="descriptionType" minOccurs="0" />
+ </xsd:sequence>
+ </xsd:complexType>
+
+ <xsd:complexType name="linkedTextType" mixed="true">
+ <xsd:sequence>
+ <xsd:element name="ref" type="refTextType" minOccurs="0" maxOccurs="unbounded" />
+ </xsd:sequence>
+ </xsd:complexType>
+
+ <xsd:complexType name="graphType">
+ <xsd:sequence>
+ <xsd:element name="node" type="nodeType" maxOccurs="unbounded" />
+ </xsd:sequence>
+ </xsd:complexType>
+
+ <xsd:complexType name="nodeType">
+ <xsd:sequence>
+ <xsd:element name="label" />
+ <xsd:element name="link" type="linkType" minOccurs="0" />
+ <xsd:element name="childnode" type="childnodeType" minOccurs="0" maxOccurs="unbounded" />
+ </xsd:sequence>
+ <xsd:attribute name="id" type="xsd:string" />
+ </xsd:complexType>
+
+ <xsd:complexType name="childnodeType">
+ <xsd:sequence>
+ <xsd:element name="edgelabel" minOccurs="0" maxOccurs="unbounded"/>
+ </xsd:sequence>
+ <xsd:attribute name="refid" type="xsd:string" />
+ <xsd:attribute name="relation" type="DoxGraphRelation" />
+ </xsd:complexType>
+
+ <xsd:complexType name="linkType">
+ <xsd:attribute name="refid" type="xsd:string" />
+ <xsd:attribute name="external" type="xsd:string" use="optional"/>
+ </xsd:complexType>
+
+ <xsd:complexType name="listingType">
+ <xsd:sequence>
+ <xsd:element name="codeline" type="codelineType" minOccurs="0" maxOccurs="unbounded" />
+ </xsd:sequence>
+ </xsd:complexType>
+
+ <xsd:complexType name="codelineType">
+ <xsd:sequence>
+ <xsd:element name="highlight" type="highlightType" minOccurs="0" maxOccurs="unbounded" />
+ </xsd:sequence>
+ <xsd:attribute name="lineno" type="xsd:integer" />
+ <xsd:attribute name="refid" type="xsd:string" />
+ <xsd:attribute name="refkind" type="DoxRefKind" />
+ <xsd:attribute name="external" type="DoxBool" />
+ </xsd:complexType>
+
+ <xsd:complexType name="highlightType" mixed="true">
+ <xsd:choice minOccurs="0" maxOccurs="unbounded">
+ <xsd:element name="sp" />
+ <xsd:element name="ref" type="refTextType" />
+ </xsd:choice>
+ <xsd:attribute name="class" type="DoxHighlightClass" />
+ </xsd:complexType>
+
+ <xsd:complexType name="referenceType" mixed="true">
+ <xsd:attribute name="refid" type="xsd:string" />
+ <xsd:attribute name="compoundref" type="xsd:string" use="optional" />
+ <xsd:attribute name="startline" type="xsd:integer" />
+ <xsd:attribute name="endline" type="xsd:integer" />
+ </xsd:complexType>
+
+ <xsd:complexType name="locationType">
+ <xsd:attribute name="file" type="xsd:string" />
+ <xsd:attribute name="line" type="xsd:integer" />
+ <xsd:attribute name="column" type="xsd:integer" use="optional"/>
+ <xsd:attribute name="bodyfile" type="xsd:string" />
+ <xsd:attribute name="bodystart" type="xsd:integer" />
+ <xsd:attribute name="bodyend" type="xsd:integer" />
+ </xsd:complexType>
+
+ <xsd:complexType name="docSect1Type" mixed="true">
+ <xsd:sequence>
+ <xsd:element name="title" type="xsd:string" />
+ <xsd:element name="para" type="docParaType" minOccurs="0" maxOccurs="unbounded" />
+ <xsd:element name="sect2" type="docSect2Type" minOccurs="0" maxOccurs="unbounded" />
+ <xsd:element name="internal" type="docInternalS1Type" minOccurs="0" />
+ </xsd:sequence>
+ <xsd:attribute name="id" type="xsd:string" />
+ </xsd:complexType>
+
+ <xsd:complexType name="docSect2Type" mixed="true">
+ <xsd:sequence>
+ <xsd:element name="title" type="xsd:string" />
+ <xsd:element name="para" type="docParaType" minOccurs="0" maxOccurs="unbounded" />
+ <xsd:element name="sect3" type="docSect3Type" minOccurs="0" maxOccurs="unbounded" />
+ <xsd:element name="internal" type="docInternalS2Type" minOccurs="0" />
+ </xsd:sequence>
+ <xsd:attribute name="id" type="xsd:string" />
+ </xsd:complexType>
+
+ <xsd:complexType name="docSect3Type" mixed="true">
+ <xsd:sequence>
+ <xsd:element name="title" type="xsd:string" />
+ <xsd:element name="para" type="docParaType" minOccurs="0" maxOccurs="unbounded" />
+ <xsd:element name="sect4" type="docSect4Type" minOccurs="0" maxOccurs="unbounded" />
+ <xsd:element name="internal" type="docInternalS3Type" minOccurs="0" />
+ </xsd:sequence>
+ <xsd:attribute name="id" type="xsd:string" />
+ </xsd:complexType>
+
+ <xsd:complexType name="docSect4Type" mixed="true">
+ <xsd:sequence>
+ <xsd:element name="title" type="xsd:string" />
+ <xsd:element name="para" type="docParaType" minOccurs="0" maxOccurs="unbounded" />
+ <xsd:element name="internal" type="docInternalS4Type" minOccurs="0" />
+ </xsd:sequence>
+ <xsd:attribute name="id" type="xsd:string" />
+ </xsd:complexType>
+
+ <xsd:complexType name="docInternalType" mixed="true">
+ <xsd:sequence>
+ <xsd:element name="para" type="docParaType" minOccurs="0" maxOccurs="unbounded" />
+ <xsd:element name="sect1" type="docSect1Type" minOccurs="0" maxOccurs="unbounded" />
+ </xsd:sequence>
+ </xsd:complexType>
+
+ <xsd:complexType name="docInternalS1Type" mixed="true">
+ <xsd:sequence>
+ <xsd:element name="para" type="docParaType" minOccurs="0" maxOccurs="unbounded" />
+ <xsd:element name="sect2" type="docSect2Type" minOccurs="0" maxOccurs="unbounded" />
+ </xsd:sequence>
+ </xsd:complexType>
+
+ <xsd:complexType name="docInternalS2Type" mixed="true">
+ <xsd:sequence>
+ <xsd:element name="para" type="docParaType" minOccurs="0" maxOccurs="unbounded" />
+ <xsd:element name="sect3" type="docSect3Type" minOccurs="0" maxOccurs="unbounded" />
+ </xsd:sequence>
+ </xsd:complexType>
+
+ <xsd:complexType name="docInternalS3Type" mixed="true">
+ <xsd:sequence>
+ <xsd:element name="para" type="docParaType" minOccurs="0" maxOccurs="unbounded" />
+ <xsd:element name="sect3" type="docSect4Type" minOccurs="0" maxOccurs="unbounded" />
+ </xsd:sequence>
+ </xsd:complexType>
+
+ <xsd:complexType name="docInternalS4Type" mixed="true">
+ <xsd:sequence>
+ <xsd:element name="para" type="docParaType" minOccurs="0" maxOccurs="unbounded" />
+ </xsd:sequence>
+ </xsd:complexType>
+
+ <xsd:group name="docTitleCmdGroup">
+ <xsd:choice>
+ <xsd:element name="ulink" type="docURLLink" />
+ <xsd:element name="bold" type="docMarkupType" />
+ <xsd:element name="emphasis" type="docMarkupType" />
+ <xsd:element name="computeroutput" type="docMarkupType" />
+ <xsd:element name="subscript" type="docMarkupType" />
+ <xsd:element name="superscript" type="docMarkupType" />
+ <xsd:element name="center" type="docMarkupType" />
+ <xsd:element name="small" type="docMarkupType" />
+ <xsd:element name="htmlonly" type="xsd:string" />
+ <xsd:element name="manonly" type="xsd:string" />
+ <xsd:element name="xmlonly" type="xsd:string" />
+ <xsd:element name="rtfonly" type="xsd:string" />
+ <xsd:element name="latexonly" type="xsd:string" />
+ <xsd:element name="dot" type="xsd:string" />
+ <xsd:element name="plantuml" type="xsd:string" />
+ <xsd:element name="anchor" type="docAnchorType" />
+ <xsd:element name="formula" type="docFormulaType" />
+ <xsd:element name="ref" type="docRefTextType" />
+ <xsd:element name="nonbreakablespace" type="docEmptyType" />
+ <xsd:element name="iexcl" type="docEmptyType" />
+ <xsd:element name="cent" type="docEmptyType" />
+ <xsd:element name="pound" type="docEmptyType" />
+ <xsd:element name="curren" type="docEmptyType" />
+ <xsd:element name="yen" type="docEmptyType" />
+ <xsd:element name="brvbar" type="docEmptyType" />
+ <xsd:element name="sect" type="docEmptyType" />
+ <xsd:element name="umlaut" type="docEmptyType" />
+ <xsd:element name="copy" type="docEmptyType" />
+ <xsd:element name="ordf" type="docEmptyType" />
+ <xsd:element name="laquo" type="docEmptyType" />
+ <xsd:element name="not" type="docEmptyType" />
+ <xsd:element name="shy" type="docEmptyType" />
+ <xsd:element name="registered" type="docEmptyType" />
+ <xsd:element name="macr" type="docEmptyType" />
+ <xsd:element name="deg" type="docEmptyType" />
+ <xsd:element name="plusmn" type="docEmptyType" />
+ <xsd:element name="sup2" type="docEmptyType" />
+ <xsd:element name="sup3" type="docEmptyType" />
+ <xsd:element name="acute" type="docEmptyType" />
+ <xsd:element name="micro" type="docEmptyType" />
+ <xsd:element name="para" type="docEmptyType" />
+ <xsd:element name="middot" type="docEmptyType" />
+ <xsd:element name="cedil" type="docEmptyType" />
+ <xsd:element name="sup1" type="docEmptyType" />
+ <xsd:element name="ordm" type="docEmptyType" />
+ <xsd:element name="raquo" type="docEmptyType" />
+ <xsd:element name="frac14" type="docEmptyType" />
+ <xsd:element name="frac12" type="docEmptyType" />
+ <xsd:element name="frac34" type="docEmptyType" />
+ <xsd:element name="iquest" type="docEmptyType" />
+ <xsd:element name="Agrave" type="docEmptyType" />
+ <xsd:element name="Aacute" type="docEmptyType" />
+ <xsd:element name="Acirc" type="docEmptyType" />
+ <xsd:element name="Atilde" type="docEmptyType" />
+ <xsd:element name="Aumlaut" type="docEmptyType" />
+ <xsd:element name="Aring" type="docEmptyType" />
+ <xsd:element name="AElig" type="docEmptyType" />
+ <xsd:element name="Ccedil" type="docEmptyType" />
+ <xsd:element name="Egrave" type="docEmptyType" />
+ <xsd:element name="Eacute" type="docEmptyType" />
+ <xsd:element name="Ecirc" type="docEmptyType" />
+ <xsd:element name="Eumlaut" type="docEmptyType" />
+ <xsd:element name="Igrave" type="docEmptyType" />
+ <xsd:element name="Iacute" type="docEmptyType" />
+ <xsd:element name="Icirc" type="docEmptyType" />
+ <xsd:element name="Iumlaut" type="docEmptyType" />
+ <xsd:element name="ETH" type="docEmptyType" />
+ <xsd:element name="Ntilde" type="docEmptyType" />
+ <xsd:element name="Ograve" type="docEmptyType" />
+ <xsd:element name="Oacute" type="docEmptyType" />
+ <xsd:element name="Ocirc" type="docEmptyType" />
+ <xsd:element name="Otilde" type="docEmptyType" />
+ <xsd:element name="Oumlaut" type="docEmptyType" />
+ <xsd:element name="times" type="docEmptyType" />
+ <xsd:element name="Oslash" type="docEmptyType" />
+ <xsd:element name="Ugrave" type="docEmptyType" />
+ <xsd:element name="Uacute" type="docEmptyType" />
+ <xsd:element name="Ucirc" type="docEmptyType" />
+ <xsd:element name="Uumlaut" type="docEmptyType" />
+ <xsd:element name="Yacute" type="docEmptyType" />
+ <xsd:element name="THORN" type="docEmptyType" />
+ <xsd:element name="szlig" type="docEmptyType" />
+ <xsd:element name="agrave" type="docEmptyType" />
+ <xsd:element name="aacute" type="docEmptyType" />
+ <xsd:element name="acirc" type="docEmptyType" />
+ <xsd:element name="atilde" type="docEmptyType" />
+ <xsd:element name="aumlaut" type="docEmptyType" />
+ <xsd:element name="aring" type="docEmptyType" />
+ <xsd:element name="aelig" type="docEmptyType" />
+ <xsd:element name="ccedil" type="docEmptyType" />
+ <xsd:element name="egrave" type="docEmptyType" />
+ <xsd:element name="eacute" type="docEmptyType" />
+ <xsd:element name="ecirc" type="docEmptyType" />
+ <xsd:element name="eumlaut" type="docEmptyType" />
+ <xsd:element name="igrave" type="docEmptyType" />
+ <xsd:element name="iacute" type="docEmptyType" />
+ <xsd:element name="icirc" type="docEmptyType" />
+ <xsd:element name="iumlaut" type="docEmptyType" />
+ <xsd:element name="eth" type="docEmptyType" />
+ <xsd:element name="ntilde" type="docEmptyType" />
+ <xsd:element name="ograve" type="docEmptyType" />
+ <xsd:element name="oacute" type="docEmptyType" />
+ <xsd:element name="ocirc" type="docEmptyType" />
+ <xsd:element name="otilde" type="docEmptyType" />
+ <xsd:element name="oumlaut" type="docEmptyType" />
+ <xsd:element name="divide" type="docEmptyType" />
+ <xsd:element name="oslash" type="docEmptyType" />
+ <xsd:element name="ugrave" type="docEmptyType" />
+ <xsd:element name="uacute" type="docEmptyType" />
+ <xsd:element name="ucirc" type="docEmptyType" />
+ <xsd:element name="uumlaut" type="docEmptyType" />
+ <xsd:element name="yacute" type="docEmptyType" />
+ <xsd:element name="thorn" type="docEmptyType" />
+ <xsd:element name="yumlaut" type="docEmptyType" />
+ <xsd:element name="fnof" type="docEmptyType" />
+ <xsd:element name="Alpha" type="docEmptyType" />
+ <xsd:element name="Beta" type="docEmptyType" />
+ <xsd:element name="Gamma" type="docEmptyType" />
+ <xsd:element name="Delta" type="docEmptyType" />
+ <xsd:element name="Epsilon" type="docEmptyType" />
+ <xsd:element name="Zeta" type="docEmptyType" />
+ <xsd:element name="Eta" type="docEmptyType" />
+ <xsd:element name="Theta" type="docEmptyType" />
+ <xsd:element name="Iota" type="docEmptyType" />
+ <xsd:element name="Kappa" type="docEmptyType" />
+ <xsd:element name="Lambda" type="docEmptyType" />
+ <xsd:element name="Mu" type="docEmptyType" />
+ <xsd:element name="Nu" type="docEmptyType" />
+ <xsd:element name="Xi" type="docEmptyType" />
+ <xsd:element name="Omicron" type="docEmptyType" />
+ <xsd:element name="Pi" type="docEmptyType" />
+ <xsd:element name="Rho" type="docEmptyType" />
+ <xsd:element name="Sigma" type="docEmptyType" />
+ <xsd:element name="Tau" type="docEmptyType" />
+ <xsd:element name="Upsilon" type="docEmptyType" />
+ <xsd:element name="Phi" type="docEmptyType" />
+ <xsd:element name="Chi" type="docEmptyType" />
+ <xsd:element name="Psi" type="docEmptyType" />
+ <xsd:element name="Omega" type="docEmptyType" />
+ <xsd:element name="alpha" type="docEmptyType" />
+ <xsd:element name="beta" type="docEmptyType" />
+ <xsd:element name="gamma" type="docEmptyType" />
+ <xsd:element name="delta" type="docEmptyType" />
+ <xsd:element name="epsilon" type="docEmptyType" />
+ <xsd:element name="zeta" type="docEmptyType" />
+ <xsd:element name="eta" type="docEmptyType" />
+ <xsd:element name="theta" type="docEmptyType" />
+ <xsd:element name="iota" type="docEmptyType" />
+ <xsd:element name="kappa" type="docEmptyType" />
+ <xsd:element name="lambda" type="docEmptyType" />
+ <xsd:element name="mu" type="docEmptyType" />
+ <xsd:element name="nu" type="docEmptyType" />
+ <xsd:element name="xi" type="docEmptyType" />
+ <xsd:element name="omicron" type="docEmptyType" />
+ <xsd:element name="pi" type="docEmptyType" />
+ <xsd:element name="rho" type="docEmptyType" />
+ <xsd:element name="sigmaf" type="docEmptyType" />
+ <xsd:element name="sigma" type="docEmptyType" />
+ <xsd:element name="tau" type="docEmptyType" />
+ <xsd:element name="upsilon" type="docEmptyType" />
+ <xsd:element name="phi" type="docEmptyType" />
+ <xsd:element name="chi" type="docEmptyType" />
+ <xsd:element name="psi" type="docEmptyType" />
+ <xsd:element name="omega" type="docEmptyType" />
+ <xsd:element name="thetasym" type="docEmptyType" />
+ <xsd:element name="upsih" type="docEmptyType" />
+ <xsd:element name="piv" type="docEmptyType" />
+ <xsd:element name="bull" type="docEmptyType" />
+ <xsd:element name="hellip" type="docEmptyType" />
+ <xsd:element name="prime" type="docEmptyType" />
+ <xsd:element name="Prime" type="docEmptyType" />
+ <xsd:element name="oline" type="docEmptyType" />
+ <xsd:element name="frasl" type="docEmptyType" />
+ <xsd:element name="weierp" type="docEmptyType" />
+ <xsd:element name="image" type="docEmptyType" />
+ <xsd:element name="real" type="docEmptyType" />
+ <xsd:element name="trademark" type="docEmptyType" />
+ <xsd:element name="alefsym" type="docEmptyType" />
+ <xsd:element name="larr" type="docEmptyType" />
+ <xsd:element name="uarr" type="docEmptyType" />
+ <xsd:element name="rarr" type="docEmptyType" />
+ <xsd:element name="darr" type="docEmptyType" />
+ <xsd:element name="harr" type="docEmptyType" />
+ <xsd:element name="crarr" type="docEmptyType" />
+ <xsd:element name="lArr" type="docEmptyType" />
+ <xsd:element name="uArr" type="docEmptyType" />
+ <xsd:element name="rArr" type="docEmptyType" />
+ <xsd:element name="dArr" type="docEmptyType" />
+ <xsd:element name="hArr" type="docEmptyType" />
+ <xsd:element name="forall" type="docEmptyType" />
+ <xsd:element name="part" type="docEmptyType" />
+ <xsd:element name="exist" type="docEmptyType" />
+ <xsd:element name="empty" type="docEmptyType" />
+ <xsd:element name="nabla" type="docEmptyType" />
+ <xsd:element name="isin" type="docEmptyType" />
+ <xsd:element name="notin" type="docEmptyType" />
+ <xsd:element name="ni" type="docEmptyType" />
+ <xsd:element name="prod" type="docEmptyType" />
+ <xsd:element name="sum" type="docEmptyType" />
+ <xsd:element name="minus" type="docEmptyType" />
+ <xsd:element name="lowast" type="docEmptyType" />
+ <xsd:element name="radic" type="docEmptyType" />
+ <xsd:element name="prop" type="docEmptyType" />
+ <xsd:element name="infin" type="docEmptyType" />
+ <xsd:element name="ang" type="docEmptyType" />
+ <xsd:element name="and" type="docEmptyType" />
+ <xsd:element name="or" type="docEmptyType" />
+ <xsd:element name="cap" type="docEmptyType" />
+ <xsd:element name="cup" type="docEmptyType" />
+ <xsd:element name="int" type="docEmptyType" />
+ <xsd:element name="there4" type="docEmptyType" />
+ <xsd:element name="sim" type="docEmptyType" />
+ <xsd:element name="cong" type="docEmptyType" />
+ <xsd:element name="asymp" type="docEmptyType" />
+ <xsd:element name="ne" type="docEmptyType" />
+ <xsd:element name="equiv" type="docEmptyType" />
+ <xsd:element name="le" type="docEmptyType" />
+ <xsd:element name="ge" type="docEmptyType" />
+ <xsd:element name="sub" type="docEmptyType" />
+ <xsd:element name="sup" type="docEmptyType" />
+ <xsd:element name="nsub" type="docEmptyType" />
+ <xsd:element name="sube" type="docEmptyType" />
+ <xsd:element name="supe" type="docEmptyType" />
+ <xsd:element name="oplus" type="docEmptyType" />
+ <xsd:element name="otimes" type="docEmptyType" />
+ <xsd:element name="perp" type="docEmptyType" />
+ <xsd:element name="sdot" type="docEmptyType" />
+ <xsd:element name="lceil" type="docEmptyType" />
+ <xsd:element name="rceil" type="docEmptyType" />
+ <xsd:element name="lfloor" type="docEmptyType" />
+ <xsd:element name="rfloor" type="docEmptyType" />
+ <xsd:element name="lang" type="docEmptyType" />
+ <xsd:element name="rang" type="docEmptyType" />
+ <xsd:element name="loz" type="docEmptyType" />
+ <xsd:element name="spades" type="docEmptyType" />
+ <xsd:element name="clubs" type="docEmptyType" />
+ <xsd:element name="hearts" type="docEmptyType" />
+ <xsd:element name="diams" type="docEmptyType" />
+ <xsd:element name="OElig" type="docEmptyType" />
+ <xsd:element name="oelig" type="docEmptyType" />
+ <xsd:element name="Scaron" type="docEmptyType" />
+ <xsd:element name="scaron" type="docEmptyType" />
+ <xsd:element name="Yumlaut" type="docEmptyType" />
+ <xsd:element name="circ" type="docEmptyType" />
+ <xsd:element name="tilde" type="docEmptyType" />
+ <xsd:element name="ensp" type="docEmptyType" />
+ <xsd:element name="emsp" type="docEmptyType" />
+ <xsd:element name="thinsp" type="docEmptyType" />
+ <xsd:element name="zwnj" type="docEmptyType" />
+ <xsd:element name="zwj" type="docEmptyType" />
+ <xsd:element name="lrm" type="docEmptyType" />
+ <xsd:element name="rlm" type="docEmptyType" />
+ <xsd:element name="ndash" type="docEmptyType" />
+ <xsd:element name="mdash" type="docEmptyType" />
+ <xsd:element name="lsquo" type="docEmptyType" />
+ <xsd:element name="rsquo" type="docEmptyType" />
+ <xsd:element name="sbquo" type="docEmptyType" />
+ <xsd:element name="ldquo" type="docEmptyType" />
+ <xsd:element name="rdquo" type="docEmptyType" />
+ <xsd:element name="bdquo" type="docEmptyType" />
+ <xsd:element name="dagger" type="docEmptyType" />
+ <xsd:element name="Dagger" type="docEmptyType" />
+ <xsd:element name="permil" type="docEmptyType" />
+ <xsd:element name="lsaquo" type="docEmptyType" />
+ <xsd:element name="rsaquo" type="docEmptyType" />
+ <xsd:element name="euro" type="docEmptyType" />
+ <xsd:element name="trademark" type="docEmptyType" />
+ </xsd:choice>
+ </xsd:group>
+
+ <xsd:complexType name="docTitleType" mixed="true">
+ <xsd:group ref="docTitleCmdGroup" minOccurs="0" maxOccurs="unbounded" />
+ </xsd:complexType>
+
+ <xsd:group name="docCmdGroup">
+ <xsd:choice>
+ <xsd:group ref="docTitleCmdGroup"/>
+ <xsd:element name="linebreak" type="docEmptyType" />
+ <xsd:element name="hruler" type="docEmptyType" />
+ <xsd:element name="preformatted" type="docMarkupType" />
+ <xsd:element name="programlisting" type="listingType" />
+ <xsd:element name="verbatim" type="xsd:string" />
+ <xsd:element name="indexentry" type="docIndexEntryType" />
+ <xsd:element name="orderedlist" type="docListType" />
+ <xsd:element name="itemizedlist" type="docListType" />
+ <xsd:element name="simplesect" type="docSimpleSectType" />
+ <xsd:element name="title" type="docTitleType" />
+ <xsd:element name="variablelist" type="docVariableListType" />
+ <xsd:element name="table" type="docTableType" />
+ <xsd:element name="heading" type="docHeadingType" />
+ <xsd:element name="image" type="docImageType" />
+ <xsd:element name="dotfile" type="docFileType" />
+ <xsd:element name="mscfile" type="docFileType" />
+ <xsd:element name="diafile" type="docFileType" />
+ <xsd:element name="toclist" type="docTocListType" />
+ <xsd:element name="language" type="docLanguageType" />
+ <xsd:element name="parameterlist" type="docParamListType" />
+ <xsd:element name="xrefsect" type="docXRefSectType" />
+ <xsd:element name="copydoc" type="docCopyType" />
+ <xsd:element name="blockquote" type="docBlockQuoteType" />
+ <xsd:element name="parblock" type="docParBlockType" />
+ </xsd:choice>
+ </xsd:group>
+
+ <xsd:complexType name="docParaType" mixed="true">
+ <xsd:group ref="docCmdGroup" minOccurs="0" maxOccurs="unbounded" />
+ </xsd:complexType>
+
+ <xsd:complexType name="docMarkupType" mixed="true">
+ <xsd:group ref="docCmdGroup" minOccurs="0" maxOccurs="unbounded" />
+ </xsd:complexType>
+
+ <xsd:complexType name="docURLLink" mixed="true">
+ <xsd:group ref="docTitleCmdGroup" minOccurs="0" maxOccurs="unbounded" />
+ <xsd:attribute name="url" type="xsd:string" />
+ </xsd:complexType>
+
+ <xsd:complexType name="docAnchorType" mixed="true">
+ <xsd:attribute name="id" type="xsd:string" />
+ </xsd:complexType>
+
+ <xsd:complexType name="docFormulaType" mixed="true">
+ <xsd:attribute name="id" type="xsd:string" />
+ </xsd:complexType>
+
+ <xsd:complexType name="docIndexEntryType">
+ <xsd:sequence>
+ <xsd:element name="primaryie" type="xsd:string" />
+ <xsd:element name="secondaryie" type="xsd:string" />
+ </xsd:sequence>
+ </xsd:complexType>
+
+ <xsd:complexType name="docListType">
+ <xsd:sequence>
+ <xsd:element name="listitem" type="docListItemType" maxOccurs="unbounded" />
+ </xsd:sequence>
+ </xsd:complexType>
+
+ <xsd:complexType name="docListItemType">
+ <xsd:sequence>
+ <xsd:element name="para" type="docParaType" minOccurs="0" maxOccurs="unbounded" />
+ </xsd:sequence>
+ </xsd:complexType>
+
+ <xsd:complexType name="docSimpleSectType">
+ <xsd:sequence>
+ <xsd:element name="title" type="docTitleType" minOccurs="0" />
+ <xsd:sequence minOccurs="0" maxOccurs="unbounded">
+ <xsd:element name="para" type="docParaType" minOccurs="1" maxOccurs="unbounded" />
+ </xsd:sequence>
+ </xsd:sequence>
+ <xsd:attribute name="kind" type="DoxSimpleSectKind" />
+ </xsd:complexType>
+
+ <xsd:complexType name="docVarListEntryType">
+ <xsd:sequence>
+ <xsd:element name="term" type="docTitleType" />
+ </xsd:sequence>
+ </xsd:complexType>
+
+ <xsd:group name="docVariableListGroup">
+ <xsd:sequence>
+ <xsd:element name="varlistentry" type="docVarListEntryType" />
+ <xsd:element name="listitem" type="docListItemType" />
+ </xsd:sequence>
+ </xsd:group>
+
+ <xsd:complexType name="docVariableListType">
+ <xsd:sequence>
+ <xsd:group ref="docVariableListGroup" maxOccurs="unbounded" />
+ </xsd:sequence>
+ </xsd:complexType>
+
+ <xsd:complexType name="docRefTextType" mixed="true">
+ <xsd:group ref="docTitleCmdGroup" minOccurs="0" maxOccurs="unbounded" />
+ <xsd:attribute name="refid" type="xsd:string" />
+ <xsd:attribute name="kindref" type="DoxRefKind" />
+ <xsd:attribute name="external" type="xsd:string" />
+ </xsd:complexType>
+
+ <xsd:complexType name="docTableType">
+ <xsd:sequence>
+ <xsd:element name="row" type="docRowType" minOccurs="0" maxOccurs="unbounded" />
+ <xsd:element name="caption" type="docCaptionType" minOccurs="0" />
+ </xsd:sequence>
+ <xsd:attribute name="rows" type="xsd:integer" />
+ <xsd:attribute name="cols" type="xsd:integer" />
+ </xsd:complexType>
+
+ <xsd:complexType name="docRowType">
+ <xsd:sequence>
+ <xsd:element name="entry" type="docEntryType" minOccurs="0" maxOccurs="unbounded" />
+ </xsd:sequence>
+ </xsd:complexType>
+
+ <xsd:complexType name="docEntryType">
+ <xsd:sequence>
+ <xsd:element name="para" type="docParaType" minOccurs="0" maxOccurs="unbounded" />
+ </xsd:sequence>
+ <xsd:attribute name="thead" type="DoxBool" />
+ </xsd:complexType>
+
+ <xsd:complexType name="docCaptionType" mixed="true">
+ <xsd:group ref="docTitleCmdGroup" minOccurs="0" maxOccurs="unbounded" />
+ </xsd:complexType>
+
+ <xsd:complexType name="docHeadingType" mixed="true">
+ <xsd:group ref="docTitleCmdGroup" minOccurs="0" maxOccurs="unbounded" />
+ <xsd:attribute name="level" type="xsd:integer" /> <!-- todo: range 1-6 -->
+ </xsd:complexType>
+
+ <xsd:complexType name="docImageType" mixed="true">
+ <xsd:group ref="docTitleCmdGroup" minOccurs="0" maxOccurs="unbounded" />
+ <xsd:attribute name="type" type="DoxImageKind" />
+ <xsd:attribute name="name" type="xsd:string" />
+ <xsd:attribute name="width" type="xsd:string" />
+ <xsd:attribute name="height" type="xsd:string" />
+ </xsd:complexType>
+
+ <xsd:complexType name="docFileType" mixed="true">
+ <xsd:group ref="docTitleCmdGroup" minOccurs="0" maxOccurs="unbounded" />
+ <xsd:attribute name="name" type="xsd:string" />
+ </xsd:complexType>
+
+ <xsd:complexType name="docTocItemType" mixed="true">
+ <xsd:group ref="docTitleCmdGroup" minOccurs="0" maxOccurs="unbounded" />
+ <xsd:attribute name="id" type="xsd:string" />
+ </xsd:complexType>
+
+ <xsd:complexType name="docTocListType">
+ <xsd:sequence>
+ <xsd:element name="tocitem" type="docTocItemType" minOccurs="0" maxOccurs="unbounded" />
+ </xsd:sequence>
+ </xsd:complexType>
+
+ <xsd:complexType name="docLanguageType">
+ <xsd:sequence>
+ <xsd:element name="para" type="docParaType" minOccurs="0" maxOccurs="unbounded" />
+ </xsd:sequence>
+ <xsd:attribute name="langid" type="xsd:string" />
+ </xsd:complexType>
+
+ <xsd:complexType name="docParamListType">
+ <xsd:sequence>
+ <xsd:element name="parameteritem" type="docParamListItem" minOccurs="0" maxOccurs="unbounded" />
+ </xsd:sequence>
+ <xsd:attribute name="kind" type="DoxParamListKind" />
+ </xsd:complexType>
+
+ <xsd:complexType name="docParamListItem">
+ <xsd:sequence>
+ <xsd:element name="parameternamelist" type="docParamNameList" minOccurs="0" maxOccurs="unbounded" />
+ <xsd:element name="parameterdescription" type="descriptionType" />
+ </xsd:sequence>
+ </xsd:complexType>
+
+ <xsd:complexType name="docParamNameList">
+ <xsd:sequence>
+ <xsd:element name="parametertype" type="docParamType" minOccurs="0" maxOccurs="unbounded" />
+ <xsd:element name="parametername" type="docParamName" minOccurs="0" maxOccurs="unbounded" />
+ </xsd:sequence>
+ </xsd:complexType>
+
+ <xsd:complexType name="docParamType" mixed="true">
+ <xsd:sequence>
+ <xsd:element name="ref" type="refTextType" minOccurs="0" maxOccurs="1" />
+ </xsd:sequence>
+ </xsd:complexType>
+
+ <xsd:complexType name="docParamName" mixed="true">
+ <xsd:sequence>
+ <xsd:element name="ref" type="refTextType" minOccurs="0" maxOccurs="1" />
+ </xsd:sequence>
+ <xsd:attribute name="direction" type="DoxParamDir" use="optional" />
+ </xsd:complexType>
+
+ <xsd:complexType name="docXRefSectType">
+ <xsd:sequence>
+ <xsd:element name="xreftitle" type="xsd:string" minOccurs="0" maxOccurs="unbounded" />
+ <xsd:element name="xrefdescription" type="descriptionType" />
+ </xsd:sequence>
+ <xsd:attribute name="id" type="xsd:string" />
+ </xsd:complexType>
+
+ <xsd:complexType name="docCopyType">
+ <xsd:sequence>
+ <xsd:element name="para" type="docParaType" minOccurs="0" maxOccurs="unbounded" />
+ <xsd:element name="sect1" type="docSect1Type" minOccurs="0" maxOccurs="unbounded" />
+ <xsd:element name="internal" type="docInternalType" minOccurs="0" />
+ </xsd:sequence>
+ <xsd:attribute name="link" type="xsd:string" />
+ </xsd:complexType>
+
+ <xsd:complexType name="docBlockQuoteType">
+ <xsd:sequence>
+ <xsd:element name="para" type="docParaType" minOccurs="0" maxOccurs="unbounded" />
+ </xsd:sequence>
+ </xsd:complexType>
+
+ <xsd:complexType name="docParBlockType">
+ <xsd:sequence>
+ <xsd:element name="para" type="docParaType" minOccurs="0" maxOccurs="unbounded" />
+ </xsd:sequence>
+ </xsd:complexType>
+
+ <xsd:complexType name="docEmptyType"/>
+
+ <!-- Simple types -->
+
+ <xsd:simpleType name="DoxBool">
+ <xsd:restriction base="xsd:string">
+ <xsd:enumeration value="yes" />
+ <xsd:enumeration value="no" />
+ </xsd:restriction>
+ </xsd:simpleType>
+
+ <xsd:simpleType name="DoxGraphRelation">
+ <xsd:restriction base="xsd:string">
+ <xsd:enumeration value="include" />
+ <xsd:enumeration value="usage" />
+ <xsd:enumeration value="template-instance" />
+ <xsd:enumeration value="public-inheritance" />
+ <xsd:enumeration value="protected-inheritance" />
+ <xsd:enumeration value="private-inheritance" />
+ </xsd:restriction>
+ </xsd:simpleType>
+
+ <xsd:simpleType name="DoxRefKind">
+ <xsd:restriction base="xsd:string">
+ <xsd:enumeration value="compound" />
+ <xsd:enumeration value="member" />
+ </xsd:restriction>
+ </xsd:simpleType>
+
+ <xsd:simpleType name="DoxMemberKind">
+ <xsd:restriction base="xsd:string">
+ <xsd:enumeration value="define" />
+ <xsd:enumeration value="property" />
+ <xsd:enumeration value="event" />
+ <xsd:enumeration value="variable" />
+ <xsd:enumeration value="typedef" />
+ <xsd:enumeration value="enum" />
+ <xsd:enumeration value="function" />
+ <xsd:enumeration value="signal" />
+ <xsd:enumeration value="prototype" />
+ <xsd:enumeration value="friend" />
+ <xsd:enumeration value="dcop" />
+ <xsd:enumeration value="slot" />
+ <xsd:enumeration value="interface" />
+ <xsd:enumeration value="service" />
+ </xsd:restriction>
+ </xsd:simpleType>
+
+ <xsd:simpleType name="DoxProtectionKind">
+ <xsd:restriction base="xsd:string">
+ <xsd:enumeration value="public" />
+ <xsd:enumeration value="protected" />
+ <xsd:enumeration value="private" />
+ <xsd:enumeration value="package" />
+ </xsd:restriction>
+ </xsd:simpleType>
+
+ <xsd:simpleType name="DoxVirtualKind">
+ <xsd:restriction base="xsd:string">
+ <xsd:enumeration value="non-virtual" />
+ <xsd:enumeration value="virtual" />
+ <xsd:enumeration value="pure-virtual" />
+ </xsd:restriction>
+ </xsd:simpleType>
+
+ <xsd:simpleType name="DoxCompoundKind">
+ <xsd:restriction base="xsd:string">
+ <xsd:enumeration value="class" />
+ <xsd:enumeration value="struct" />
+ <xsd:enumeration value="union" />
+ <xsd:enumeration value="interface" />
+ <xsd:enumeration value="protocol" />
+ <xsd:enumeration value="category" />
+ <xsd:enumeration value="exception" />
+ <xsd:enumeration value="service" />
+ <xsd:enumeration value="singleton" />
+ <xsd:enumeration value="module" />
+ <xsd:enumeration value="type" />
+ <xsd:enumeration value="file" />
+ <xsd:enumeration value="namespace" />
+ <xsd:enumeration value="group" />
+ <xsd:enumeration value="page" />
+ <xsd:enumeration value="example" />
+ <xsd:enumeration value="dir" />
+ </xsd:restriction>
+ </xsd:simpleType>
+
+ <xsd:simpleType name="DoxSectionKind">
+ <xsd:restriction base="xsd:string">
+ <xsd:enumeration value="user-defined" />
+ <xsd:enumeration value="public-type" />
+ <xsd:enumeration value="public-func" />
+ <xsd:enumeration value="public-attrib" />
+ <xsd:enumeration value="public-slot" />
+ <xsd:enumeration value="signal" />
+ <xsd:enumeration value="dcop-func" />
+ <xsd:enumeration value="property" />
+ <xsd:enumeration value="event" />
+ <xsd:enumeration value="public-static-func" />
+ <xsd:enumeration value="public-static-attrib" />
+ <xsd:enumeration value="protected-type" />
+ <xsd:enumeration value="protected-func" />
+ <xsd:enumeration value="protected-attrib" />
+ <xsd:enumeration value="protected-slot" />
+ <xsd:enumeration value="protected-static-func" />
+ <xsd:enumeration value="protected-static-attrib" />
+ <xsd:enumeration value="package-type" />
+ <xsd:enumeration value="package-func" />
+ <xsd:enumeration value="package-attrib" />
+ <xsd:enumeration value="package-static-func" />
+ <xsd:enumeration value="package-static-attrib" />
+ <xsd:enumeration value="private-type" />
+ <xsd:enumeration value="private-func" />
+ <xsd:enumeration value="private-attrib" />
+ <xsd:enumeration value="private-slot" />
+ <xsd:enumeration value="private-static-func" />
+ <xsd:enumeration value="private-static-attrib" />
+ <xsd:enumeration value="friend" />
+ <xsd:enumeration value="related" />
+ <xsd:enumeration value="define" />
+ <xsd:enumeration value="prototype" />
+ <xsd:enumeration value="typedef" />
+ <xsd:enumeration value="enum" />
+ <xsd:enumeration value="func" />
+ <xsd:enumeration value="var" />
+ </xsd:restriction>
+ </xsd:simpleType>
+
+ <xsd:simpleType name="DoxHighlightClass">
+ <xsd:restriction base="xsd:string">
+ <xsd:enumeration value="comment" />
+ <xsd:enumeration value="normal" />
+ <xsd:enumeration value="preprocessor" />
+ <xsd:enumeration value="keyword" />
+ <xsd:enumeration value="keywordtype" />
+ <xsd:enumeration value="keywordflow" />
+ <xsd:enumeration value="stringliteral" />
+ <xsd:enumeration value="charliteral" />
+ </xsd:restriction>
+ </xsd:simpleType>
+
+ <xsd:simpleType name="DoxSimpleSectKind">
+ <xsd:restriction base="xsd:string">
+ <xsd:enumeration value="see" />
+ <xsd:enumeration value="return" />
+ <xsd:enumeration value="author" />
+ <xsd:enumeration value="authors" />
+ <xsd:enumeration value="version" />
+ <xsd:enumeration value="since" />
+ <xsd:enumeration value="date" />
+ <xsd:enumeration value="note" />
+ <xsd:enumeration value="warning" />
+ <xsd:enumeration value="pre" />
+ <xsd:enumeration value="post" />
+ <xsd:enumeration value="copyright" />
+ <xsd:enumeration value="invariant" />
+ <xsd:enumeration value="remark" />
+ <xsd:enumeration value="attention" />
+ <xsd:enumeration value="par" />
+ <xsd:enumeration value="rcs" />
+ </xsd:restriction>
+ </xsd:simpleType>
+
+ <xsd:simpleType name="DoxVersionNumber">
+ <xsd:restriction base="xsd:string">
+ <xsd:pattern value="\d+\.\d+.*" />
+ </xsd:restriction>
+ </xsd:simpleType>
+
+ <xsd:simpleType name="DoxImageKind">
+ <xsd:restriction base="xsd:string">
+ <xsd:enumeration value="html" />
+ <xsd:enumeration value="latex" />
+ <xsd:enumeration value="rtf" />
+ </xsd:restriction>
+ </xsd:simpleType>
+
+ <xsd:simpleType name="DoxParamListKind">
+ <xsd:restriction base="xsd:string">
+ <xsd:enumeration value="param" />
+ <xsd:enumeration value="retval" />
+ <xsd:enumeration value="exception" />
+ <xsd:enumeration value="templateparam" />
+ </xsd:restriction>
+ </xsd:simpleType>
+
+ <xsd:simpleType name="DoxCharRange">
+ <xsd:restriction base="xsd:string">
+ <xsd:pattern value="[aeiouncAEIOUNC]" />
+ </xsd:restriction>
+ </xsd:simpleType>
+
+ <xsd:simpleType name="DoxParamDir">
+ <xsd:restriction base="xsd:string">
+ <xsd:enumeration value="in"/>
+ <xsd:enumeration value="out"/>
+ <xsd:enumeration value="inout"/>
+ </xsd:restriction>
+ </xsd:simpleType>
+
+ <xsd:simpleType name="DoxAccessor">
+ <xsd:restriction base="xsd:string">
+ <xsd:enumeration value="retain"/>
+ <xsd:enumeration value="copy"/>
+ <xsd:enumeration value="assign"/>
+ <xsd:enumeration value="weak"/>
+ <xsd:enumeration value="strong"/>
+ <xsd:enumeration value="unretained"/>
+ </xsd:restriction>
+ </xsd:simpleType>
+
+</xsd:schema>
+
--- /dev/null
+<?xml version='1.0' encoding='UTF-8' standalone='no'?>
+<doxygen xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="compound.xsd" version="1.8.8">
+ <compounddef id="dir_68267d1309a1af8e8297ef4c3efbcdba" kind="dir">
+ <compoundname>src</compoundname>
+ <innerdir refid="dir_b8e0663afee48cb679b74bbd21bdf843">src/org</innerdir>
+ <briefdescription>
+ </briefdescription>
+ <detaileddescription>
+ </detaileddescription>
+ <location file="%SOURCE_DIRECTORY%/"/>
+ </compounddef>
+</doxygen>
--- /dev/null
+<?xml version='1.0' encoding='UTF-8' standalone='no'?>
+<doxygen xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="compound.xsd" version="1.8.8">
+ <compounddef id="dir_8c35fc67c36f89d827afb23e8c52a418" kind="dir">
+ <compoundname>src/org/example</compoundname>
+ <innerdir refid="dir_ad5d6582648a7bbb3a301939a41e6c0b">src/org/example/foo</innerdir>
+ <briefdescription>
+ </briefdescription>
+ <detaileddescription>
+ </detaileddescription>
+ <location file="%SOURCE_DIRECTORY%/org/example/"/>
+ </compounddef>
+</doxygen>
--- /dev/null
+<?xml version='1.0' encoding='UTF-8' standalone='no'?>
+<doxygen xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="compound.xsd" version="1.8.8">
+ <compounddef id="dir_ad5d6582648a7bbb3a301939a41e6c0b" kind="dir">
+ <compoundname>src/org/example/foo</compoundname>
+ <innerfile refid="_a_8java">A.java</innerfile>
+ <innerfile refid="_b_8java">B.java</innerfile>
+ <innerfile refid="_c_8java">C.java</innerfile>
+ <innerfile refid="_empty_class_8java">EmptyClass.java</innerfile>
+ <briefdescription>
+ </briefdescription>
+ <detaileddescription>
+ </detaileddescription>
+ <location file="%SOURCE_DIRECTORY%/org/example/foo/"/>
+ </compounddef>
+</doxygen>
--- /dev/null
+<?xml version='1.0' encoding='UTF-8' standalone='no'?>
+<doxygen xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="compound.xsd" version="1.8.8">
+ <compounddef id="dir_b8e0663afee48cb679b74bbd21bdf843" kind="dir">
+ <compoundname>src/org</compoundname>
+ <innerdir refid="dir_8c35fc67c36f89d827afb23e8c52a418">src/org/example</innerdir>
+ <briefdescription>
+ </briefdescription>
+ <detaileddescription>
+ </detaileddescription>
+ <location file="%SOURCE_DIRECTORY%/org/"/>
+ </compounddef>
+</doxygen>
--- /dev/null
+<?xml version='1.0' encoding='UTF-8' standalone='no'?>
+<doxygenindex xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="index.xsd" version="1.8.8">
+ <compound refid="classorg_1_1example_1_1foo_1_1_a" kind="class"><name>org::example::foo::A</name>
+ <member refid="classorg_1_1example_1_1foo_1_1_a_1add415ae4129969055d678c7e7e048852" kind="function"><name>bar</name></member>
+ </compound>
+ <compound refid="classorg_1_1example_1_1foo_1_1_b" kind="class"><name>org::example::foo::B</name>
+ <member refid="classorg_1_1example_1_1foo_1_1_b_1ac6b627949b10b9357eefc0cafcae1d87" kind="variable"><name>qux</name></member>
+ <member refid="classorg_1_1example_1_1foo_1_1_b_1a11e157943665cc9e3a9be1502ebeb3b5" kind="function"><name>bar</name></member>
+ <member refid="classorg_1_1example_1_1foo_1_1_b_1a733f4e076f29c7d0c41ed258199ea1d9" kind="function"><name>baz</name></member>
+ </compound>
+ <compound refid="interfaceorg_1_1example_1_1foo_1_1_c" kind="interface"><name>org::example::foo::C</name>
+ <member refid="interfaceorg_1_1example_1_1foo_1_1_c_1a4e97061eb40b045e820de05b33c43d21" kind="variable"><name>THE_ANSWER</name></member>
+ <member refid="interfaceorg_1_1example_1_1foo_1_1_c_1a28ac7ce349ebb3e4a7747a8dd951582b" kind="function"><name>baz</name></member>
+ </compound>
+ <compound refid="classorg_1_1example_1_1foo_1_1_empty_class" kind="class"><name>org::example::foo::EmptyClass</name>
+ </compound>
+ <compound refid="namespaceorg" kind="namespace"><name>org</name>
+ </compound>
+ <compound refid="namespaceorg_1_1example" kind="namespace"><name>org::example</name>
+ </compound>
+ <compound refid="namespaceorg_1_1example_1_1foo" kind="namespace"><name>org::example::foo</name>
+ </compound>
+ <compound refid="_a_8java" kind="file"><name>A.java</name>
+ </compound>
+ <compound refid="_b_8java" kind="file"><name>B.java</name>
+ </compound>
+ <compound refid="_c_8java" kind="file"><name>C.java</name>
+ </compound>
+ <compound refid="_empty_class_8java" kind="file"><name>EmptyClass.java</name>
+ </compound>
+ <compound refid="dir_8c35fc67c36f89d827afb23e8c52a418" kind="dir"><name>src/org/example</name>
+ </compound>
+ <compound refid="dir_ad5d6582648a7bbb3a301939a41e6c0b" kind="dir"><name>src/org/example/foo</name>
+ </compound>
+ <compound refid="dir_b8e0663afee48cb679b74bbd21bdf843" kind="dir"><name>src/org</name>
+ </compound>
+ <compound refid="dir_68267d1309a1af8e8297ef4c3efbcdba" kind="dir"><name>src</name>
+ </compound>
+</doxygenindex>
--- /dev/null
+<?xml version='1.0' encoding='utf-8' ?>
+<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
+ <xsd:element name="doxygenindex" type="DoxygenType"/>
+
+ <xsd:complexType name="DoxygenType">
+ <xsd:sequence>
+ <xsd:element name="compound" type="CompoundType" minOccurs="0" maxOccurs="unbounded"/>
+ </xsd:sequence>
+ <xsd:attribute name="version" type="xsd:string" use="required"/>
+ </xsd:complexType>
+
+ <xsd:complexType name="CompoundType">
+ <xsd:sequence>
+ <xsd:element name="name" type="xsd:string"/>
+ <xsd:element name="member" type="MemberType" minOccurs="0" maxOccurs="unbounded"/>
+ </xsd:sequence>
+ <xsd:attribute name="refid" type="xsd:string" use="required"/>
+ <xsd:attribute name="kind" type="CompoundKind" use="required"/>
+ </xsd:complexType>
+
+ <xsd:complexType name="MemberType">
+ <xsd:sequence>
+ <xsd:element name="name" type="xsd:string"/>
+ </xsd:sequence>
+ <xsd:attribute name="refid" type="xsd:string" use="required"/>
+ <xsd:attribute name="kind" type="MemberKind" use="required"/>
+ </xsd:complexType>
+
+ <xsd:simpleType name="CompoundKind">
+ <xsd:restriction base="xsd:string">
+ <xsd:enumeration value="class"/>
+ <xsd:enumeration value="struct"/>
+ <xsd:enumeration value="union"/>
+ <xsd:enumeration value="interface"/>
+ <xsd:enumeration value="protocol"/>
+ <xsd:enumeration value="category"/>
+ <xsd:enumeration value="exception"/>
+ <xsd:enumeration value="file"/>
+ <xsd:enumeration value="namespace"/>
+ <xsd:enumeration value="group"/>
+ <xsd:enumeration value="page"/>
+ <xsd:enumeration value="example"/>
+ <xsd:enumeration value="dir"/>
+ </xsd:restriction>
+ </xsd:simpleType>
+
+ <xsd:simpleType name="MemberKind">
+ <xsd:restriction base="xsd:string">
+ <xsd:enumeration value="define"/>
+ <xsd:enumeration value="property"/>
+ <xsd:enumeration value="event"/>
+ <xsd:enumeration value="variable"/>
+ <xsd:enumeration value="typedef"/>
+ <xsd:enumeration value="enum"/>
+ <xsd:enumeration value="enumvalue"/>
+ <xsd:enumeration value="function"/>
+ <xsd:enumeration value="signal"/>
+ <xsd:enumeration value="prototype"/>
+ <xsd:enumeration value="friend"/>
+ <xsd:enumeration value="dcop"/>
+ <xsd:enumeration value="slot"/>
+ </xsd:restriction>
+ </xsd:simpleType>
+
+</xsd:schema>
+
--- /dev/null
+<?xml version='1.0' encoding='UTF-8' standalone='no'?>
+<doxygen xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="compound.xsd" version="1.8.8">
+ <compounddef id="interfaceorg_1_1example_1_1foo_1_1_c" kind="interface" prot="public">
+ <compoundname>org::example::foo::C</compoundname>
+ <derivedcompoundref refid="classorg_1_1example_1_1foo_1_1_b" prot="public" virt="non-virtual">org.example.foo.B</derivedcompoundref>
+ <sectiondef kind="public-static-attrib">
+ <memberdef kind="variable" id="interfaceorg_1_1example_1_1foo_1_1_c_1a4e97061eb40b045e820de05b33c43d21" prot="public" static="yes" mutable="no">
+ <type>final long</type>
+ <definition>final long org.example.foo.C.THE_ANSWER</definition>
+ <argsstring></argsstring>
+ <name>THE_ANSWER</name>
+ <initializer>= 42L</initializer>
+ <briefdescription>
+ </briefdescription>
+ <detaileddescription>
+<para>“Answer to the Ultimate Question of Life, the Universe, and Everything.“ </para> </detaileddescription>
+ <inbodydescription>
+ </inbodydescription>
+ <location file="%SOURCE_DIRECTORY%/org/example/foo/C.java" line="25" column="1" bodyfile="%SOURCE_DIRECTORY%/org/example/foo/C.java" bodystart="25" bodyend="-1"/>
+ </memberdef>
+ </sectiondef>
+ <sectiondef kind="public-func">
+ <memberdef kind="function" id="interfaceorg_1_1example_1_1foo_1_1_c_1a28ac7ce349ebb3e4a7747a8dd951582b" prot="public" static="no" const="no" explicit="no" inline="no" virt="non-virtual">
+ <type>void</type>
+ <definition>void org.example.foo.C.baz</definition>
+ <argsstring>()</argsstring>
+ <name>baz</name>
+ <reimplementedby refid="classorg_1_1example_1_1foo_1_1_b_1a733f4e076f29c7d0c41ed258199ea1d9">baz</reimplementedby>
+ <briefdescription>
+ </briefdescription>
+ <detaileddescription>
+<para><ref refid="classorg_1_1example_1_1foo_1_1_a" kindref="compound">A</ref> function with implicit modifiers. </para> </detaileddescription>
+ <inbodydescription>
+ </inbodydescription>
+ <location file="%SOURCE_DIRECTORY%/org/example/foo/C.java" line="30" column="1"/>
+ </memberdef>
+ </sectiondef>
+ <briefdescription>
+ </briefdescription>
+ <detaileddescription>
+<para>An interface </para> </detaileddescription>
+ <inheritancegraph>
+ <node id="10">
+ <label>org.example.foo.B</label>
+ <link refid="classorg_1_1example_1_1foo_1_1_b"/>
+ <childnode refid="9" relation="public-inheritance">
+ </childnode>
+ </node>
+ <node id="9">
+ <label>org.example.foo.C</label>
+ <link refid="interfaceorg_1_1example_1_1foo_1_1_c"/>
+ </node>
+ </inheritancegraph>
+ <location file="%SOURCE_DIRECTORY%/org/example/foo/C.java" line="21" column="1" bodyfile="%SOURCE_DIRECTORY%/org/example/foo/C.java" bodystart="21" bodyend="31"/>
+ <listofallmembers>
+ <member refid="interfaceorg_1_1example_1_1foo_1_1_c_1a28ac7ce349ebb3e4a7747a8dd951582b" prot="public" virt="non-virtual"><scope>org::example::foo::C</scope><name>baz</name></member>
+ <member refid="interfaceorg_1_1example_1_1foo_1_1_c_1a4e97061eb40b045e820de05b33c43d21" prot="public" virt="non-virtual"><scope>org::example::foo::C</scope><name>THE_ANSWER</name></member>
+ </listofallmembers>
+ </compounddef>
+</doxygen>
--- /dev/null
+<?xml version='1.0' encoding='UTF-8' standalone='no'?>
+<doxygen xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="compound.xsd" version="1.8.8">
+ <compounddef id="namespaceorg" kind="namespace">
+ <compoundname>org</compoundname>
+ <innernamespace refid="namespaceorg_1_1example">org::example</innernamespace>
+ <briefdescription>
+ </briefdescription>
+ <detaileddescription>
+ </detaileddescription>
+ <location file="[generated]" line="1" column="1"/>
+ </compounddef>
+</doxygen>
--- /dev/null
+<?xml version='1.0' encoding='UTF-8' standalone='no'?>
+<doxygen xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="compound.xsd" version="1.8.8">
+ <compounddef id="namespaceorg_1_1example" kind="namespace">
+ <compoundname>org::example</compoundname>
+ <innernamespace refid="namespaceorg_1_1example_1_1foo">org::example::foo</innernamespace>
+ <briefdescription>
+ </briefdescription>
+ <detaileddescription>
+ </detaileddescription>
+ <location file="[generated]" line="1" column="1"/>
+ </compounddef>
+</doxygen>
--- /dev/null
+<?xml version='1.0' encoding='UTF-8' standalone='no'?>
+<doxygen xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="compound.xsd" version="1.8.8">
+ <compounddef id="namespaceorg_1_1example_1_1foo" kind="namespace">
+ <compoundname>org::example::foo</compoundname>
+ <innerclass refid="classorg_1_1example_1_1foo_1_1_a" prot="public">org::example::foo::A</innerclass>
+ <innerclass refid="classorg_1_1example_1_1foo_1_1_b" prot="public">org::example::foo::B</innerclass>
+ <innerclass refid="interfaceorg_1_1example_1_1foo_1_1_c" prot="public">org::example::foo::C</innerclass>
+ <innerclass refid="classorg_1_1example_1_1foo_1_1_empty_class" prot="package">org::example::foo::EmptyClass</innerclass>
+ <briefdescription>
+ </briefdescription>
+ <detaileddescription>
+ </detaileddescription>
+ <location file="%SOURCE_DIRECTORY%/org/example/foo/A.java" line="16" column="1"/>
+ </compounddef>
+</doxygen>
--- /dev/null
+# Doxyfile 1.8.8
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project.
+#
+# All text after a double hash (##) is considered a comment and is placed in
+# front of the TAG it is preceding.
+#
+# All text after a single hash (#) is considered a comment and will be ignored.
+# The format is:
+# TAG = value [value, ...]
+# For lists, items can also be appended using:
+# TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (\" \").
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# This tag specifies the encoding used for all characters in the config file
+# that follow. The default is UTF-8 which is also the encoding used for all text
+# before the first occurrence of this tag. Doxygen uses libiconv (or the iconv
+# built into libc) for the transcoding. See http://www.gnu.org/software/libiconv
+# for the list of possible encodings.
+# The default value is: UTF-8.
+
+DOXYFILE_ENCODING = UTF-8
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by
+# double-quotes, unless you are using Doxywizard) that should identify the
+# project for which the documentation is generated. This name is used in the
+# title of most generated pages and in a few other places.
+# The default value is: My Project.
+
+PROJECT_NAME = "Test Project"
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number. This
+# could be handy for archiving the generated documentation or if some version
+# control system is used.
+
+PROJECT_NUMBER =
+
+# Using the PROJECT_BRIEF tag one can provide an optional one line description
+# for a project that appears at the top of each page and should give viewer a
+# quick idea about the purpose of the project. Keep the description short.
+
+PROJECT_BRIEF =
+
+# With the PROJECT_LOGO tag one can specify a logo or an icon that is included
+# in the documentation. The maximum height of the logo should not exceed 55
+# pixels and the maximum width should not exceed 200 pixels. Doxygen will copy
+# the logo to the output directory.
+
+PROJECT_LOGO =
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path
+# into which the generated documentation will be written. If a relative path is
+# entered, it will be relative to the location where doxygen was started. If
+# left blank the current directory will be used.
+
+OUTPUT_DIRECTORY =
+
+# If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub-
+# directories (in 2 levels) under the output directory of each output format and
+# will distribute the generated files over these directories. Enabling this
+# option can be useful when feeding doxygen a huge amount of source files, where
+# putting all generated files in the same directory would otherwise causes
+# performance problems for the file system.
+# The default value is: NO.
+
+CREATE_SUBDIRS = NO
+
+# If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII
+# characters to appear in the names of generated files. If set to NO, non-ASCII
+# characters will be escaped, for example _xE3_x81_x84 will be used for Unicode
+# U+3044.
+# The default value is: NO.
+
+ALLOW_UNICODE_NAMES = NO
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all
+# documentation generated by doxygen is written. Doxygen will use this
+# information to generate all constant output in the proper language.
+# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese,
+# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States),
+# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian,
+# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages),
+# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian,
+# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian,
+# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish,
+# Ukrainian and Vietnamese.
+# The default value is: English.
+
+OUTPUT_LANGUAGE = English
+
+# If the BRIEF_MEMBER_DESC tag is set to YES, doxygen will include brief member
+# descriptions after the members that are listed in the file and class
+# documentation (similar to Javadoc). Set to NO to disable this.
+# The default value is: YES.
+
+BRIEF_MEMBER_DESC = YES
+
+# If the REPEAT_BRIEF tag is set to YES, doxygen will prepend the brief
+# description of a member or function before the detailed description
+#
+# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
+# brief descriptions will be completely suppressed.
+# The default value is: YES.
+
+REPEAT_BRIEF = YES
+
+# This tag implements a quasi-intelligent brief description abbreviator that is
+# used to form the text in various listings. Each string in this list, if found
+# as the leading text of the brief description, will be stripped from the text
+# and the result, after processing the whole list, is used as the annotated
+# text. Otherwise, the brief description is used as-is. If left blank, the
+# following values are used ($name is automatically replaced with the name of
+# the entity):The $name class, The $name widget, The $name file, is, provides,
+# specifies, contains, represents, a, an and the.
+
+ABBREVIATE_BRIEF = "The $name class" \
+ "The $name widget" \
+ "The $name file" \
+ is \
+ provides \
+ specifies \
+ contains \
+ represents \
+ a \
+ an \
+ the
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
+# doxygen will generate a detailed section even if there is only a brief
+# description.
+# The default value is: NO.
+
+ALWAYS_DETAILED_SEC = NO
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
+# inherited members of a class in the documentation of that class as if those
+# members were ordinary class members. Constructors, destructors and assignment
+# operators of the base classes will not be shown.
+# The default value is: NO.
+
+INLINE_INHERITED_MEMB = NO
+
+# If the FULL_PATH_NAMES tag is set to YES, doxygen will prepend the full path
+# before files name in the file list and in the header files. If set to NO the
+# shortest path that makes the file name unique will be used
+# The default value is: YES.
+
+FULL_PATH_NAMES = YES
+
+# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path.
+# Stripping is only done if one of the specified strings matches the left-hand
+# part of the path. The tag can be used to show relative paths in the file list.
+# If left blank the directory from which doxygen is run is used as the path to
+# strip.
+#
+# Note that you can specify absolute paths here, but also relative paths, which
+# will be relative from the directory where doxygen is started.
+# This tag requires that the tag FULL_PATH_NAMES is set to YES.
+
+STRIP_FROM_PATH =
+
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the
+# path mentioned in the documentation of a class, which tells the reader which
+# header file to include in order to use a class. If left blank only the name of
+# the header file containing the class definition is used. Otherwise one should
+# specify the list of include paths that are normally passed to the compiler
+# using the -I flag.
+
+STRIP_FROM_INC_PATH =
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but
+# less readable) file names. This can be useful is your file systems doesn't
+# support long names like on DOS, Mac, or CD-ROM.
+# The default value is: NO.
+
+SHORT_NAMES = NO
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the
+# first line (until the first dot) of a Javadoc-style comment as the brief
+# description. If set to NO, the Javadoc-style will behave just like regular Qt-
+# style comments (thus requiring an explicit @brief command for a brief
+# description.)
+# The default value is: NO.
+
+JAVADOC_AUTOBRIEF = NO
+
+# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first
+# line (until the first dot) of a Qt-style comment as the brief description. If
+# set to NO, the Qt-style will behave just like regular Qt-style comments (thus
+# requiring an explicit \brief command for a brief description.)
+# The default value is: NO.
+
+QT_AUTOBRIEF = NO
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a
+# multi-line C++ special comment block (i.e. a block of //! or /// comments) as
+# a brief description. This used to be the default behavior. The new default is
+# to treat a multi-line C++ comment block as a detailed description. Set this
+# tag to YES if you prefer the old behavior instead.
+#
+# Note that setting this tag to YES also means that rational rose comments are
+# not recognized any more.
+# The default value is: NO.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the
+# documentation from any documented member that it re-implements.
+# The default value is: YES.
+
+INHERIT_DOCS = YES
+
+# If the SEPARATE_MEMBER_PAGES tag is set to YES then doxygen will produce a new
+# page for each member. If set to NO, the documentation of a member will be part
+# of the file/class/namespace that contains it.
+# The default value is: NO.
+
+SEPARATE_MEMBER_PAGES = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen
+# uses this value to replace tabs by spaces in code fragments.
+# Minimum value: 1, maximum value: 16, default value: 4.
+
+TAB_SIZE = 4
+
+# This tag can be used to specify a number of aliases that act as commands in
+# the documentation. An alias has the form:
+# name=value
+# For example adding
+# "sideeffect=@par Side Effects:\n"
+# will allow you to put the command \sideeffect (or @sideeffect) in the
+# documentation, which will result in a user-defined paragraph with heading
+# "Side Effects:". You can put \n's in the value part of an alias to insert
+# newlines.
+
+ALIASES =
+
+# This tag can be used to specify a number of word-keyword mappings (TCL only).
+# A mapping has the form "name=value". For example adding "class=itcl::class"
+# will allow you to use the command class in the itcl::class meaning.
+
+TCL_SUBST =
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources
+# only. Doxygen will then generate output that is more tailored for C. For
+# instance, some of the names that are used will be different. The list of all
+# members will be omitted, etc.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_FOR_C = NO
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or
+# Python sources only. Doxygen will then generate output that is more tailored
+# for that language. For instance, namespaces will be presented as packages,
+# qualified scopes will look different, etc.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_JAVA = YES
+
+# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran
+# sources. Doxygen will then generate output that is tailored for Fortran.
+# The default value is: NO.
+
+OPTIMIZE_FOR_FORTRAN = NO
+
+# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL
+# sources. Doxygen will then generate output that is tailored for VHDL.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_VHDL = NO
+
+# Doxygen selects the parser to use depending on the extension of the files it
+# parses. With this tag you can assign which parser to use for a given
+# extension. Doxygen has a built-in mapping, but you can override or extend it
+# using this tag. The format is ext=language, where ext is a file extension, and
+# language is one of the parsers supported by doxygen: IDL, Java, Javascript,
+# C#, C, C++, D, PHP, Objective-C, Python, Fortran (fixed format Fortran:
+# FortranFixed, free formatted Fortran: FortranFree, unknown formatted Fortran:
+# Fortran. In the later case the parser tries to guess whether the code is fixed
+# or free formatted code, this is the default for Fortran type files), VHDL. For
+# instance to make doxygen treat .inc files as Fortran files (default is PHP),
+# and .f files as C (default is Fortran), use: inc=Fortran f=C.
+#
+# Note: For files without extension you can use no_extension as a placeholder.
+#
+# Note that for custom extensions you also need to set FILE_PATTERNS otherwise
+# the files are not read by doxygen.
+
+EXTENSION_MAPPING =
+
+# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments
+# according to the Markdown format, which allows for more readable
+# documentation. See http://daringfireball.net/projects/markdown/ for details.
+# The output of markdown processing is further processed by doxygen, so you can
+# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in
+# case of backward compatibilities issues.
+# The default value is: YES.
+
+MARKDOWN_SUPPORT = YES
+
+# When enabled doxygen tries to link words that correspond to documented
+# classes, or namespaces to their corresponding documentation. Such a link can
+# be prevented in individual cases by putting a % sign in front of the word or
+# globally by setting AUTOLINK_SUPPORT to NO.
+# The default value is: YES.
+
+AUTOLINK_SUPPORT = YES
+
+# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
+# to include (a tag file for) the STL sources as input, then you should set this
+# tag to YES in order to let doxygen match functions declarations and
+# definitions whose arguments contain STL classes (e.g. func(std::string);
+# versus func(std::string) {}). This also make the inheritance and collaboration
+# diagrams that involve STL classes more complete and accurate.
+# The default value is: NO.
+
+BUILTIN_STL_SUPPORT = NO
+
+# If you use Microsoft's C++/CLI language, you should set this option to YES to
+# enable parsing support.
+# The default value is: NO.
+
+CPP_CLI_SUPPORT = NO
+
+# Set the SIP_SUPPORT tag to YES if your project consists of sip (see:
+# http://www.riverbankcomputing.co.uk/software/sip/intro) sources only. Doxygen
+# will parse them like normal C++ but will assume all classes use public instead
+# of private inheritance when no explicit protection keyword is present.
+# The default value is: NO.
+
+SIP_SUPPORT = NO
+
+# For Microsoft's IDL there are propget and propput attributes to indicate
+# getter and setter methods for a property. Setting this option to YES will make
+# doxygen to replace the get and set methods by a property in the documentation.
+# This will only work if the methods are indeed getting or setting a simple
+# type. If this is not the case, or you want to show the methods anyway, you
+# should set this option to NO.
+# The default value is: YES.
+
+IDL_PROPERTY_SUPPORT = YES
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
+# tag is set to YES then doxygen will reuse the documentation of the first
+# member in the group (if any) for the other members of the group. By default
+# all members of a group must be documented explicitly.
+# The default value is: NO.
+
+DISTRIBUTE_GROUP_DOC = NO
+
+# Set the SUBGROUPING tag to YES to allow class member groups of the same type
+# (for instance a group of public functions) to be put as a subgroup of that
+# type (e.g. under the Public Functions section). Set it to NO to prevent
+# subgrouping. Alternatively, this can be done per class using the
+# \nosubgrouping command.
+# The default value is: YES.
+
+SUBGROUPING = YES
+
+# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions
+# are shown inside the group in which they are included (e.g. using \ingroup)
+# instead of on a separate page (for HTML and Man pages) or section (for LaTeX
+# and RTF).
+#
+# Note that this feature does not work in combination with
+# SEPARATE_MEMBER_PAGES.
+# The default value is: NO.
+
+INLINE_GROUPED_CLASSES = NO
+
+# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions
+# with only public data fields or simple typedef fields will be shown inline in
+# the documentation of the scope in which they are defined (i.e. file,
+# namespace, or group documentation), provided this scope is documented. If set
+# to NO, structs, classes, and unions are shown on a separate page (for HTML and
+# Man pages) or section (for LaTeX and RTF).
+# The default value is: NO.
+
+INLINE_SIMPLE_STRUCTS = NO
+
+# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or
+# enum is documented as struct, union, or enum with the name of the typedef. So
+# typedef struct TypeS {} TypeT, will appear in the documentation as a struct
+# with name TypeT. When disabled the typedef will appear as a member of a file,
+# namespace, or class. And the struct will be named TypeS. This can typically be
+# useful for C code in case the coding convention dictates that all compound
+# types are typedef'ed and only the typedef is referenced, never the tag name.
+# The default value is: NO.
+
+TYPEDEF_HIDES_STRUCT = NO
+
+# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This
+# cache is used to resolve symbols given their name and scope. Since this can be
+# an expensive process and often the same symbol appears multiple times in the
+# code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small
+# doxygen will become slower. If the cache is too large, memory is wasted. The
+# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range
+# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536
+# symbols. At the end of a run doxygen will report the cache usage and suggest
+# the optimal cache size from a speed point of view.
+# Minimum value: 0, maximum value: 9, default value: 0.
+
+LOOKUP_CACHE_SIZE = 0
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# If the EXTRACT_ALL tag is set to YES, doxygen will assume all entities in
+# documentation are documented, even if no documentation was available. Private
+# class members and static file members will be hidden unless the
+# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES.
+# Note: This will also disable the warnings about undocumented members that are
+# normally produced when WARNINGS is set to YES.
+# The default value is: NO.
+
+EXTRACT_ALL = NO
+
+# If the EXTRACT_PRIVATE tag is set to YES, all private members of a class will
+# be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PRIVATE = NO
+
+# If the EXTRACT_PACKAGE tag is set to YES, all members with package or internal
+# scope will be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PACKAGE = NO
+
+# If the EXTRACT_STATIC tag is set to YES, all static members of a file will be
+# included in the documentation.
+# The default value is: NO.
+
+EXTRACT_STATIC = NO
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES, classes (and structs) defined
+# locally in source files will be included in the documentation. If set to NO,
+# only classes defined in header files are included. Does not have any effect
+# for Java sources.
+# The default value is: YES.
+
+EXTRACT_LOCAL_CLASSES = YES
+
+# This flag is only useful for Objective-C code. If set to YES, local methods,
+# which are defined in the implementation section but not in the interface are
+# included in the documentation. If set to NO, only methods in the interface are
+# included.
+# The default value is: NO.
+
+EXTRACT_LOCAL_METHODS = NO
+
+# If this flag is set to YES, the members of anonymous namespaces will be
+# extracted and appear in the documentation as a namespace called
+# 'anonymous_namespace{file}', where file will be replaced with the base name of
+# the file that contains the anonymous namespace. By default anonymous namespace
+# are hidden.
+# The default value is: NO.
+
+EXTRACT_ANON_NSPACES = NO
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all
+# undocumented members inside documented classes or files. If set to NO these
+# members will be included in the various overviews, but no documentation
+# section is generated. This option has no effect if EXTRACT_ALL is enabled.
+# The default value is: NO.
+
+HIDE_UNDOC_MEMBERS = NO
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all
+# undocumented classes that are normally visible in the class hierarchy. If set
+# to NO, these classes will be included in the various overviews. This option
+# has no effect if EXTRACT_ALL is enabled.
+# The default value is: NO.
+
+HIDE_UNDOC_CLASSES = NO
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend
+# (class|struct|union) declarations. If set to NO, these declarations will be
+# included in the documentation.
+# The default value is: NO.
+
+HIDE_FRIEND_COMPOUNDS = NO
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any
+# documentation blocks found inside the body of a function. If set to NO, these
+# blocks will be appended to the function's detailed documentation block.
+# The default value is: NO.
+
+HIDE_IN_BODY_DOCS = NO
+
+# The INTERNAL_DOCS tag determines if documentation that is typed after a
+# \internal command is included. If the tag is set to NO then the documentation
+# will be excluded. Set it to YES to include the internal documentation.
+# The default value is: NO.
+
+INTERNAL_DOCS = NO
+
+# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file
+# names in lower-case letters. If set to YES, upper-case letters are also
+# allowed. This is useful if you have classes or files whose names only differ
+# in case and if your file system supports case sensitive file names. Windows
+# and Mac users are advised to set this option to NO.
+# The default value is: system dependent.
+
+CASE_SENSE_NAMES = NO
+
+# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with
+# their full class and namespace scopes in the documentation. If set to YES, the
+# scope will be hidden.
+# The default value is: NO.
+
+HIDE_SCOPE_NAMES = NO
+
+# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of
+# the files that are included by a file in the documentation of that file.
+# The default value is: YES.
+
+SHOW_INCLUDE_FILES = YES
+
+# If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each
+# grouped member an include statement to the documentation, telling the reader
+# which file to include in order to use the member.
+# The default value is: NO.
+
+SHOW_GROUPED_MEMB_INC = NO
+
+# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include
+# files with double quotes in the documentation rather than with sharp brackets.
+# The default value is: NO.
+
+FORCE_LOCAL_INCLUDES = NO
+
+# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the
+# documentation for inline members.
+# The default value is: YES.
+
+INLINE_INFO = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the
+# (detailed) documentation of file and class members alphabetically by member
+# name. If set to NO, the members will appear in declaration order.
+# The default value is: YES.
+
+SORT_MEMBER_DOCS = YES
+
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief
+# descriptions of file, namespace and class members alphabetically by member
+# name. If set to NO, the members will appear in declaration order. Note that
+# this will also influence the order of the classes in the class list.
+# The default value is: NO.
+
+SORT_BRIEF_DOCS = NO
+
+# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the
+# (brief and detailed) documentation of class members so that constructors and
+# destructors are listed first. If set to NO the constructors will appear in the
+# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS.
+# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief
+# member documentation.
+# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting
+# detailed member documentation.
+# The default value is: NO.
+
+SORT_MEMBERS_CTORS_1ST = NO
+
+# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy
+# of group names into alphabetical order. If set to NO the group names will
+# appear in their defined order.
+# The default value is: NO.
+
+SORT_GROUP_NAMES = NO
+
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by
+# fully-qualified names, including namespaces. If set to NO, the class list will
+# be sorted only by class name, not including the namespace part.
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
+# Note: This option applies only to the class list, not to the alphabetical
+# list.
+# The default value is: NO.
+
+SORT_BY_SCOPE_NAME = NO
+
+# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper
+# type resolution of all parameters of a function it will reject a match between
+# the prototype and the implementation of a member function even if there is
+# only one candidate or it is obvious which candidate to choose by doing a
+# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still
+# accept a match between prototype and implementation in such cases.
+# The default value is: NO.
+
+STRICT_PROTO_MATCHING = NO
+
+# The GENERATE_TODOLIST tag can be used to enable (YES) or disable (NO) the todo
+# list. This list is created by putting \todo commands in the documentation.
+# The default value is: YES.
+
+GENERATE_TODOLIST = YES
+
+# The GENERATE_TESTLIST tag can be used to enable (YES) or disable (NO) the test
+# list. This list is created by putting \test commands in the documentation.
+# The default value is: YES.
+
+GENERATE_TESTLIST = YES
+
+# The GENERATE_BUGLIST tag can be used to enable (YES) or disable (NO) the bug
+# list. This list is created by putting \bug commands in the documentation.
+# The default value is: YES.
+
+GENERATE_BUGLIST = YES
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or disable (NO)
+# the deprecated list. This list is created by putting \deprecated commands in
+# the documentation.
+# The default value is: YES.
+
+GENERATE_DEPRECATEDLIST= YES
+
+# The ENABLED_SECTIONS tag can be used to enable conditional documentation
+# sections, marked by \if <section_label> ... \endif and \cond <section_label>
+# ... \endcond blocks.
+
+ENABLED_SECTIONS =
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the
+# initial value of a variable or macro / define can have for it to appear in the
+# documentation. If the initializer consists of more lines than specified here
+# it will be hidden. Use a value of 0 to hide initializers completely. The
+# appearance of the value of individual variables and macros / defines can be
+# controlled using \showinitializer or \hideinitializer command in the
+# documentation regardless of this setting.
+# Minimum value: 0, maximum value: 10000, default value: 30.
+
+MAX_INITIALIZER_LINES = 30
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at
+# the bottom of the documentation of classes and structs. If set to YES, the
+# list will mention the files that were used to generate the documentation.
+# The default value is: YES.
+
+SHOW_USED_FILES = YES
+
+# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This
+# will remove the Files entry from the Quick Index and from the Folder Tree View
+# (if specified).
+# The default value is: YES.
+
+SHOW_FILES = YES
+
+# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces
+# page. This will remove the Namespaces entry from the Quick Index and from the
+# Folder Tree View (if specified).
+# The default value is: YES.
+
+SHOW_NAMESPACES = YES
+
+# The FILE_VERSION_FILTER tag can be used to specify a program or script that
+# doxygen should invoke to get the current version for each file (typically from
+# the version control system). Doxygen will invoke the program by executing (via
+# popen()) the command command input-file, where command is the value of the
+# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided
+# by doxygen. Whatever the program writes to standard output is used as the file
+# version. For an example see the documentation.
+
+FILE_VERSION_FILTER =
+
+# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed
+# by doxygen. The layout file controls the global structure of the generated
+# output files in an output format independent way. To create the layout file
+# that represents doxygen's defaults, run doxygen with the -l option. You can
+# optionally specify a file name after the option, if omitted DoxygenLayout.xml
+# will be used as the name of the layout file.
+#
+# Note that if you run doxygen from a directory containing a file called
+# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE
+# tag is left empty.
+
+LAYOUT_FILE =
+
+# The CITE_BIB_FILES tag can be used to specify one or more bib files containing
+# the reference definitions. This must be a list of .bib files. The .bib
+# extension is automatically appended if omitted. This requires the bibtex tool
+# to be installed. See also http://en.wikipedia.org/wiki/BibTeX for more info.
+# For LaTeX the style of the bibliography can be controlled using
+# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the
+# search path. See also \cite for info how to create references.
+
+CITE_BIB_FILES =
+
+#---------------------------------------------------------------------------
+# Configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated to
+# standard output by doxygen. If QUIET is set to YES this implies that the
+# messages are off.
+# The default value is: NO.
+
+QUIET = NO
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are
+# generated to standard error (stderr) by doxygen. If WARNINGS is set to YES
+# this implies that the warnings are on.
+#
+# Tip: Turn warnings on while writing the documentation.
+# The default value is: YES.
+
+WARNINGS = YES
+
+# If the WARN_IF_UNDOCUMENTED tag is set to YES then doxygen will generate
+# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag
+# will automatically be disabled.
+# The default value is: YES.
+
+WARN_IF_UNDOCUMENTED = YES
+
+# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for
+# potential errors in the documentation, such as not documenting some parameters
+# in a documented function, or documenting parameters that don't exist or using
+# markup commands wrongly.
+# The default value is: YES.
+
+WARN_IF_DOC_ERROR = YES
+
+# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that
+# are documented, but have no documentation for their parameters or return
+# value. If set to NO, doxygen will only warn about wrong or incomplete
+# parameter documentation, but not about the absence of documentation.
+# The default value is: NO.
+
+WARN_NO_PARAMDOC = NO
+
+# The WARN_FORMAT tag determines the format of the warning messages that doxygen
+# can produce. The string should contain the $file, $line, and $text tags, which
+# will be replaced by the file and line number from which the warning originated
+# and the warning text. Optionally the format may contain $version, which will
+# be replaced by the version of the file (if it could be obtained via
+# FILE_VERSION_FILTER)
+# The default value is: $file:$line: $text.
+
+WARN_FORMAT = "$file:$line: $text"
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning and error
+# messages should be written. If left blank the output is written to standard
+# error (stderr).
+
+WARN_LOGFILE =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag is used to specify the files and/or directories that contain
+# documented source files. You may enter file names like myfile.cpp or
+# directories like /usr/src/myproject. Separate the files or directories with
+# spaces.
+# Note: If this tag is empty the current directory is searched.
+
+INPUT = src
+
+# This tag can be used to specify the character encoding of the source files
+# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
+# libiconv (or the iconv built into libc) for the transcoding. See the libiconv
+# documentation (see: http://www.gnu.org/software/libiconv) for the list of
+# possible encodings.
+# The default value is: UTF-8.
+
+INPUT_ENCODING = UTF-8
+
+# If the value of the INPUT tag contains directories, you can use the
+# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and
+# *.h) to filter out the source-files in the directories. If left blank the
+# following patterns are tested:*.c, *.cc, *.cxx, *.cpp, *.c++, *.java, *.ii,
+# *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, *.hh, *.hxx, *.hpp,
+# *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, *.m, *.markdown,
+# *.md, *.mm, *.dox, *.py, *.f90, *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf,
+# *.qsf, *.as and *.js.
+
+FILE_PATTERNS = *.c \
+ *.cc \
+ *.cxx \
+ *.cpp \
+ *.c++ \
+ *.java \
+ *.ii \
+ *.ixx \
+ *.ipp \
+ *.i++ \
+ *.inl \
+ *.idl \
+ *.ddl \
+ *.odl \
+ *.h \
+ *.hh \
+ *.hxx \
+ *.hpp \
+ *.h++ \
+ *.cs \
+ *.d \
+ *.php \
+ *.php4 \
+ *.php5 \
+ *.phtml \
+ *.inc \
+ *.m \
+ *.markdown \
+ *.md \
+ *.mm \
+ *.dox \
+ *.py \
+ *.f90 \
+ *.f \
+ *.for \
+ *.tcl \
+ *.vhd \
+ *.vhdl \
+ *.ucf \
+ *.qsf \
+ *.as \
+ *.js
+
+# The RECURSIVE tag can be used to specify whether or not subdirectories should
+# be searched for input files as well.
+# The default value is: NO.
+
+RECURSIVE = YES
+
+# The EXCLUDE tag can be used to specify files and/or directories that should be
+# excluded from the INPUT source files. This way you can easily exclude a
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+#
+# Note that relative paths are relative to the directory from which doxygen is
+# run.
+
+EXCLUDE =
+
+# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or
+# directories that are symbolic links (a Unix file system feature) are excluded
+# from the input.
+# The default value is: NO.
+
+EXCLUDE_SYMLINKS = NO
+
+# If the value of the INPUT tag contains directories, you can use the
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
+# certain files from those directories.
+#
+# Note that the wildcards are matched against the file with absolute path, so to
+# exclude all test directories for example use the pattern */test/*
+
+EXCLUDE_PATTERNS =
+
+# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
+# (namespaces, classes, functions, etc.) that should be excluded from the
+# output. The symbol name can be a fully qualified name, a word, or if the
+# wildcard * is used, a substring. Examples: ANamespace, AClass,
+# AClass::ANamespace, ANamespace::*Test
+#
+# Note that the wildcards are matched against the file with absolute path, so to
+# exclude all test directories use the pattern */test/*
+
+EXCLUDE_SYMBOLS =
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or directories
+# that contain example code fragments that are included (see the \include
+# command).
+
+EXAMPLE_PATH =
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and
+# *.h) to filter out the source-files in the directories. If left blank all
+# files are included.
+
+EXAMPLE_PATTERNS = *
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
+# searched for input files to be used with the \include or \dontinclude commands
+# irrespective of the value of the RECURSIVE tag.
+# The default value is: NO.
+
+EXAMPLE_RECURSIVE = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or directories
+# that contain images that are to be included in the documentation (see the
+# \image command).
+
+IMAGE_PATH =
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should
+# invoke to filter for each input file. Doxygen will invoke the filter program
+# by executing (via popen()) the command:
+#
+# <filter> <input-file>
+#
+# where <filter> is the value of the INPUT_FILTER tag, and <input-file> is the
+# name of an input file. Doxygen will then use the output that the filter
+# program writes to standard output. If FILTER_PATTERNS is specified, this tag
+# will be ignored.
+#
+# Note that the filter must not add or remove lines; it is applied before the
+# code is scanned, but not when the output code is generated. If lines are added
+# or removed, the anchors will not be placed correctly.
+
+INPUT_FILTER =
+
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
+# basis. Doxygen will compare the file name with each pattern and apply the
+# filter if there is a match. The filters are a list of the form: pattern=filter
+# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how
+# filters are used. If the FILTER_PATTERNS tag is empty or if none of the
+# patterns match the file name, INPUT_FILTER is applied.
+
+FILTER_PATTERNS =
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
+# INPUT_FILTER) will also be used to filter the input files that are used for
+# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES).
+# The default value is: NO.
+
+FILTER_SOURCE_FILES = NO
+
+# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file
+# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and
+# it is also possible to disable source filtering for a specific pattern using
+# *.ext= (so without naming a filter).
+# This tag requires that the tag FILTER_SOURCE_FILES is set to YES.
+
+FILTER_SOURCE_PATTERNS =
+
+# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that
+# is part of the input, its contents will be placed on the main page
+# (index.html). This can be useful if you have a project on for instance GitHub
+# and want to reuse the introduction page also for the doxygen output.
+
+USE_MDFILE_AS_MAINPAGE =
+
+#---------------------------------------------------------------------------
+# Configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will be
+# generated. Documented entities will be cross-referenced with these sources.
+#
+# Note: To get rid of all source code in the generated output, make sure that
+# also VERBATIM_HEADERS is set to NO.
+# The default value is: NO.
+
+SOURCE_BROWSER = NO
+
+# Setting the INLINE_SOURCES tag to YES will include the body of functions,
+# classes and enums directly into the documentation.
+# The default value is: NO.
+
+INLINE_SOURCES = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any
+# special comment blocks from generated source code fragments. Normal C, C++ and
+# Fortran comments will always remain visible.
+# The default value is: YES.
+
+STRIP_CODE_COMMENTS = YES
+
+# If the REFERENCED_BY_RELATION tag is set to YES then for each documented
+# function all documented functions referencing it will be listed.
+# The default value is: NO.
+
+REFERENCED_BY_RELATION = NO
+
+# If the REFERENCES_RELATION tag is set to YES then for each documented function
+# all documented entities called/used by that function will be listed.
+# The default value is: NO.
+
+REFERENCES_RELATION = NO
+
+# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set
+# to YES then the hyperlinks from functions in REFERENCES_RELATION and
+# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will
+# link to the documentation.
+# The default value is: YES.
+
+REFERENCES_LINK_SOURCE = YES
+
+# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the
+# source code will show a tooltip with additional information such as prototype,
+# brief description and links to the definition and documentation. Since this
+# will make the HTML file larger and loading of large files a bit slower, you
+# can opt to disable this feature.
+# The default value is: YES.
+# This tag requires that the tag SOURCE_BROWSER is set to YES.
+
+SOURCE_TOOLTIPS = YES
+
+# If the USE_HTAGS tag is set to YES then the references to source code will
+# point to the HTML generated by the htags(1) tool instead of doxygen built-in
+# source browser. The htags tool is part of GNU's global source tagging system
+# (see http://www.gnu.org/software/global/global.html). You will need version
+# 4.8.6 or higher.
+#
+# To use it do the following:
+# - Install the latest version of global
+# - Enable SOURCE_BROWSER and USE_HTAGS in the config file
+# - Make sure the INPUT points to the root of the source tree
+# - Run doxygen as normal
+#
+# Doxygen will invoke htags (and that will in turn invoke gtags), so these
+# tools must be available from the command line (i.e. in the search path).
+#
+# The result: instead of the source browser generated by doxygen, the links to
+# source code will now point to the output of htags.
+# The default value is: NO.
+# This tag requires that the tag SOURCE_BROWSER is set to YES.
+
+USE_HTAGS = NO
+
+# If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a
+# verbatim copy of the header file for each class for which an include is
+# specified. Set to NO to disable this.
+# See also: Section \class.
+# The default value is: YES.
+
+VERBATIM_HEADERS = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all
+# compounds will be generated. Enable this if the project contains a lot of
+# classes, structs, unions or interfaces.
+# The default value is: YES.
+
+ALPHABETICAL_INDEX = YES
+
+# The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in
+# which the alphabetical index list will be split.
+# Minimum value: 1, maximum value: 20, default value: 5.
+# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
+
+COLS_IN_ALPHA_INDEX = 5
+
+# In case all classes in a project start with a common prefix, all classes will
+# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag
+# can be used to specify a prefix (or a list of prefixes) that should be ignored
+# while generating the index headers.
+# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
+
+IGNORE_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES, doxygen will generate HTML output
+# The default value is: YES.
+
+GENERATE_HTML = NO
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: html.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_OUTPUT = html
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each
+# generated HTML page (for example: .htm, .php, .asp).
+# The default value is: .html.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_FILE_EXTENSION = .html
+
+# The HTML_HEADER tag can be used to specify a user-defined HTML header file for
+# each generated HTML page. If the tag is left blank doxygen will generate a
+# standard header.
+#
+# To get valid HTML the header file that includes any scripts and style sheets
+# that doxygen needs, which is dependent on the configuration options used (e.g.
+# the setting GENERATE_TREEVIEW). It is highly recommended to start with a
+# default header using
+# doxygen -w html new_header.html new_footer.html new_stylesheet.css
+# YourConfigFile
+# and then modify the file new_header.html. See also section "Doxygen usage"
+# for information on how to generate the default header that doxygen normally
+# uses.
+# Note: The header is subject to change so you typically have to regenerate the
+# default header when upgrading to a newer version of doxygen. For a description
+# of the possible markers and block names see the documentation.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_HEADER =
+
+# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each
+# generated HTML page. If the tag is left blank doxygen will generate a standard
+# footer. See HTML_HEADER for more information on how to generate a default
+# footer and what special commands can be used inside the footer. See also
+# section "Doxygen usage" for information on how to generate the default footer
+# that doxygen normally uses.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_FOOTER =
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style
+# sheet that is used by each HTML page. It can be used to fine-tune the look of
+# the HTML output. If left blank doxygen will generate a default style sheet.
+# See also section "Doxygen usage" for information on how to generate the style
+# sheet that doxygen normally uses.
+# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as
+# it is more robust and this tag (HTML_STYLESHEET) will in the future become
+# obsolete.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_STYLESHEET =
+
+# The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined
+# cascading style sheets that are included after the standard style sheets
+# created by doxygen. Using this option one can overrule certain style aspects.
+# This is preferred over using HTML_STYLESHEET since it does not replace the
+# standard style sheet and is therefore more robust against future updates.
+# Doxygen will copy the style sheet files to the output directory.
+# Note: The order of the extra stylesheet files is of importance (e.g. the last
+# stylesheet in the list overrules the setting of the previous ones in the
+# list). For an example see the documentation.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_EXTRA_STYLESHEET =
+
+# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the HTML output directory. Note
+# that these files will be copied to the base HTML output directory. Use the
+# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these
+# files. In the HTML_STYLESHEET file, use the file name only. Also note that the
+# files will be copied as-is; there are no commands or markers available.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_EXTRA_FILES =
+
+# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen
+# will adjust the colors in the stylesheet and background images according to
+# this color. Hue is specified as an angle on a colorwheel, see
+# http://en.wikipedia.org/wiki/Hue for more information. For instance the value
+# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300
+# purple, and 360 is red again.
+# Minimum value: 0, maximum value: 359, default value: 220.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_HUE = 220
+
+# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors
+# in the HTML output. For a value of 0 the output will use grayscales only. A
+# value of 255 will produce the most vivid colors.
+# Minimum value: 0, maximum value: 255, default value: 100.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_SAT = 100
+
+# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the
+# luminance component of the colors in the HTML output. Values below 100
+# gradually make the output lighter, whereas values above 100 make the output
+# darker. The value divided by 100 is the actual gamma applied, so 80 represents
+# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not
+# change the gamma.
+# Minimum value: 40, maximum value: 240, default value: 80.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_GAMMA = 80
+
+# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML
+# page will contain the date and time when the page was generated. Setting this
+# to NO can help when comparing the output of multiple runs.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_TIMESTAMP = YES
+
+# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
+# documentation will contain sections that can be hidden and shown after the
+# page has loaded.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_DYNAMIC_SECTIONS = NO
+
+# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries
+# shown in the various tree structured indices initially; the user can expand
+# and collapse entries dynamically later on. Doxygen will expand the tree to
+# such a level that at most the specified number of entries are visible (unless
+# a fully collapsed tree already exceeds this amount). So setting the number of
+# entries 1 will produce a full collapsed tree by default. 0 is a special value
+# representing an infinite number of entries and will result in a full expanded
+# tree by default.
+# Minimum value: 0, maximum value: 9999, default value: 100.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_INDEX_NUM_ENTRIES = 100
+
+# If the GENERATE_DOCSET tag is set to YES, additional index files will be
+# generated that can be used as input for Apple's Xcode 3 integrated development
+# environment (see: http://developer.apple.com/tools/xcode/), introduced with
+# OSX 10.5 (Leopard). To create a documentation set, doxygen will generate a
+# Makefile in the HTML output directory. Running make will produce the docset in
+# that directory and running make install will install the docset in
+# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at
+# startup. See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html
+# for more information.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_DOCSET = NO
+
+# This tag determines the name of the docset feed. A documentation feed provides
+# an umbrella under which multiple documentation sets from a single provider
+# (such as a company or product suite) can be grouped.
+# The default value is: Doxygen generated docs.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_FEEDNAME = "Doxygen generated docs"
+
+# This tag specifies a string that should uniquely identify the documentation
+# set bundle. This should be a reverse domain-name style string, e.g.
+# com.mycompany.MyDocSet. Doxygen will append .docset to the name.
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_BUNDLE_ID = org.doxygen.Project
+
+# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify
+# the documentation publisher. This should be a reverse domain-name style
+# string, e.g. com.mycompany.MyDocSet.documentation.
+# The default value is: org.doxygen.Publisher.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_PUBLISHER_ID = org.doxygen.Publisher
+
+# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher.
+# The default value is: Publisher.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_PUBLISHER_NAME = Publisher
+
+# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three
+# additional HTML index files: index.hhp, index.hhc, and index.hhk. The
+# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop
+# (see: http://www.microsoft.com/en-us/download/details.aspx?id=21138) on
+# Windows.
+#
+# The HTML Help Workshop contains a compiler that can convert all HTML output
+# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML
+# files are now used as the Windows 98 help format, and will replace the old
+# Windows help format (.hlp) on all Windows platforms in the future. Compressed
+# HTML files also contain an index, a table of contents, and you can search for
+# words in the documentation. The HTML workshop also contains a viewer for
+# compressed HTML files.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_HTMLHELP = NO
+
+# The CHM_FILE tag can be used to specify the file name of the resulting .chm
+# file. You can add a path in front of the file if the result should not be
+# written to the html output directory.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+CHM_FILE =
+
+# The HHC_LOCATION tag can be used to specify the location (absolute path
+# including file name) of the HTML help compiler (hhc.exe). If non-empty,
+# doxygen will try to run the HTML help compiler on the generated index.hhp.
+# The file has to be specified with full path.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+HHC_LOCATION =
+
+# The GENERATE_CHI flag controls if a separate .chi index file is generated
+# (YES) or that it should be included in the master .chm file (NO).
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+GENERATE_CHI = NO
+
+# The CHM_INDEX_ENCODING is used to encode HtmlHelp index (hhk), content (hhc)
+# and project file content.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+CHM_INDEX_ENCODING =
+
+# The BINARY_TOC flag controls whether a binary table of contents is generated
+# (YES) or a normal table of contents (NO) in the .chm file. Furthermore it
+# enables the Previous and Next buttons.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+BINARY_TOC = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members to
+# the table of contents of the HTML help documentation and to the tree view.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+TOC_EXPAND = NO
+
+# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and
+# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that
+# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help
+# (.qch) of the generated HTML documentation.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_QHP = NO
+
+# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify
+# the file name of the resulting .qch file. The path specified is relative to
+# the HTML output folder.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QCH_FILE =
+
+# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help
+# Project output. For more information please see Qt Help Project / Namespace
+# (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#namespace).
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_NAMESPACE = org.doxygen.Project
+
+# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt
+# Help Project output. For more information please see Qt Help Project / Virtual
+# Folders (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#virtual-
+# folders).
+# The default value is: doc.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_VIRTUAL_FOLDER = doc
+
+# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom
+# filter to add. For more information please see Qt Help Project / Custom
+# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-
+# filters).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_CUST_FILTER_NAME =
+
+# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the
+# custom filter to add. For more information please see Qt Help Project / Custom
+# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-
+# filters).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_CUST_FILTER_ATTRS =
+
+# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this
+# project's filter section matches. Qt Help Project / Filter Attributes (see:
+# http://qt-project.org/doc/qt-4.8/qthelpproject.html#filter-attributes).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_SECT_FILTER_ATTRS =
+
+# The QHG_LOCATION tag can be used to specify the location of Qt's
+# qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the
+# generated .qhp file.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHG_LOCATION =
+
+# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be
+# generated, together with the HTML files, they form an Eclipse help plugin. To
+# install this plugin and make it available under the help contents menu in
+# Eclipse, the contents of the directory containing the HTML and XML files needs
+# to be copied into the plugins directory of eclipse. The name of the directory
+# within the plugins directory should be the same as the ECLIPSE_DOC_ID value.
+# After copying Eclipse needs to be restarted before the help appears.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_ECLIPSEHELP = NO
+
+# A unique identifier for the Eclipse help plugin. When installing the plugin
+# the directory name containing the HTML and XML files should also have this
+# name. Each documentation set should have its own identifier.
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES.
+
+ECLIPSE_DOC_ID = org.doxygen.Project
+
+# If you want full control over the layout of the generated HTML pages it might
+# be necessary to disable the index and replace it with your own. The
+# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top
+# of each HTML page. A value of NO enables the index and the value YES disables
+# it. Since the tabs in the index contain the same information as the navigation
+# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+DISABLE_INDEX = NO
+
+# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
+# structure should be generated to display hierarchical information. If the tag
+# value is set to YES, a side panel will be generated containing a tree-like
+# index structure (just like the one that is generated for HTML Help). For this
+# to work a browser that supports JavaScript, DHTML, CSS and frames is required
+# (i.e. any modern browser). Windows users are probably better off using the
+# HTML help feature. Via custom stylesheets (see HTML_EXTRA_STYLESHEET) one can
+# further fine-tune the look of the index. As an example, the default style
+# sheet generated by doxygen has an example that shows how to put an image at
+# the root of the tree instead of the PROJECT_NAME. Since the tree basically has
+# the same information as the tab index, you could consider setting
+# DISABLE_INDEX to YES when enabling this option.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_TREEVIEW = NO
+
+# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that
+# doxygen will group on one line in the generated HTML documentation.
+#
+# Note that a value of 0 will completely suppress the enum values from appearing
+# in the overview section.
+# Minimum value: 0, maximum value: 20, default value: 4.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+ENUM_VALUES_PER_LINE = 4
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used
+# to set the initial width (in pixels) of the frame in which the tree is shown.
+# Minimum value: 0, maximum value: 1500, default value: 250.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+TREEVIEW_WIDTH = 250
+
+# If the EXT_LINKS_IN_WINDOW option is set to YES, doxygen will open links to
+# external symbols imported via tag files in a separate window.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+EXT_LINKS_IN_WINDOW = NO
+
+# Use this tag to change the font size of LaTeX formulas included as images in
+# the HTML documentation. When you change the font size after a successful
+# doxygen run you need to manually remove any form_*.png images from the HTML
+# output directory to force them to be regenerated.
+# Minimum value: 8, maximum value: 50, default value: 10.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+FORMULA_FONTSIZE = 10
+
+# Use the FORMULA_TRANPARENT tag to determine whether or not the images
+# generated for formulas are transparent PNGs. Transparent PNGs are not
+# supported properly for IE 6.0, but are supported on all modern browsers.
+#
+# Note that when changing this option you need to delete any form_*.png files in
+# the HTML output directory before the changes have effect.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+FORMULA_TRANSPARENT = YES
+
+# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see
+# http://www.mathjax.org) which uses client side Javascript for the rendering
+# instead of using pre-rendered bitmaps. Use this if you do not have LaTeX
+# installed or if you want to formulas look prettier in the HTML output. When
+# enabled you may also need to install MathJax separately and configure the path
+# to it using the MATHJAX_RELPATH option.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+USE_MATHJAX = NO
+
+# When MathJax is enabled you can set the default output format to be used for
+# the MathJax output. See the MathJax site (see:
+# http://docs.mathjax.org/en/latest/output.html) for more details.
+# Possible values are: HTML-CSS (which is slower, but has the best
+# compatibility), NativeMML (i.e. MathML) and SVG.
+# The default value is: HTML-CSS.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_FORMAT = HTML-CSS
+
+# When MathJax is enabled you need to specify the location relative to the HTML
+# output directory using the MATHJAX_RELPATH option. The destination directory
+# should contain the MathJax.js script. For instance, if the mathjax directory
+# is located at the same level as the HTML output directory, then
+# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax
+# Content Delivery Network so you can quickly see the result without installing
+# MathJax. However, it is strongly recommended to install a local copy of
+# MathJax from http://www.mathjax.org before deployment.
+# The default value is: http://cdn.mathjax.org/mathjax/latest.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest
+
+# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax
+# extension names that should be enabled during MathJax rendering. For example
+# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_EXTENSIONS =
+
+# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces
+# of code that will be used on startup of the MathJax code. See the MathJax site
+# (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an
+# example see the documentation.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_CODEFILE =
+
+# When the SEARCHENGINE tag is enabled doxygen will generate a search box for
+# the HTML output. The underlying search engine uses javascript and DHTML and
+# should work on any modern browser. Note that when using HTML help
+# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET)
+# there is already a search function so this one should typically be disabled.
+# For large projects the javascript based search engine can be slow, then
+# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to
+# search using the keyboard; to jump to the search box use <access key> + S
+# (what the <access key> is depends on the OS and browser, but it is typically
+# <CTRL>, <ALT>/<option>, or both). Inside the search box use the <cursor down
+# key> to jump into the search results window, the results can be navigated
+# using the <cursor keys>. Press <Enter> to select an item or <escape> to cancel
+# the search. The filter options can be selected when the cursor is inside the
+# search box by pressing <Shift>+<cursor down>. Also here use the <cursor keys>
+# to select a filter and <Enter> or <escape> to activate or cancel the filter
+# option.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+SEARCHENGINE = YES
+
+# When the SERVER_BASED_SEARCH tag is enabled the search engine will be
+# implemented using a web server instead of a web client using Javascript. There
+# are two flavors of web server based searching depending on the EXTERNAL_SEARCH
+# setting. When disabled, doxygen will generate a PHP script for searching and
+# an index file used by the script. When EXTERNAL_SEARCH is enabled the indexing
+# and searching needs to be provided by external tools. See the section
+# "External Indexing and Searching" for details.
+# The default value is: NO.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SERVER_BASED_SEARCH = NO
+
+# When EXTERNAL_SEARCH tag is enabled doxygen will no longer generate the PHP
+# script for searching. Instead the search results are written to an XML file
+# which needs to be processed by an external indexer. Doxygen will invoke an
+# external search engine pointed to by the SEARCHENGINE_URL option to obtain the
+# search results.
+#
+# Doxygen ships with an example indexer (doxyindexer) and search engine
+# (doxysearch.cgi) which are based on the open source search engine library
+# Xapian (see: http://xapian.org/).
+#
+# See the section "External Indexing and Searching" for details.
+# The default value is: NO.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTERNAL_SEARCH = NO
+
+# The SEARCHENGINE_URL should point to a search engine hosted by a web server
+# which will return the search results when EXTERNAL_SEARCH is enabled.
+#
+# Doxygen ships with an example indexer (doxyindexer) and search engine
+# (doxysearch.cgi) which are based on the open source search engine library
+# Xapian (see: http://xapian.org/). See the section "External Indexing and
+# Searching" for details.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SEARCHENGINE_URL =
+
+# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the unindexed
+# search data is written to a file for indexing by an external tool. With the
+# SEARCHDATA_FILE tag the name of this file can be specified.
+# The default file is: searchdata.xml.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SEARCHDATA_FILE = searchdata.xml
+
+# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the
+# EXTERNAL_SEARCH_ID tag can be used as an identifier for the project. This is
+# useful in combination with EXTRA_SEARCH_MAPPINGS to search through multiple
+# projects and redirect the results back to the right project.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTERNAL_SEARCH_ID =
+
+# The EXTRA_SEARCH_MAPPINGS tag can be used to enable searching through doxygen
+# projects other than the one defined by this configuration file, but that are
+# all added to the same external search index. Each project needs to have a
+# unique id set via EXTERNAL_SEARCH_ID. The search mapping then maps the id of
+# to a relative location where the documentation can be found. The format is:
+# EXTRA_SEARCH_MAPPINGS = tagname1=loc1 tagname2=loc2 ...
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTRA_SEARCH_MAPPINGS =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES, doxygen will generate LaTeX output.
+# The default value is: YES.
+
+GENERATE_LATEX = NO
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: latex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_OUTPUT = latex
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
+# invoked.
+#
+# Note that when enabling USE_PDFLATEX this option is only used for generating
+# bitmaps for formulas in the HTML output, but not in the Makefile that is
+# written to the output directory.
+# The default file is: latex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_CMD_NAME = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to generate
+# index for LaTeX.
+# The default file is: makeindex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+MAKEINDEX_CMD_NAME = makeindex
+
+# If the COMPACT_LATEX tag is set to YES, doxygen generates more compact LaTeX
+# documents. This may be useful for small projects and may help to save some
+# trees in general.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+COMPACT_LATEX = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used by the
+# printer.
+# Possible values are: a4 (210 x 297 mm), letter (8.5 x 11 inches), legal (8.5 x
+# 14 inches) and executive (7.25 x 10.5 inches).
+# The default value is: a4.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+PAPER_TYPE = a4
+
+# The EXTRA_PACKAGES tag can be used to specify one or more LaTeX package names
+# that should be included in the LaTeX output. To get the times font for
+# instance you can specify
+# EXTRA_PACKAGES=times
+# If left blank no extra packages will be included.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+EXTRA_PACKAGES =
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for the
+# generated LaTeX document. The header should contain everything until the first
+# chapter. If it is left blank doxygen will generate a standard header. See
+# section "Doxygen usage" for information on how to let doxygen write the
+# default header to a separate file.
+#
+# Note: Only use a user-defined header if you know what you are doing! The
+# following commands have a special meaning inside the header: $title,
+# $datetime, $date, $doxygenversion, $projectname, $projectnumber,
+# $projectbrief, $projectlogo. Doxygen will replace $title with the empty
+# string, for the replacement values of the other commands the user is referred
+# to HTML_HEADER.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_HEADER =
+
+# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for the
+# generated LaTeX document. The footer should contain everything after the last
+# chapter. If it is left blank doxygen will generate a standard footer. See
+# LATEX_HEADER for more information on how to generate a default footer and what
+# special commands can be used inside the footer.
+#
+# Note: Only use a user-defined footer if you know what you are doing!
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_FOOTER =
+
+# The LATEX_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the LATEX_OUTPUT output
+# directory. Note that the files will be copied as-is; there are no commands or
+# markers available.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_EXTRA_FILES =
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated is
+# prepared for conversion to PDF (using ps2pdf or pdflatex). The PDF file will
+# contain links (just like the HTML output) instead of page references. This
+# makes the output suitable for online browsing using a PDF viewer.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+PDF_HYPERLINKS = YES
+
+# If the USE_PDFLATEX tag is set to YES, doxygen will use pdflatex to generate
+# the PDF file directly from the LaTeX files. Set this option to YES, to get a
+# higher quality PDF documentation.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+USE_PDFLATEX = YES
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \batchmode
+# command to the generated LaTeX files. This will instruct LaTeX to keep running
+# if errors occur, instead of asking the user for help. This option is also used
+# when generating formulas in HTML.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_BATCHMODE = NO
+
+# If the LATEX_HIDE_INDICES tag is set to YES then doxygen will not include the
+# index chapters (such as File Index, Compound Index, etc.) in the output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_HIDE_INDICES = NO
+
+# If the LATEX_SOURCE_CODE tag is set to YES then doxygen will include source
+# code with syntax highlighting in the LaTeX output.
+#
+# Note that which sources are shown also depends on other settings such as
+# SOURCE_BROWSER.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_SOURCE_CODE = NO
+
+# The LATEX_BIB_STYLE tag can be used to specify the style to use for the
+# bibliography, e.g. plainnat, or ieeetr. See
+# http://en.wikipedia.org/wiki/BibTeX and \cite for more info.
+# The default value is: plain.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_BIB_STYLE = plain
+
+#---------------------------------------------------------------------------
+# Configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES, doxygen will generate RTF output. The
+# RTF output is optimized for Word 97 and may not look too pretty with other RTF
+# readers/editors.
+# The default value is: NO.
+
+GENERATE_RTF = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: rtf.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_OUTPUT = rtf
+
+# If the COMPACT_RTF tag is set to YES, doxygen generates more compact RTF
+# documents. This may be useful for small projects and may help to save some
+# trees in general.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+COMPACT_RTF = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated will
+# contain hyperlink fields. The RTF file will contain links (just like the HTML
+# output) instead of page references. This makes the output suitable for online
+# browsing using Word or some other Word compatible readers that support those
+# fields.
+#
+# Note: WordPad (write) and others do not support links.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_HYPERLINKS = NO
+
+# Load stylesheet definitions from file. Syntax is similar to doxygen's config
+# file, i.e. a series of assignments. You only have to provide replacements,
+# missing definitions are set to their default value.
+#
+# See also section "Doxygen usage" for information on how to generate the
+# default style sheet that doxygen normally uses.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_STYLESHEET_FILE =
+
+# Set optional variables used in the generation of an RTF document. Syntax is
+# similar to doxygen's config file. A template extensions file can be generated
+# using doxygen -e rtf extensionFile.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_EXTENSIONS_FILE =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES, doxygen will generate man pages for
+# classes and files.
+# The default value is: NO.
+
+GENERATE_MAN = NO
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it. A directory man3 will be created inside the directory specified by
+# MAN_OUTPUT.
+# The default directory is: man.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_OUTPUT = man
+
+# The MAN_EXTENSION tag determines the extension that is added to the generated
+# man pages. In case the manual section does not start with a number, the number
+# 3 is prepended. The dot (.) at the beginning of the MAN_EXTENSION tag is
+# optional.
+# The default value is: .3.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_EXTENSION = .3
+
+# The MAN_SUBDIR tag determines the name of the directory created within
+# MAN_OUTPUT in which the man pages are placed. If defaults to man followed by
+# MAN_EXTENSION with the initial . removed.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_SUBDIR =
+
+# If the MAN_LINKS tag is set to YES and doxygen generates man output, then it
+# will generate one additional man file for each entity documented in the real
+# man page(s). These additional files only source the real man page, but without
+# them the man command would be unable to find the correct page.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_LINKS = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES, doxygen will generate an XML file that
+# captures the structure of the code including all documentation.
+# The default value is: NO.
+
+GENERATE_XML = YES
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: xml.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_OUTPUT = xml
+
+# If the XML_PROGRAMLISTING tag is set to YES, doxygen will dump the program
+# listings (including syntax highlighting and cross-referencing information) to
+# the XML output. Note that enabling this will significantly increase the size
+# of the XML output.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_PROGRAMLISTING = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the DOCBOOK output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_DOCBOOK tag is set to YES, doxygen will generate Docbook files
+# that can be used to generate PDF.
+# The default value is: NO.
+
+GENERATE_DOCBOOK = NO
+
+# The DOCBOOK_OUTPUT tag is used to specify where the Docbook pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be put in
+# front of it.
+# The default directory is: docbook.
+# This tag requires that the tag GENERATE_DOCBOOK is set to YES.
+
+DOCBOOK_OUTPUT = docbook
+
+# If the DOCBOOK_PROGRAMLISTING tag is set to YES, doxygen will include the
+# program listings (including syntax highlighting and cross-referencing
+# information) to the DOCBOOK output. Note that enabling this will significantly
+# increase the size of the DOCBOOK output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_DOCBOOK is set to YES.
+
+DOCBOOK_PROGRAMLISTING = NO
+
+#---------------------------------------------------------------------------
+# Configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES, doxygen will generate an
+# AutoGen Definitions (see http://autogen.sf.net) file that captures the
+# structure of the code including all documentation. Note that this feature is
+# still experimental and incomplete at the moment.
+# The default value is: NO.
+
+GENERATE_AUTOGEN_DEF = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES, doxygen will generate a Perl module
+# file that captures the structure of the code including all documentation.
+#
+# Note that this feature is still experimental and incomplete at the moment.
+# The default value is: NO.
+
+GENERATE_PERLMOD = NO
+
+# If the PERLMOD_LATEX tag is set to YES, doxygen will generate the necessary
+# Makefile rules, Perl scripts and LaTeX code to be able to generate PDF and DVI
+# output from the Perl module output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_LATEX = NO
+
+# If the PERLMOD_PRETTY tag is set to YES, the Perl module output will be nicely
+# formatted so it can be parsed by a human reader. This is useful if you want to
+# understand what is going on. On the other hand, if this tag is set to NO, the
+# size of the Perl module output will be much smaller and Perl will parse it
+# just the same.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_PRETTY = YES
+
+# The names of the make variables in the generated doxyrules.make file are
+# prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. This is useful
+# so different doxyrules.make files included by the same Makefile don't
+# overwrite each other's variables.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_MAKEVAR_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES, doxygen will evaluate all
+# C-preprocessor directives found in the sources and include files.
+# The default value is: YES.
+
+ENABLE_PREPROCESSING = YES
+
+# If the MACRO_EXPANSION tag is set to YES, doxygen will expand all macro names
+# in the source code. If set to NO, only conditional compilation will be
+# performed. Macro expansion can be done in a controlled way by setting
+# EXPAND_ONLY_PREDEF to YES.
+# The default value is: NO.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+MACRO_EXPANSION = NO
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES then
+# the macro expansion is limited to the macros specified with the PREDEFINED and
+# EXPAND_AS_DEFINED tags.
+# The default value is: NO.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+EXPAND_ONLY_PREDEF = NO
+
+# If the SEARCH_INCLUDES tag is set to YES, the include files in the
+# INCLUDE_PATH will be searched if a #include is found.
+# The default value is: YES.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+SEARCH_INCLUDES = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that
+# contain include files that are not input files but should be processed by the
+# preprocessor.
+# This tag requires that the tag SEARCH_INCLUDES is set to YES.
+
+INCLUDE_PATH =
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
+# patterns (like *.h and *.hpp) to filter out the header-files in the
+# directories. If left blank, the patterns specified with FILE_PATTERNS will be
+# used.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+INCLUDE_FILE_PATTERNS =
+
+# The PREDEFINED tag can be used to specify one or more macro names that are
+# defined before the preprocessor is started (similar to the -D option of e.g.
+# gcc). The argument of the tag is a list of macros of the form: name or
+# name=definition (no spaces). If the definition and the "=" are omitted, "=1"
+# is assumed. To prevent a macro definition from being undefined via #undef or
+# recursively expanded use the := operator instead of the = operator.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+PREDEFINED =
+
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this
+# tag can be used to specify a list of macro names that should be expanded. The
+# macro definition that is found in the sources will be used. Use the PREDEFINED
+# tag if you want to use a different macro definition that overrules the
+# definition found in the source code.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+EXPAND_AS_DEFINED =
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES then doxygen's preprocessor will
+# remove all references to function-like macros that are alone on a line, have
+# an all uppercase name, and do not end with a semicolon. Such function macros
+# are typically used for boiler-plate code, and will confuse the parser if not
+# removed.
+# The default value is: YES.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+SKIP_FUNCTION_MACROS = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to external references
+#---------------------------------------------------------------------------
+
+# The TAGFILES tag can be used to specify one or more tag files. For each tag
+# file the location of the external documentation should be added. The format of
+# a tag file without this location is as follows:
+# TAGFILES = file1 file2 ...
+# Adding location for the tag files is done as follows:
+# TAGFILES = file1=loc1 "file2 = loc2" ...
+# where loc1 and loc2 can be relative or absolute paths or URLs. See the
+# section "Linking to external documentation" for more information about the use
+# of tag files.
+# Note: Each tag file must have a unique name (where the name does NOT include
+# the path). If a tag file is not located in the directory in which doxygen is
+# run, you must also specify the path to the tagfile here.
+
+TAGFILES =
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create a
+# tag file that is based on the input files it reads. See section "Linking to
+# external documentation" for more information about the usage of tag files.
+
+GENERATE_TAGFILE =
+
+# If the ALLEXTERNALS tag is set to YES, all external class will be listed in
+# the class index. If set to NO, only the inherited external classes will be
+# listed.
+# The default value is: NO.
+
+ALLEXTERNALS = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES, all external groups will be listed
+# in the modules index. If set to NO, only the current project's groups will be
+# listed.
+# The default value is: YES.
+
+EXTERNAL_GROUPS = YES
+
+# If the EXTERNAL_PAGES tag is set to YES, all external pages will be listed in
+# the related pages index. If set to NO, only the current project's pages will
+# be listed.
+# The default value is: YES.
+
+EXTERNAL_PAGES = YES
+
+# The PERL_PATH should be the absolute path and name of the perl script
+# interpreter (i.e. the result of 'which perl').
+# The default file (with absolute path) is: /usr/bin/perl.
+
+PERL_PATH = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES, doxygen will generate a class diagram
+# (in HTML and LaTeX) for classes with base or super classes. Setting the tag to
+# NO turns the diagrams off. Note that this option also works with HAVE_DOT
+# disabled, but it is recommended to install and use dot, since it yields more
+# powerful graphs.
+# The default value is: YES.
+
+CLASS_DIAGRAMS = YES
+
+# You can define message sequence charts within doxygen comments using the \msc
+# command. Doxygen will then run the mscgen tool (see:
+# http://www.mcternan.me.uk/mscgen/)) to produce the chart and insert it in the
+# documentation. The MSCGEN_PATH tag allows you to specify the directory where
+# the mscgen tool resides. If left empty the tool is assumed to be found in the
+# default search path.
+
+MSCGEN_PATH =
+
+# You can include diagrams made with dia in doxygen documentation. Doxygen will
+# then run dia to produce the diagram and insert it in the documentation. The
+# DIA_PATH tag allows you to specify the directory where the dia binary resides.
+# If left empty dia is assumed to be found in the default search path.
+
+DIA_PATH =
+
+# If set to YES the inheritance and collaboration graphs will hide inheritance
+# and usage relations if the target is undocumented or is not a class.
+# The default value is: YES.
+
+HIDE_UNDOC_RELATIONS = YES
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
+# available from the path. This tool is part of Graphviz (see:
+# http://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent
+# Bell Labs. The other options in this section have no effect if this option is
+# set to NO
+# The default value is: NO.
+
+HAVE_DOT = NO
+
+# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is allowed
+# to run in parallel. When set to 0 doxygen will base this on the number of
+# processors available in the system. You can set it explicitly to a value
+# larger than 0 to get control over the balance between CPU load and processing
+# speed.
+# Minimum value: 0, maximum value: 32, default value: 0.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_NUM_THREADS = 0
+
+# When you want a differently looking font in the dot files that doxygen
+# generates you can specify the font name using DOT_FONTNAME. You need to make
+# sure dot is able to find the font, which can be done by putting it in a
+# standard location or by setting the DOTFONTPATH environment variable or by
+# setting DOT_FONTPATH to the directory containing the font.
+# The default value is: Helvetica.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTNAME = Helvetica
+
+# The DOT_FONTSIZE tag can be used to set the size (in points) of the font of
+# dot graphs.
+# Minimum value: 4, maximum value: 24, default value: 10.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTSIZE = 10
+
+# By default doxygen will tell dot to use the default font as specified with
+# DOT_FONTNAME. If you specify a different font using DOT_FONTNAME you can set
+# the path where dot can find it using this tag.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTPATH =
+
+# If the CLASS_GRAPH tag is set to YES then doxygen will generate a graph for
+# each documented class showing the direct and indirect inheritance relations.
+# Setting this tag to YES will force the CLASS_DIAGRAMS tag to NO.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CLASS_GRAPH = YES
+
+# If the COLLABORATION_GRAPH tag is set to YES then doxygen will generate a
+# graph for each documented class showing the direct and indirect implementation
+# dependencies (inheritance, containment, and class references variables) of the
+# class with other documented classes.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+COLLABORATION_GRAPH = YES
+
+# If the GROUP_GRAPHS tag is set to YES then doxygen will generate a graph for
+# groups, showing the direct groups dependencies.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GROUP_GRAPHS = YES
+
+# If the UML_LOOK tag is set to YES, doxygen will generate inheritance and
+# collaboration diagrams in a style similar to the OMG's Unified Modeling
+# Language.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+UML_LOOK = NO
+
+# If the UML_LOOK tag is enabled, the fields and methods are shown inside the
+# class node. If there are many fields or methods and many nodes the graph may
+# become too big to be useful. The UML_LIMIT_NUM_FIELDS threshold limits the
+# number of items for each type to make the size more manageable. Set this to 0
+# for no limit. Note that the threshold may be exceeded by 50% before the limit
+# is enforced. So when you set the threshold to 10, up to 15 fields may appear,
+# but if the number exceeds 15, the total amount of fields shown is limited to
+# 10.
+# Minimum value: 0, maximum value: 100, default value: 10.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+UML_LIMIT_NUM_FIELDS = 10
+
+# If the TEMPLATE_RELATIONS tag is set to YES then the inheritance and
+# collaboration graphs will show the relations between templates and their
+# instances.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+TEMPLATE_RELATIONS = NO
+
+# If the INCLUDE_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are set to
+# YES then doxygen will generate a graph for each documented file showing the
+# direct and indirect include dependencies of the file with other documented
+# files.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INCLUDE_GRAPH = YES
+
+# If the INCLUDED_BY_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are
+# set to YES then doxygen will generate a graph for each documented file showing
+# the direct and indirect include dependencies of the file with other documented
+# files.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INCLUDED_BY_GRAPH = YES
+
+# If the CALL_GRAPH tag is set to YES then doxygen will generate a call
+# dependency graph for every global function or class method.
+#
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable call graphs for selected
+# functions only using the \callgraph command.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CALL_GRAPH = NO
+
+# If the CALLER_GRAPH tag is set to YES then doxygen will generate a caller
+# dependency graph for every global function or class method.
+#
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable caller graphs for selected
+# functions only using the \callergraph command.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CALLER_GRAPH = NO
+
+# If the GRAPHICAL_HIERARCHY tag is set to YES then doxygen will graphical
+# hierarchy of all classes instead of a textual one.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GRAPHICAL_HIERARCHY = YES
+
+# If the DIRECTORY_GRAPH tag is set to YES then doxygen will show the
+# dependencies a directory has on other directories in a graphical way. The
+# dependency relations are determined by the #include relations between the
+# files in the directories.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DIRECTORY_GRAPH = YES
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
+# generated by dot.
+# Note: If you choose svg you need to set HTML_FILE_EXTENSION to xhtml in order
+# to make the SVG files visible in IE 9+ (other browsers do not have this
+# requirement).
+# Possible values are: png, jpg, gif and svg.
+# The default value is: png.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_IMAGE_FORMAT = png
+
+# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to
+# enable generation of interactive SVG images that allow zooming and panning.
+#
+# Note that this requires a modern browser other than Internet Explorer. Tested
+# and working are Firefox, Chrome, Safari, and Opera.
+# Note: For IE 9+ you need to set HTML_FILE_EXTENSION to xhtml in order to make
+# the SVG files visible. Older versions of IE do not have SVG support.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INTERACTIVE_SVG = NO
+
+# The DOT_PATH tag can be used to specify the path where the dot tool can be
+# found. If left blank, it is assumed the dot tool can be found in the path.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_PATH =
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that
+# contain dot files that are included in the documentation (see the \dotfile
+# command).
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOTFILE_DIRS =
+
+# The MSCFILE_DIRS tag can be used to specify one or more directories that
+# contain msc files that are included in the documentation (see the \mscfile
+# command).
+
+MSCFILE_DIRS =
+
+# The DIAFILE_DIRS tag can be used to specify one or more directories that
+# contain dia files that are included in the documentation (see the \diafile
+# command).
+
+DIAFILE_DIRS =
+
+# When using plantuml, the PLANTUML_JAR_PATH tag should be used to specify the
+# path where java can find the plantuml.jar file. If left blank, it is assumed
+# PlantUML is not used or called during a preprocessing step. Doxygen will
+# generate a warning when it encounters a \startuml command in this case and
+# will not generate output for the diagram.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+PLANTUML_JAR_PATH =
+
+# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of nodes
+# that will be shown in the graph. If the number of nodes in a graph becomes
+# larger than this value, doxygen will truncate the graph, which is visualized
+# by representing a node as a red box. Note that doxygen if the number of direct
+# children of the root node in a graph is already larger than
+# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note that
+# the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
+# Minimum value: 0, maximum value: 10000, default value: 50.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_GRAPH_MAX_NODES = 50
+
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the graphs
+# generated by dot. A depth value of 3 means that only nodes reachable from the
+# root by following a path via at most 3 edges will be shown. Nodes that lay
+# further from the root node will be omitted. Note that setting this option to 1
+# or 2 may greatly reduce the computation time needed for large code bases. Also
+# note that the size of a graph can be further restricted by
+# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
+# Minimum value: 0, maximum value: 1000, default value: 0.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+MAX_DOT_GRAPH_DEPTH = 0
+
+# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
+# background. This is disabled by default, because dot on Windows does not seem
+# to support this out of the box.
+#
+# Warning: Depending on the platform used, enabling this option may lead to
+# badly anti-aliased labels on the edges of a graph (i.e. they become hard to
+# read).
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_TRANSPARENT = NO
+
+# Set the DOT_MULTI_TARGETS tag to YES to allow dot to generate multiple output
+# files in one run (i.e. multiple -o and -T options on the command line). This
+# makes dot run faster, but since only newer versions of dot (>1.8.10) support
+# this, this feature is disabled by default.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_MULTI_TARGETS = NO
+
+# If the GENERATE_LEGEND tag is set to YES doxygen will generate a legend page
+# explaining the meaning of the various boxes and arrows in the dot generated
+# graphs.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GENERATE_LEGEND = YES
+
+# If the DOT_CLEANUP tag is set to YES, doxygen will remove the intermediate dot
+# files that are used to generate the various graphs.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_CLEANUP = YES
--- /dev/null
+This directory contains a dummy Java project for testing purposes.
+
+To regenerate the XML output located in `xml`, run `make`. If the `Makefile`
+does not exists, you can regenerate it by running `make bootstrap` in the parent
+directory.
--- /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.
+ */
+
+/**
+ * A class in the root namespace
+ */
+class Foo {}
--- /dev/null
+<?xml version='1.0' encoding='UTF-8' standalone='no'?>
+<doxygen xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="compound.xsd" version="1.8.8">
+ <compounddef id="_foo_8java" kind="file">
+ <compoundname>Foo.java</compoundname>
+ <innerclass refid="class_foo" prot="package">Foo</innerclass>
+ <briefdescription>
+ </briefdescription>
+ <detaileddescription>
+ </detaileddescription>
+ <location file="%SOURCE_DIRECTORY%/Foo.java"/>
+ </compounddef>
+</doxygen>
--- /dev/null
+<?xml version='1.0' encoding='UTF-8' standalone='no'?>
+<doxygen xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="compound.xsd" version="1.8.8">
+ <compounddef id="class_foo" kind="class" prot="package">
+ <compoundname>Foo</compoundname>
+ <briefdescription>
+ </briefdescription>
+ <detaileddescription>
+<para>A class in the root namespace </para> </detaileddescription>
+ <location file="%SOURCE_DIRECTORY%/Foo.java" line="19" column="1" bodyfile="%SOURCE_DIRECTORY%/Foo.java" bodystart="19" bodyend="19"/>
+ <listofallmembers>
+ </listofallmembers>
+ </compounddef>
+</doxygen>
--- /dev/null
+<!-- XSLT script to combine the generated output into a single file.
+ If you have xsltproc you could use:
+ xsltproc combine.xslt index.xml >all.xml
+-->
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
+ <xsl:output method="xml" version="1.0" indent="no" standalone="yes" />
+ <xsl:template match="/">
+ <doxygen version="{doxygenindex/@version}">
+ <!-- Load all doxgen generated xml files -->
+ <xsl:for-each select="doxygenindex/compound">
+ <xsl:copy-of select="document( concat( @refid, '.xml' ) )/doxygen/*" />
+ </xsl:for-each>
+ </doxygen>
+ </xsl:template>
+</xsl:stylesheet>
--- /dev/null
+<?xml version='1.0' encoding='utf-8' ?>
+<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
+ <xsd:element name="doxygen" type="DoxygenType"/>
+
+ <!-- Complex types -->
+
+ <xsd:complexType name="DoxygenType">
+ <xsd:sequence maxOccurs="unbounded">
+ <xsd:element name="compounddef" type="compounddefType" minOccurs="0" />
+ </xsd:sequence>
+ <xsd:attribute name="version" type="DoxVersionNumber" use="required" />
+ </xsd:complexType>
+
+ <xsd:complexType name="compounddefType">
+ <xsd:sequence>
+ <xsd:element name="compoundname" type="xsd:string"/>
+ <xsd:element name="title" type="xsd:string" minOccurs="0" />
+ <xsd:element name="basecompoundref" type="compoundRefType" minOccurs="0" maxOccurs="unbounded" />
+ <xsd:element name="derivedcompoundref" type="compoundRefType" minOccurs="0" maxOccurs="unbounded" />
+ <xsd:element name="includes" type="incType" minOccurs="0" maxOccurs="unbounded" />
+ <xsd:element name="includedby" type="incType" minOccurs="0" maxOccurs="unbounded" />
+ <xsd:element name="incdepgraph" type="graphType" minOccurs="0" />
+ <xsd:element name="invincdepgraph" type="graphType" minOccurs="0" />
+ <xsd:element name="innerdir" type="refType" minOccurs="0" maxOccurs="unbounded" />
+ <xsd:element name="innerfile" type="refType" minOccurs="0" maxOccurs="unbounded" />
+ <xsd:element name="innerclass" type="refType" minOccurs="0" maxOccurs="unbounded" />
+ <xsd:element name="innernamespace" type="refType" minOccurs="0" maxOccurs="unbounded" />
+ <xsd:element name="innerpage" type="refType" minOccurs="0" maxOccurs="unbounded" />
+ <xsd:element name="innergroup" type="refType" minOccurs="0" maxOccurs="unbounded" />
+ <xsd:element name="templateparamlist" type="templateparamlistType" minOccurs="0" />
+ <xsd:element name="sectiondef" type="sectiondefType" minOccurs="0" maxOccurs="unbounded" />
+ <xsd:element name="briefdescription" type="descriptionType" minOccurs="0" />
+ <xsd:element name="detaileddescription" type="descriptionType" minOccurs="0" />
+ <xsd:element name="inheritancegraph" type="graphType" minOccurs="0" />
+ <xsd:element name="collaborationgraph" type="graphType" minOccurs="0" />
+ <xsd:element name="programlisting" type="listingType" minOccurs="0" />
+ <xsd:element name="location" type="locationType" minOccurs="0" />
+ <xsd:element name="listofallmembers" type="listofallmembersType" minOccurs="0" />
+ </xsd:sequence>
+ <xsd:attribute name="id" type="xsd:string" />
+ <xsd:attribute name="kind" type="DoxCompoundKind" />
+ <xsd:attribute name="prot" type="DoxProtectionKind" />
+ <xsd:attribute name="final" type="DoxBool" use="optional"/>
+ <xsd:attribute name="sealed" type="DoxBool" use="optional"/>
+ <xsd:attribute name="abstract" type="DoxBool" use="optional"/>
+ </xsd:complexType>
+
+ <xsd:complexType name="listofallmembersType">
+ <xsd:sequence>
+ <xsd:element name="member" type="memberRefType" minOccurs="0" maxOccurs="unbounded" />
+ </xsd:sequence>
+ </xsd:complexType>
+
+ <xsd:complexType name="memberRefType">
+ <xsd:sequence>
+ <xsd:element name="scope" />
+ <xsd:element name="name" />
+ </xsd:sequence>
+ <xsd:attribute name="refid" type="xsd:string" />
+ <xsd:attribute name="prot" type="DoxProtectionKind" />
+ <xsd:attribute name="virt" type="DoxVirtualKind" />
+ <xsd:attribute name="ambiguityscope" type="xsd:string" />
+ </xsd:complexType>
+
+ <xsd:complexType name="compoundRefType">
+ <xsd:simpleContent>
+ <xsd:extension base="xsd:string">
+ <xsd:attribute name="refid" type="xsd:string" use="optional" />
+ <xsd:attribute name="prot" type="DoxProtectionKind" />
+ <xsd:attribute name="virt" type="DoxVirtualKind" />
+ </xsd:extension>
+ </xsd:simpleContent>
+ </xsd:complexType>
+
+ <xsd:complexType name="reimplementType">
+ <xsd:simpleContent>
+ <xsd:extension base="xsd:string">
+ <xsd:attribute name="refid" type="xsd:string" />
+ </xsd:extension>
+ </xsd:simpleContent>
+ </xsd:complexType>
+
+ <xsd:complexType name="incType">
+ <xsd:simpleContent>
+ <xsd:extension base="xsd:string">
+ <xsd:attribute name="refid" type="xsd:string" />
+ <xsd:attribute name="local" type="DoxBool" />
+ </xsd:extension>
+ </xsd:simpleContent>
+ </xsd:complexType>
+
+ <xsd:complexType name="refType">
+ <xsd:simpleContent>
+ <xsd:extension base="xsd:string">
+ <xsd:attribute name="refid" type="xsd:string" />
+ <xsd:attribute name="prot" type="DoxProtectionKind" use="optional"/>
+ </xsd:extension>
+ </xsd:simpleContent>
+ </xsd:complexType>
+
+ <xsd:complexType name="refTextType">
+ <xsd:simpleContent>
+ <xsd:extension base="xsd:string">
+ <xsd:attribute name="refid" type="xsd:string" />
+ <xsd:attribute name="kindref" type="DoxRefKind" />
+ <xsd:attribute name="external" type="xsd:string" use="optional"/>
+ <xsd:attribute name="tooltip" type="xsd:string" use="optional"/>
+ </xsd:extension>
+ </xsd:simpleContent>
+ </xsd:complexType>
+
+ <xsd:complexType name="sectiondefType">
+ <xsd:sequence>
+ <xsd:element name="header" type="xsd:string" minOccurs="0" />
+ <xsd:element name="description" type="descriptionType" minOccurs="0" />
+ <xsd:element name="memberdef" type="memberdefType" maxOccurs="unbounded" />
+ </xsd:sequence>
+ <xsd:attribute name="kind" type="DoxSectionKind" />
+ </xsd:complexType>
+
+ <xsd:complexType name="memberdefType">
+ <xsd:sequence>
+ <xsd:element name="templateparamlist" type="templateparamlistType" minOccurs="0" />
+ <xsd:element name="type" type="linkedTextType" minOccurs="0" />
+ <xsd:element name="definition" minOccurs="0" />
+ <xsd:element name="argsstring" minOccurs="0" />
+ <xsd:element name="name" />
+ <xsd:element name="read" minOccurs="0" />
+ <xsd:element name="write" minOccurs="0" />
+ <xsd:element name="bitfield" minOccurs="0" />
+ <xsd:element name="reimplements" type="reimplementType" minOccurs="0" maxOccurs="unbounded" />
+ <xsd:element name="reimplementedby" type="reimplementType" minOccurs="0" maxOccurs="unbounded" />
+ <xsd:element name="param" type="paramType" minOccurs="0" maxOccurs="unbounded" />
+ <xsd:element name="enumvalue" type="enumvalueType" minOccurs="0" maxOccurs="unbounded" />
+ <xsd:element name="initializer" type="linkedTextType" minOccurs="0" />
+ <xsd:element name="exceptions" type="linkedTextType" minOccurs="0" />
+ <xsd:element name="briefdescription" type="descriptionType" minOccurs="0" />
+ <xsd:element name="detaileddescription" type="descriptionType" minOccurs="0" />
+ <xsd:element name="inbodydescription" type="descriptionType" minOccurs="0" />
+ <xsd:element name="location" type="locationType" />
+ <xsd:element name="references" type="referenceType" minOccurs="0" maxOccurs="unbounded" />
+ <xsd:element name="referencedby" type="referenceType" minOccurs="0" maxOccurs="unbounded" />
+ </xsd:sequence>
+ <xsd:attribute name="kind" type="DoxMemberKind" />
+ <xsd:attribute name="id" type="xsd:string" />
+ <xsd:attribute name="prot" type="DoxProtectionKind" />
+ <xsd:attribute name="static" type="DoxBool" />
+ <xsd:attribute name="const" type="DoxBool" use="optional"/>
+ <xsd:attribute name="explicit" type="DoxBool" use="optional"/>
+ <xsd:attribute name="inline" type="DoxBool" use="optional"/>
+ <xsd:attribute name="virt" type="DoxVirtualKind" use="optional"/>
+ <xsd:attribute name="volatile" type="DoxBool" use="optional"/>
+ <xsd:attribute name="mutable" type="DoxBool" use="optional"/>
+ <!-- Qt property -->
+ <xsd:attribute name="readable" type="DoxBool" use="optional"/>
+ <xsd:attribute name="writable" type="DoxBool" use="optional"/>
+ <!-- C++/CLI variable -->
+ <xsd:attribute name="initonly" type="DoxBool" use="optional"/>
+ <!-- C++/CLI and C# property -->
+ <xsd:attribute name="settable" type="DoxBool" use="optional"/>
+ <xsd:attribute name="gettable" type="DoxBool" use="optional"/>
+ <!-- C++/CLI function -->
+ <xsd:attribute name="final" type="DoxBool" use="optional"/>
+ <xsd:attribute name="sealed" type="DoxBool" use="optional"/>
+ <xsd:attribute name="new" type="DoxBool" use="optional"/>
+ <!-- C++/CLI event -->
+ <xsd:attribute name="add" type="DoxBool" use="optional"/>
+ <xsd:attribute name="remove" type="DoxBool" use="optional"/>
+ <xsd:attribute name="raise" type="DoxBool" use="optional"/>
+ <!-- Objective-C 2.0 protocol method -->
+ <xsd:attribute name="optional" type="DoxBool" use="optional"/>
+ <xsd:attribute name="required" type="DoxBool" use="optional"/>
+ <!-- Objective-C 2.0 property accessor -->
+ <xsd:attribute name="accessor" type="DoxAccessor" use="optional"/>
+ <!-- UNO IDL -->
+ <xsd:attribute name="attribute" type="DoxBool" use="optional"/>
+ <xsd:attribute name="property" type="DoxBool" use="optional"/>
+ <xsd:attribute name="readonly" type="DoxBool" use="optional"/>
+ <xsd:attribute name="bound" type="DoxBool" use="optional"/>
+ <xsd:attribute name="removable" type="DoxBool" use="optional"/>
+ <xsd:attribute name="contrained" type="DoxBool" use="optional"/>
+ <xsd:attribute name="transient" type="DoxBool" use="optional"/>
+ <xsd:attribute name="maybevoid" type="DoxBool" use="optional"/>
+ <xsd:attribute name="maybedefault" type="DoxBool" use="optional"/>
+ <xsd:attribute name="maybeambiguous" type="DoxBool" use="optional"/>
+
+ </xsd:complexType>
+
+ <xsd:complexType name="descriptionType" mixed="true">
+ <xsd:sequence>
+ <xsd:element name="title" type="xsd:string" minOccurs="0"/>
+ <xsd:element name="para" type="docParaType" minOccurs="0" maxOccurs="unbounded" />
+ <xsd:element name="sect1" type="docSect1Type" minOccurs="0" maxOccurs="unbounded" />
+ <xsd:element name="internal" type="docInternalType" minOccurs="0" />
+ </xsd:sequence>
+ </xsd:complexType>
+
+ <xsd:complexType name="enumvalueType" mixed="true">
+ <xsd:sequence>
+ <xsd:element name="name" />
+ <xsd:element name="initializer" type="linkedTextType" minOccurs="0" />
+ <xsd:element name="briefdescription" type="descriptionType" minOccurs="0" />
+ <xsd:element name="detaileddescription" type="descriptionType" minOccurs="0" />
+ </xsd:sequence>
+ <xsd:attribute name="id" type="xsd:string" />
+ <xsd:attribute name="prot" type="DoxProtectionKind" />
+ </xsd:complexType>
+
+ <xsd:complexType name="templateparamlistType">
+ <xsd:sequence>
+ <xsd:element name="param" type="paramType" minOccurs="0" maxOccurs="unbounded" />
+ </xsd:sequence>
+ </xsd:complexType>
+
+ <xsd:complexType name="paramType">
+ <xsd:sequence>
+ <xsd:element name="type" type="linkedTextType" minOccurs="0" />
+ <xsd:element name="declname" minOccurs="0" />
+ <xsd:element name="defname" minOccurs="0" />
+ <xsd:element name="array" minOccurs="0" />
+ <xsd:element name="defval" type="linkedTextType" minOccurs="0" />
+ <xsd:element name="briefdescription" type="descriptionType" minOccurs="0" />
+ </xsd:sequence>
+ </xsd:complexType>
+
+ <xsd:complexType name="linkedTextType" mixed="true">
+ <xsd:sequence>
+ <xsd:element name="ref" type="refTextType" minOccurs="0" maxOccurs="unbounded" />
+ </xsd:sequence>
+ </xsd:complexType>
+
+ <xsd:complexType name="graphType">
+ <xsd:sequence>
+ <xsd:element name="node" type="nodeType" maxOccurs="unbounded" />
+ </xsd:sequence>
+ </xsd:complexType>
+
+ <xsd:complexType name="nodeType">
+ <xsd:sequence>
+ <xsd:element name="label" />
+ <xsd:element name="link" type="linkType" minOccurs="0" />
+ <xsd:element name="childnode" type="childnodeType" minOccurs="0" maxOccurs="unbounded" />
+ </xsd:sequence>
+ <xsd:attribute name="id" type="xsd:string" />
+ </xsd:complexType>
+
+ <xsd:complexType name="childnodeType">
+ <xsd:sequence>
+ <xsd:element name="edgelabel" minOccurs="0" maxOccurs="unbounded"/>
+ </xsd:sequence>
+ <xsd:attribute name="refid" type="xsd:string" />
+ <xsd:attribute name="relation" type="DoxGraphRelation" />
+ </xsd:complexType>
+
+ <xsd:complexType name="linkType">
+ <xsd:attribute name="refid" type="xsd:string" />
+ <xsd:attribute name="external" type="xsd:string" use="optional"/>
+ </xsd:complexType>
+
+ <xsd:complexType name="listingType">
+ <xsd:sequence>
+ <xsd:element name="codeline" type="codelineType" minOccurs="0" maxOccurs="unbounded" />
+ </xsd:sequence>
+ </xsd:complexType>
+
+ <xsd:complexType name="codelineType">
+ <xsd:sequence>
+ <xsd:element name="highlight" type="highlightType" minOccurs="0" maxOccurs="unbounded" />
+ </xsd:sequence>
+ <xsd:attribute name="lineno" type="xsd:integer" />
+ <xsd:attribute name="refid" type="xsd:string" />
+ <xsd:attribute name="refkind" type="DoxRefKind" />
+ <xsd:attribute name="external" type="DoxBool" />
+ </xsd:complexType>
+
+ <xsd:complexType name="highlightType" mixed="true">
+ <xsd:choice minOccurs="0" maxOccurs="unbounded">
+ <xsd:element name="sp" />
+ <xsd:element name="ref" type="refTextType" />
+ </xsd:choice>
+ <xsd:attribute name="class" type="DoxHighlightClass" />
+ </xsd:complexType>
+
+ <xsd:complexType name="referenceType" mixed="true">
+ <xsd:attribute name="refid" type="xsd:string" />
+ <xsd:attribute name="compoundref" type="xsd:string" use="optional" />
+ <xsd:attribute name="startline" type="xsd:integer" />
+ <xsd:attribute name="endline" type="xsd:integer" />
+ </xsd:complexType>
+
+ <xsd:complexType name="locationType">
+ <xsd:attribute name="file" type="xsd:string" />
+ <xsd:attribute name="line" type="xsd:integer" />
+ <xsd:attribute name="column" type="xsd:integer" use="optional"/>
+ <xsd:attribute name="bodyfile" type="xsd:string" />
+ <xsd:attribute name="bodystart" type="xsd:integer" />
+ <xsd:attribute name="bodyend" type="xsd:integer" />
+ </xsd:complexType>
+
+ <xsd:complexType name="docSect1Type" mixed="true">
+ <xsd:sequence>
+ <xsd:element name="title" type="xsd:string" />
+ <xsd:element name="para" type="docParaType" minOccurs="0" maxOccurs="unbounded" />
+ <xsd:element name="sect2" type="docSect2Type" minOccurs="0" maxOccurs="unbounded" />
+ <xsd:element name="internal" type="docInternalS1Type" minOccurs="0" />
+ </xsd:sequence>
+ <xsd:attribute name="id" type="xsd:string" />
+ </xsd:complexType>
+
+ <xsd:complexType name="docSect2Type" mixed="true">
+ <xsd:sequence>
+ <xsd:element name="title" type="xsd:string" />
+ <xsd:element name="para" type="docParaType" minOccurs="0" maxOccurs="unbounded" />
+ <xsd:element name="sect3" type="docSect3Type" minOccurs="0" maxOccurs="unbounded" />
+ <xsd:element name="internal" type="docInternalS2Type" minOccurs="0" />
+ </xsd:sequence>
+ <xsd:attribute name="id" type="xsd:string" />
+ </xsd:complexType>
+
+ <xsd:complexType name="docSect3Type" mixed="true">
+ <xsd:sequence>
+ <xsd:element name="title" type="xsd:string" />
+ <xsd:element name="para" type="docParaType" minOccurs="0" maxOccurs="unbounded" />
+ <xsd:element name="sect4" type="docSect4Type" minOccurs="0" maxOccurs="unbounded" />
+ <xsd:element name="internal" type="docInternalS3Type" minOccurs="0" />
+ </xsd:sequence>
+ <xsd:attribute name="id" type="xsd:string" />
+ </xsd:complexType>
+
+ <xsd:complexType name="docSect4Type" mixed="true">
+ <xsd:sequence>
+ <xsd:element name="title" type="xsd:string" />
+ <xsd:element name="para" type="docParaType" minOccurs="0" maxOccurs="unbounded" />
+ <xsd:element name="internal" type="docInternalS4Type" minOccurs="0" />
+ </xsd:sequence>
+ <xsd:attribute name="id" type="xsd:string" />
+ </xsd:complexType>
+
+ <xsd:complexType name="docInternalType" mixed="true">
+ <xsd:sequence>
+ <xsd:element name="para" type="docParaType" minOccurs="0" maxOccurs="unbounded" />
+ <xsd:element name="sect1" type="docSect1Type" minOccurs="0" maxOccurs="unbounded" />
+ </xsd:sequence>
+ </xsd:complexType>
+
+ <xsd:complexType name="docInternalS1Type" mixed="true">
+ <xsd:sequence>
+ <xsd:element name="para" type="docParaType" minOccurs="0" maxOccurs="unbounded" />
+ <xsd:element name="sect2" type="docSect2Type" minOccurs="0" maxOccurs="unbounded" />
+ </xsd:sequence>
+ </xsd:complexType>
+
+ <xsd:complexType name="docInternalS2Type" mixed="true">
+ <xsd:sequence>
+ <xsd:element name="para" type="docParaType" minOccurs="0" maxOccurs="unbounded" />
+ <xsd:element name="sect3" type="docSect3Type" minOccurs="0" maxOccurs="unbounded" />
+ </xsd:sequence>
+ </xsd:complexType>
+
+ <xsd:complexType name="docInternalS3Type" mixed="true">
+ <xsd:sequence>
+ <xsd:element name="para" type="docParaType" minOccurs="0" maxOccurs="unbounded" />
+ <xsd:element name="sect3" type="docSect4Type" minOccurs="0" maxOccurs="unbounded" />
+ </xsd:sequence>
+ </xsd:complexType>
+
+ <xsd:complexType name="docInternalS4Type" mixed="true">
+ <xsd:sequence>
+ <xsd:element name="para" type="docParaType" minOccurs="0" maxOccurs="unbounded" />
+ </xsd:sequence>
+ </xsd:complexType>
+
+ <xsd:group name="docTitleCmdGroup">
+ <xsd:choice>
+ <xsd:element name="ulink" type="docURLLink" />
+ <xsd:element name="bold" type="docMarkupType" />
+ <xsd:element name="emphasis" type="docMarkupType" />
+ <xsd:element name="computeroutput" type="docMarkupType" />
+ <xsd:element name="subscript" type="docMarkupType" />
+ <xsd:element name="superscript" type="docMarkupType" />
+ <xsd:element name="center" type="docMarkupType" />
+ <xsd:element name="small" type="docMarkupType" />
+ <xsd:element name="htmlonly" type="xsd:string" />
+ <xsd:element name="manonly" type="xsd:string" />
+ <xsd:element name="xmlonly" type="xsd:string" />
+ <xsd:element name="rtfonly" type="xsd:string" />
+ <xsd:element name="latexonly" type="xsd:string" />
+ <xsd:element name="dot" type="xsd:string" />
+ <xsd:element name="plantuml" type="xsd:string" />
+ <xsd:element name="anchor" type="docAnchorType" />
+ <xsd:element name="formula" type="docFormulaType" />
+ <xsd:element name="ref" type="docRefTextType" />
+ <xsd:element name="nonbreakablespace" type="docEmptyType" />
+ <xsd:element name="iexcl" type="docEmptyType" />
+ <xsd:element name="cent" type="docEmptyType" />
+ <xsd:element name="pound" type="docEmptyType" />
+ <xsd:element name="curren" type="docEmptyType" />
+ <xsd:element name="yen" type="docEmptyType" />
+ <xsd:element name="brvbar" type="docEmptyType" />
+ <xsd:element name="sect" type="docEmptyType" />
+ <xsd:element name="umlaut" type="docEmptyType" />
+ <xsd:element name="copy" type="docEmptyType" />
+ <xsd:element name="ordf" type="docEmptyType" />
+ <xsd:element name="laquo" type="docEmptyType" />
+ <xsd:element name="not" type="docEmptyType" />
+ <xsd:element name="shy" type="docEmptyType" />
+ <xsd:element name="registered" type="docEmptyType" />
+ <xsd:element name="macr" type="docEmptyType" />
+ <xsd:element name="deg" type="docEmptyType" />
+ <xsd:element name="plusmn" type="docEmptyType" />
+ <xsd:element name="sup2" type="docEmptyType" />
+ <xsd:element name="sup3" type="docEmptyType" />
+ <xsd:element name="acute" type="docEmptyType" />
+ <xsd:element name="micro" type="docEmptyType" />
+ <xsd:element name="para" type="docEmptyType" />
+ <xsd:element name="middot" type="docEmptyType" />
+ <xsd:element name="cedil" type="docEmptyType" />
+ <xsd:element name="sup1" type="docEmptyType" />
+ <xsd:element name="ordm" type="docEmptyType" />
+ <xsd:element name="raquo" type="docEmptyType" />
+ <xsd:element name="frac14" type="docEmptyType" />
+ <xsd:element name="frac12" type="docEmptyType" />
+ <xsd:element name="frac34" type="docEmptyType" />
+ <xsd:element name="iquest" type="docEmptyType" />
+ <xsd:element name="Agrave" type="docEmptyType" />
+ <xsd:element name="Aacute" type="docEmptyType" />
+ <xsd:element name="Acirc" type="docEmptyType" />
+ <xsd:element name="Atilde" type="docEmptyType" />
+ <xsd:element name="Aumlaut" type="docEmptyType" />
+ <xsd:element name="Aring" type="docEmptyType" />
+ <xsd:element name="AElig" type="docEmptyType" />
+ <xsd:element name="Ccedil" type="docEmptyType" />
+ <xsd:element name="Egrave" type="docEmptyType" />
+ <xsd:element name="Eacute" type="docEmptyType" />
+ <xsd:element name="Ecirc" type="docEmptyType" />
+ <xsd:element name="Eumlaut" type="docEmptyType" />
+ <xsd:element name="Igrave" type="docEmptyType" />
+ <xsd:element name="Iacute" type="docEmptyType" />
+ <xsd:element name="Icirc" type="docEmptyType" />
+ <xsd:element name="Iumlaut" type="docEmptyType" />
+ <xsd:element name="ETH" type="docEmptyType" />
+ <xsd:element name="Ntilde" type="docEmptyType" />
+ <xsd:element name="Ograve" type="docEmptyType" />
+ <xsd:element name="Oacute" type="docEmptyType" />
+ <xsd:element name="Ocirc" type="docEmptyType" />
+ <xsd:element name="Otilde" type="docEmptyType" />
+ <xsd:element name="Oumlaut" type="docEmptyType" />
+ <xsd:element name="times" type="docEmptyType" />
+ <xsd:element name="Oslash" type="docEmptyType" />
+ <xsd:element name="Ugrave" type="docEmptyType" />
+ <xsd:element name="Uacute" type="docEmptyType" />
+ <xsd:element name="Ucirc" type="docEmptyType" />
+ <xsd:element name="Uumlaut" type="docEmptyType" />
+ <xsd:element name="Yacute" type="docEmptyType" />
+ <xsd:element name="THORN" type="docEmptyType" />
+ <xsd:element name="szlig" type="docEmptyType" />
+ <xsd:element name="agrave" type="docEmptyType" />
+ <xsd:element name="aacute" type="docEmptyType" />
+ <xsd:element name="acirc" type="docEmptyType" />
+ <xsd:element name="atilde" type="docEmptyType" />
+ <xsd:element name="aumlaut" type="docEmptyType" />
+ <xsd:element name="aring" type="docEmptyType" />
+ <xsd:element name="aelig" type="docEmptyType" />
+ <xsd:element name="ccedil" type="docEmptyType" />
+ <xsd:element name="egrave" type="docEmptyType" />
+ <xsd:element name="eacute" type="docEmptyType" />
+ <xsd:element name="ecirc" type="docEmptyType" />
+ <xsd:element name="eumlaut" type="docEmptyType" />
+ <xsd:element name="igrave" type="docEmptyType" />
+ <xsd:element name="iacute" type="docEmptyType" />
+ <xsd:element name="icirc" type="docEmptyType" />
+ <xsd:element name="iumlaut" type="docEmptyType" />
+ <xsd:element name="eth" type="docEmptyType" />
+ <xsd:element name="ntilde" type="docEmptyType" />
+ <xsd:element name="ograve" type="docEmptyType" />
+ <xsd:element name="oacute" type="docEmptyType" />
+ <xsd:element name="ocirc" type="docEmptyType" />
+ <xsd:element name="otilde" type="docEmptyType" />
+ <xsd:element name="oumlaut" type="docEmptyType" />
+ <xsd:element name="divide" type="docEmptyType" />
+ <xsd:element name="oslash" type="docEmptyType" />
+ <xsd:element name="ugrave" type="docEmptyType" />
+ <xsd:element name="uacute" type="docEmptyType" />
+ <xsd:element name="ucirc" type="docEmptyType" />
+ <xsd:element name="uumlaut" type="docEmptyType" />
+ <xsd:element name="yacute" type="docEmptyType" />
+ <xsd:element name="thorn" type="docEmptyType" />
+ <xsd:element name="yumlaut" type="docEmptyType" />
+ <xsd:element name="fnof" type="docEmptyType" />
+ <xsd:element name="Alpha" type="docEmptyType" />
+ <xsd:element name="Beta" type="docEmptyType" />
+ <xsd:element name="Gamma" type="docEmptyType" />
+ <xsd:element name="Delta" type="docEmptyType" />
+ <xsd:element name="Epsilon" type="docEmptyType" />
+ <xsd:element name="Zeta" type="docEmptyType" />
+ <xsd:element name="Eta" type="docEmptyType" />
+ <xsd:element name="Theta" type="docEmptyType" />
+ <xsd:element name="Iota" type="docEmptyType" />
+ <xsd:element name="Kappa" type="docEmptyType" />
+ <xsd:element name="Lambda" type="docEmptyType" />
+ <xsd:element name="Mu" type="docEmptyType" />
+ <xsd:element name="Nu" type="docEmptyType" />
+ <xsd:element name="Xi" type="docEmptyType" />
+ <xsd:element name="Omicron" type="docEmptyType" />
+ <xsd:element name="Pi" type="docEmptyType" />
+ <xsd:element name="Rho" type="docEmptyType" />
+ <xsd:element name="Sigma" type="docEmptyType" />
+ <xsd:element name="Tau" type="docEmptyType" />
+ <xsd:element name="Upsilon" type="docEmptyType" />
+ <xsd:element name="Phi" type="docEmptyType" />
+ <xsd:element name="Chi" type="docEmptyType" />
+ <xsd:element name="Psi" type="docEmptyType" />
+ <xsd:element name="Omega" type="docEmptyType" />
+ <xsd:element name="alpha" type="docEmptyType" />
+ <xsd:element name="beta" type="docEmptyType" />
+ <xsd:element name="gamma" type="docEmptyType" />
+ <xsd:element name="delta" type="docEmptyType" />
+ <xsd:element name="epsilon" type="docEmptyType" />
+ <xsd:element name="zeta" type="docEmptyType" />
+ <xsd:element name="eta" type="docEmptyType" />
+ <xsd:element name="theta" type="docEmptyType" />
+ <xsd:element name="iota" type="docEmptyType" />
+ <xsd:element name="kappa" type="docEmptyType" />
+ <xsd:element name="lambda" type="docEmptyType" />
+ <xsd:element name="mu" type="docEmptyType" />
+ <xsd:element name="nu" type="docEmptyType" />
+ <xsd:element name="xi" type="docEmptyType" />
+ <xsd:element name="omicron" type="docEmptyType" />
+ <xsd:element name="pi" type="docEmptyType" />
+ <xsd:element name="rho" type="docEmptyType" />
+ <xsd:element name="sigmaf" type="docEmptyType" />
+ <xsd:element name="sigma" type="docEmptyType" />
+ <xsd:element name="tau" type="docEmptyType" />
+ <xsd:element name="upsilon" type="docEmptyType" />
+ <xsd:element name="phi" type="docEmptyType" />
+ <xsd:element name="chi" type="docEmptyType" />
+ <xsd:element name="psi" type="docEmptyType" />
+ <xsd:element name="omega" type="docEmptyType" />
+ <xsd:element name="thetasym" type="docEmptyType" />
+ <xsd:element name="upsih" type="docEmptyType" />
+ <xsd:element name="piv" type="docEmptyType" />
+ <xsd:element name="bull" type="docEmptyType" />
+ <xsd:element name="hellip" type="docEmptyType" />
+ <xsd:element name="prime" type="docEmptyType" />
+ <xsd:element name="Prime" type="docEmptyType" />
+ <xsd:element name="oline" type="docEmptyType" />
+ <xsd:element name="frasl" type="docEmptyType" />
+ <xsd:element name="weierp" type="docEmptyType" />
+ <xsd:element name="image" type="docEmptyType" />
+ <xsd:element name="real" type="docEmptyType" />
+ <xsd:element name="trademark" type="docEmptyType" />
+ <xsd:element name="alefsym" type="docEmptyType" />
+ <xsd:element name="larr" type="docEmptyType" />
+ <xsd:element name="uarr" type="docEmptyType" />
+ <xsd:element name="rarr" type="docEmptyType" />
+ <xsd:element name="darr" type="docEmptyType" />
+ <xsd:element name="harr" type="docEmptyType" />
+ <xsd:element name="crarr" type="docEmptyType" />
+ <xsd:element name="lArr" type="docEmptyType" />
+ <xsd:element name="uArr" type="docEmptyType" />
+ <xsd:element name="rArr" type="docEmptyType" />
+ <xsd:element name="dArr" type="docEmptyType" />
+ <xsd:element name="hArr" type="docEmptyType" />
+ <xsd:element name="forall" type="docEmptyType" />
+ <xsd:element name="part" type="docEmptyType" />
+ <xsd:element name="exist" type="docEmptyType" />
+ <xsd:element name="empty" type="docEmptyType" />
+ <xsd:element name="nabla" type="docEmptyType" />
+ <xsd:element name="isin" type="docEmptyType" />
+ <xsd:element name="notin" type="docEmptyType" />
+ <xsd:element name="ni" type="docEmptyType" />
+ <xsd:element name="prod" type="docEmptyType" />
+ <xsd:element name="sum" type="docEmptyType" />
+ <xsd:element name="minus" type="docEmptyType" />
+ <xsd:element name="lowast" type="docEmptyType" />
+ <xsd:element name="radic" type="docEmptyType" />
+ <xsd:element name="prop" type="docEmptyType" />
+ <xsd:element name="infin" type="docEmptyType" />
+ <xsd:element name="ang" type="docEmptyType" />
+ <xsd:element name="and" type="docEmptyType" />
+ <xsd:element name="or" type="docEmptyType" />
+ <xsd:element name="cap" type="docEmptyType" />
+ <xsd:element name="cup" type="docEmptyType" />
+ <xsd:element name="int" type="docEmptyType" />
+ <xsd:element name="there4" type="docEmptyType" />
+ <xsd:element name="sim" type="docEmptyType" />
+ <xsd:element name="cong" type="docEmptyType" />
+ <xsd:element name="asymp" type="docEmptyType" />
+ <xsd:element name="ne" type="docEmptyType" />
+ <xsd:element name="equiv" type="docEmptyType" />
+ <xsd:element name="le" type="docEmptyType" />
+ <xsd:element name="ge" type="docEmptyType" />
+ <xsd:element name="sub" type="docEmptyType" />
+ <xsd:element name="sup" type="docEmptyType" />
+ <xsd:element name="nsub" type="docEmptyType" />
+ <xsd:element name="sube" type="docEmptyType" />
+ <xsd:element name="supe" type="docEmptyType" />
+ <xsd:element name="oplus" type="docEmptyType" />
+ <xsd:element name="otimes" type="docEmptyType" />
+ <xsd:element name="perp" type="docEmptyType" />
+ <xsd:element name="sdot" type="docEmptyType" />
+ <xsd:element name="lceil" type="docEmptyType" />
+ <xsd:element name="rceil" type="docEmptyType" />
+ <xsd:element name="lfloor" type="docEmptyType" />
+ <xsd:element name="rfloor" type="docEmptyType" />
+ <xsd:element name="lang" type="docEmptyType" />
+ <xsd:element name="rang" type="docEmptyType" />
+ <xsd:element name="loz" type="docEmptyType" />
+ <xsd:element name="spades" type="docEmptyType" />
+ <xsd:element name="clubs" type="docEmptyType" />
+ <xsd:element name="hearts" type="docEmptyType" />
+ <xsd:element name="diams" type="docEmptyType" />
+ <xsd:element name="OElig" type="docEmptyType" />
+ <xsd:element name="oelig" type="docEmptyType" />
+ <xsd:element name="Scaron" type="docEmptyType" />
+ <xsd:element name="scaron" type="docEmptyType" />
+ <xsd:element name="Yumlaut" type="docEmptyType" />
+ <xsd:element name="circ" type="docEmptyType" />
+ <xsd:element name="tilde" type="docEmptyType" />
+ <xsd:element name="ensp" type="docEmptyType" />
+ <xsd:element name="emsp" type="docEmptyType" />
+ <xsd:element name="thinsp" type="docEmptyType" />
+ <xsd:element name="zwnj" type="docEmptyType" />
+ <xsd:element name="zwj" type="docEmptyType" />
+ <xsd:element name="lrm" type="docEmptyType" />
+ <xsd:element name="rlm" type="docEmptyType" />
+ <xsd:element name="ndash" type="docEmptyType" />
+ <xsd:element name="mdash" type="docEmptyType" />
+ <xsd:element name="lsquo" type="docEmptyType" />
+ <xsd:element name="rsquo" type="docEmptyType" />
+ <xsd:element name="sbquo" type="docEmptyType" />
+ <xsd:element name="ldquo" type="docEmptyType" />
+ <xsd:element name="rdquo" type="docEmptyType" />
+ <xsd:element name="bdquo" type="docEmptyType" />
+ <xsd:element name="dagger" type="docEmptyType" />
+ <xsd:element name="Dagger" type="docEmptyType" />
+ <xsd:element name="permil" type="docEmptyType" />
+ <xsd:element name="lsaquo" type="docEmptyType" />
+ <xsd:element name="rsaquo" type="docEmptyType" />
+ <xsd:element name="euro" type="docEmptyType" />
+ <xsd:element name="trademark" type="docEmptyType" />
+ </xsd:choice>
+ </xsd:group>
+
+ <xsd:complexType name="docTitleType" mixed="true">
+ <xsd:group ref="docTitleCmdGroup" minOccurs="0" maxOccurs="unbounded" />
+ </xsd:complexType>
+
+ <xsd:group name="docCmdGroup">
+ <xsd:choice>
+ <xsd:group ref="docTitleCmdGroup"/>
+ <xsd:element name="linebreak" type="docEmptyType" />
+ <xsd:element name="hruler" type="docEmptyType" />
+ <xsd:element name="preformatted" type="docMarkupType" />
+ <xsd:element name="programlisting" type="listingType" />
+ <xsd:element name="verbatim" type="xsd:string" />
+ <xsd:element name="indexentry" type="docIndexEntryType" />
+ <xsd:element name="orderedlist" type="docListType" />
+ <xsd:element name="itemizedlist" type="docListType" />
+ <xsd:element name="simplesect" type="docSimpleSectType" />
+ <xsd:element name="title" type="docTitleType" />
+ <xsd:element name="variablelist" type="docVariableListType" />
+ <xsd:element name="table" type="docTableType" />
+ <xsd:element name="heading" type="docHeadingType" />
+ <xsd:element name="image" type="docImageType" />
+ <xsd:element name="dotfile" type="docFileType" />
+ <xsd:element name="mscfile" type="docFileType" />
+ <xsd:element name="diafile" type="docFileType" />
+ <xsd:element name="toclist" type="docTocListType" />
+ <xsd:element name="language" type="docLanguageType" />
+ <xsd:element name="parameterlist" type="docParamListType" />
+ <xsd:element name="xrefsect" type="docXRefSectType" />
+ <xsd:element name="copydoc" type="docCopyType" />
+ <xsd:element name="blockquote" type="docBlockQuoteType" />
+ <xsd:element name="parblock" type="docParBlockType" />
+ </xsd:choice>
+ </xsd:group>
+
+ <xsd:complexType name="docParaType" mixed="true">
+ <xsd:group ref="docCmdGroup" minOccurs="0" maxOccurs="unbounded" />
+ </xsd:complexType>
+
+ <xsd:complexType name="docMarkupType" mixed="true">
+ <xsd:group ref="docCmdGroup" minOccurs="0" maxOccurs="unbounded" />
+ </xsd:complexType>
+
+ <xsd:complexType name="docURLLink" mixed="true">
+ <xsd:group ref="docTitleCmdGroup" minOccurs="0" maxOccurs="unbounded" />
+ <xsd:attribute name="url" type="xsd:string" />
+ </xsd:complexType>
+
+ <xsd:complexType name="docAnchorType" mixed="true">
+ <xsd:attribute name="id" type="xsd:string" />
+ </xsd:complexType>
+
+ <xsd:complexType name="docFormulaType" mixed="true">
+ <xsd:attribute name="id" type="xsd:string" />
+ </xsd:complexType>
+
+ <xsd:complexType name="docIndexEntryType">
+ <xsd:sequence>
+ <xsd:element name="primaryie" type="xsd:string" />
+ <xsd:element name="secondaryie" type="xsd:string" />
+ </xsd:sequence>
+ </xsd:complexType>
+
+ <xsd:complexType name="docListType">
+ <xsd:sequence>
+ <xsd:element name="listitem" type="docListItemType" maxOccurs="unbounded" />
+ </xsd:sequence>
+ </xsd:complexType>
+
+ <xsd:complexType name="docListItemType">
+ <xsd:sequence>
+ <xsd:element name="para" type="docParaType" minOccurs="0" maxOccurs="unbounded" />
+ </xsd:sequence>
+ </xsd:complexType>
+
+ <xsd:complexType name="docSimpleSectType">
+ <xsd:sequence>
+ <xsd:element name="title" type="docTitleType" minOccurs="0" />
+ <xsd:sequence minOccurs="0" maxOccurs="unbounded">
+ <xsd:element name="para" type="docParaType" minOccurs="1" maxOccurs="unbounded" />
+ </xsd:sequence>
+ </xsd:sequence>
+ <xsd:attribute name="kind" type="DoxSimpleSectKind" />
+ </xsd:complexType>
+
+ <xsd:complexType name="docVarListEntryType">
+ <xsd:sequence>
+ <xsd:element name="term" type="docTitleType" />
+ </xsd:sequence>
+ </xsd:complexType>
+
+ <xsd:group name="docVariableListGroup">
+ <xsd:sequence>
+ <xsd:element name="varlistentry" type="docVarListEntryType" />
+ <xsd:element name="listitem" type="docListItemType" />
+ </xsd:sequence>
+ </xsd:group>
+
+ <xsd:complexType name="docVariableListType">
+ <xsd:sequence>
+ <xsd:group ref="docVariableListGroup" maxOccurs="unbounded" />
+ </xsd:sequence>
+ </xsd:complexType>
+
+ <xsd:complexType name="docRefTextType" mixed="true">
+ <xsd:group ref="docTitleCmdGroup" minOccurs="0" maxOccurs="unbounded" />
+ <xsd:attribute name="refid" type="xsd:string" />
+ <xsd:attribute name="kindref" type="DoxRefKind" />
+ <xsd:attribute name="external" type="xsd:string" />
+ </xsd:complexType>
+
+ <xsd:complexType name="docTableType">
+ <xsd:sequence>
+ <xsd:element name="row" type="docRowType" minOccurs="0" maxOccurs="unbounded" />
+ <xsd:element name="caption" type="docCaptionType" minOccurs="0" />
+ </xsd:sequence>
+ <xsd:attribute name="rows" type="xsd:integer" />
+ <xsd:attribute name="cols" type="xsd:integer" />
+ </xsd:complexType>
+
+ <xsd:complexType name="docRowType">
+ <xsd:sequence>
+ <xsd:element name="entry" type="docEntryType" minOccurs="0" maxOccurs="unbounded" />
+ </xsd:sequence>
+ </xsd:complexType>
+
+ <xsd:complexType name="docEntryType">
+ <xsd:sequence>
+ <xsd:element name="para" type="docParaType" minOccurs="0" maxOccurs="unbounded" />
+ </xsd:sequence>
+ <xsd:attribute name="thead" type="DoxBool" />
+ </xsd:complexType>
+
+ <xsd:complexType name="docCaptionType" mixed="true">
+ <xsd:group ref="docTitleCmdGroup" minOccurs="0" maxOccurs="unbounded" />
+ </xsd:complexType>
+
+ <xsd:complexType name="docHeadingType" mixed="true">
+ <xsd:group ref="docTitleCmdGroup" minOccurs="0" maxOccurs="unbounded" />
+ <xsd:attribute name="level" type="xsd:integer" /> <!-- todo: range 1-6 -->
+ </xsd:complexType>
+
+ <xsd:complexType name="docImageType" mixed="true">
+ <xsd:group ref="docTitleCmdGroup" minOccurs="0" maxOccurs="unbounded" />
+ <xsd:attribute name="type" type="DoxImageKind" />
+ <xsd:attribute name="name" type="xsd:string" />
+ <xsd:attribute name="width" type="xsd:string" />
+ <xsd:attribute name="height" type="xsd:string" />
+ </xsd:complexType>
+
+ <xsd:complexType name="docFileType" mixed="true">
+ <xsd:group ref="docTitleCmdGroup" minOccurs="0" maxOccurs="unbounded" />
+ <xsd:attribute name="name" type="xsd:string" />
+ </xsd:complexType>
+
+ <xsd:complexType name="docTocItemType" mixed="true">
+ <xsd:group ref="docTitleCmdGroup" minOccurs="0" maxOccurs="unbounded" />
+ <xsd:attribute name="id" type="xsd:string" />
+ </xsd:complexType>
+
+ <xsd:complexType name="docTocListType">
+ <xsd:sequence>
+ <xsd:element name="tocitem" type="docTocItemType" minOccurs="0" maxOccurs="unbounded" />
+ </xsd:sequence>
+ </xsd:complexType>
+
+ <xsd:complexType name="docLanguageType">
+ <xsd:sequence>
+ <xsd:element name="para" type="docParaType" minOccurs="0" maxOccurs="unbounded" />
+ </xsd:sequence>
+ <xsd:attribute name="langid" type="xsd:string" />
+ </xsd:complexType>
+
+ <xsd:complexType name="docParamListType">
+ <xsd:sequence>
+ <xsd:element name="parameteritem" type="docParamListItem" minOccurs="0" maxOccurs="unbounded" />
+ </xsd:sequence>
+ <xsd:attribute name="kind" type="DoxParamListKind" />
+ </xsd:complexType>
+
+ <xsd:complexType name="docParamListItem">
+ <xsd:sequence>
+ <xsd:element name="parameternamelist" type="docParamNameList" minOccurs="0" maxOccurs="unbounded" />
+ <xsd:element name="parameterdescription" type="descriptionType" />
+ </xsd:sequence>
+ </xsd:complexType>
+
+ <xsd:complexType name="docParamNameList">
+ <xsd:sequence>
+ <xsd:element name="parametertype" type="docParamType" minOccurs="0" maxOccurs="unbounded" />
+ <xsd:element name="parametername" type="docParamName" minOccurs="0" maxOccurs="unbounded" />
+ </xsd:sequence>
+ </xsd:complexType>
+
+ <xsd:complexType name="docParamType" mixed="true">
+ <xsd:sequence>
+ <xsd:element name="ref" type="refTextType" minOccurs="0" maxOccurs="1" />
+ </xsd:sequence>
+ </xsd:complexType>
+
+ <xsd:complexType name="docParamName" mixed="true">
+ <xsd:sequence>
+ <xsd:element name="ref" type="refTextType" minOccurs="0" maxOccurs="1" />
+ </xsd:sequence>
+ <xsd:attribute name="direction" type="DoxParamDir" use="optional" />
+ </xsd:complexType>
+
+ <xsd:complexType name="docXRefSectType">
+ <xsd:sequence>
+ <xsd:element name="xreftitle" type="xsd:string" minOccurs="0" maxOccurs="unbounded" />
+ <xsd:element name="xrefdescription" type="descriptionType" />
+ </xsd:sequence>
+ <xsd:attribute name="id" type="xsd:string" />
+ </xsd:complexType>
+
+ <xsd:complexType name="docCopyType">
+ <xsd:sequence>
+ <xsd:element name="para" type="docParaType" minOccurs="0" maxOccurs="unbounded" />
+ <xsd:element name="sect1" type="docSect1Type" minOccurs="0" maxOccurs="unbounded" />
+ <xsd:element name="internal" type="docInternalType" minOccurs="0" />
+ </xsd:sequence>
+ <xsd:attribute name="link" type="xsd:string" />
+ </xsd:complexType>
+
+ <xsd:complexType name="docBlockQuoteType">
+ <xsd:sequence>
+ <xsd:element name="para" type="docParaType" minOccurs="0" maxOccurs="unbounded" />
+ </xsd:sequence>
+ </xsd:complexType>
+
+ <xsd:complexType name="docParBlockType">
+ <xsd:sequence>
+ <xsd:element name="para" type="docParaType" minOccurs="0" maxOccurs="unbounded" />
+ </xsd:sequence>
+ </xsd:complexType>
+
+ <xsd:complexType name="docEmptyType"/>
+
+ <!-- Simple types -->
+
+ <xsd:simpleType name="DoxBool">
+ <xsd:restriction base="xsd:string">
+ <xsd:enumeration value="yes" />
+ <xsd:enumeration value="no" />
+ </xsd:restriction>
+ </xsd:simpleType>
+
+ <xsd:simpleType name="DoxGraphRelation">
+ <xsd:restriction base="xsd:string">
+ <xsd:enumeration value="include" />
+ <xsd:enumeration value="usage" />
+ <xsd:enumeration value="template-instance" />
+ <xsd:enumeration value="public-inheritance" />
+ <xsd:enumeration value="protected-inheritance" />
+ <xsd:enumeration value="private-inheritance" />
+ </xsd:restriction>
+ </xsd:simpleType>
+
+ <xsd:simpleType name="DoxRefKind">
+ <xsd:restriction base="xsd:string">
+ <xsd:enumeration value="compound" />
+ <xsd:enumeration value="member" />
+ </xsd:restriction>
+ </xsd:simpleType>
+
+ <xsd:simpleType name="DoxMemberKind">
+ <xsd:restriction base="xsd:string">
+ <xsd:enumeration value="define" />
+ <xsd:enumeration value="property" />
+ <xsd:enumeration value="event" />
+ <xsd:enumeration value="variable" />
+ <xsd:enumeration value="typedef" />
+ <xsd:enumeration value="enum" />
+ <xsd:enumeration value="function" />
+ <xsd:enumeration value="signal" />
+ <xsd:enumeration value="prototype" />
+ <xsd:enumeration value="friend" />
+ <xsd:enumeration value="dcop" />
+ <xsd:enumeration value="slot" />
+ <xsd:enumeration value="interface" />
+ <xsd:enumeration value="service" />
+ </xsd:restriction>
+ </xsd:simpleType>
+
+ <xsd:simpleType name="DoxProtectionKind">
+ <xsd:restriction base="xsd:string">
+ <xsd:enumeration value="public" />
+ <xsd:enumeration value="protected" />
+ <xsd:enumeration value="private" />
+ <xsd:enumeration value="package" />
+ </xsd:restriction>
+ </xsd:simpleType>
+
+ <xsd:simpleType name="DoxVirtualKind">
+ <xsd:restriction base="xsd:string">
+ <xsd:enumeration value="non-virtual" />
+ <xsd:enumeration value="virtual" />
+ <xsd:enumeration value="pure-virtual" />
+ </xsd:restriction>
+ </xsd:simpleType>
+
+ <xsd:simpleType name="DoxCompoundKind">
+ <xsd:restriction base="xsd:string">
+ <xsd:enumeration value="class" />
+ <xsd:enumeration value="struct" />
+ <xsd:enumeration value="union" />
+ <xsd:enumeration value="interface" />
+ <xsd:enumeration value="protocol" />
+ <xsd:enumeration value="category" />
+ <xsd:enumeration value="exception" />
+ <xsd:enumeration value="service" />
+ <xsd:enumeration value="singleton" />
+ <xsd:enumeration value="module" />
+ <xsd:enumeration value="type" />
+ <xsd:enumeration value="file" />
+ <xsd:enumeration value="namespace" />
+ <xsd:enumeration value="group" />
+ <xsd:enumeration value="page" />
+ <xsd:enumeration value="example" />
+ <xsd:enumeration value="dir" />
+ </xsd:restriction>
+ </xsd:simpleType>
+
+ <xsd:simpleType name="DoxSectionKind">
+ <xsd:restriction base="xsd:string">
+ <xsd:enumeration value="user-defined" />
+ <xsd:enumeration value="public-type" />
+ <xsd:enumeration value="public-func" />
+ <xsd:enumeration value="public-attrib" />
+ <xsd:enumeration value="public-slot" />
+ <xsd:enumeration value="signal" />
+ <xsd:enumeration value="dcop-func" />
+ <xsd:enumeration value="property" />
+ <xsd:enumeration value="event" />
+ <xsd:enumeration value="public-static-func" />
+ <xsd:enumeration value="public-static-attrib" />
+ <xsd:enumeration value="protected-type" />
+ <xsd:enumeration value="protected-func" />
+ <xsd:enumeration value="protected-attrib" />
+ <xsd:enumeration value="protected-slot" />
+ <xsd:enumeration value="protected-static-func" />
+ <xsd:enumeration value="protected-static-attrib" />
+ <xsd:enumeration value="package-type" />
+ <xsd:enumeration value="package-func" />
+ <xsd:enumeration value="package-attrib" />
+ <xsd:enumeration value="package-static-func" />
+ <xsd:enumeration value="package-static-attrib" />
+ <xsd:enumeration value="private-type" />
+ <xsd:enumeration value="private-func" />
+ <xsd:enumeration value="private-attrib" />
+ <xsd:enumeration value="private-slot" />
+ <xsd:enumeration value="private-static-func" />
+ <xsd:enumeration value="private-static-attrib" />
+ <xsd:enumeration value="friend" />
+ <xsd:enumeration value="related" />
+ <xsd:enumeration value="define" />
+ <xsd:enumeration value="prototype" />
+ <xsd:enumeration value="typedef" />
+ <xsd:enumeration value="enum" />
+ <xsd:enumeration value="func" />
+ <xsd:enumeration value="var" />
+ </xsd:restriction>
+ </xsd:simpleType>
+
+ <xsd:simpleType name="DoxHighlightClass">
+ <xsd:restriction base="xsd:string">
+ <xsd:enumeration value="comment" />
+ <xsd:enumeration value="normal" />
+ <xsd:enumeration value="preprocessor" />
+ <xsd:enumeration value="keyword" />
+ <xsd:enumeration value="keywordtype" />
+ <xsd:enumeration value="keywordflow" />
+ <xsd:enumeration value="stringliteral" />
+ <xsd:enumeration value="charliteral" />
+ </xsd:restriction>
+ </xsd:simpleType>
+
+ <xsd:simpleType name="DoxSimpleSectKind">
+ <xsd:restriction base="xsd:string">
+ <xsd:enumeration value="see" />
+ <xsd:enumeration value="return" />
+ <xsd:enumeration value="author" />
+ <xsd:enumeration value="authors" />
+ <xsd:enumeration value="version" />
+ <xsd:enumeration value="since" />
+ <xsd:enumeration value="date" />
+ <xsd:enumeration value="note" />
+ <xsd:enumeration value="warning" />
+ <xsd:enumeration value="pre" />
+ <xsd:enumeration value="post" />
+ <xsd:enumeration value="copyright" />
+ <xsd:enumeration value="invariant" />
+ <xsd:enumeration value="remark" />
+ <xsd:enumeration value="attention" />
+ <xsd:enumeration value="par" />
+ <xsd:enumeration value="rcs" />
+ </xsd:restriction>
+ </xsd:simpleType>
+
+ <xsd:simpleType name="DoxVersionNumber">
+ <xsd:restriction base="xsd:string">
+ <xsd:pattern value="\d+\.\d+.*" />
+ </xsd:restriction>
+ </xsd:simpleType>
+
+ <xsd:simpleType name="DoxImageKind">
+ <xsd:restriction base="xsd:string">
+ <xsd:enumeration value="html" />
+ <xsd:enumeration value="latex" />
+ <xsd:enumeration value="rtf" />
+ </xsd:restriction>
+ </xsd:simpleType>
+
+ <xsd:simpleType name="DoxParamListKind">
+ <xsd:restriction base="xsd:string">
+ <xsd:enumeration value="param" />
+ <xsd:enumeration value="retval" />
+ <xsd:enumeration value="exception" />
+ <xsd:enumeration value="templateparam" />
+ </xsd:restriction>
+ </xsd:simpleType>
+
+ <xsd:simpleType name="DoxCharRange">
+ <xsd:restriction base="xsd:string">
+ <xsd:pattern value="[aeiouncAEIOUNC]" />
+ </xsd:restriction>
+ </xsd:simpleType>
+
+ <xsd:simpleType name="DoxParamDir">
+ <xsd:restriction base="xsd:string">
+ <xsd:enumeration value="in"/>
+ <xsd:enumeration value="out"/>
+ <xsd:enumeration value="inout"/>
+ </xsd:restriction>
+ </xsd:simpleType>
+
+ <xsd:simpleType name="DoxAccessor">
+ <xsd:restriction base="xsd:string">
+ <xsd:enumeration value="retain"/>
+ <xsd:enumeration value="copy"/>
+ <xsd:enumeration value="assign"/>
+ <xsd:enumeration value="weak"/>
+ <xsd:enumeration value="strong"/>
+ <xsd:enumeration value="unretained"/>
+ </xsd:restriction>
+ </xsd:simpleType>
+
+</xsd:schema>
+
--- /dev/null
+<?xml version='1.0' encoding='UTF-8' standalone='no'?>
+<doxygen xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="compound.xsd" version="1.8.8">
+ <compounddef id="dir_68267d1309a1af8e8297ef4c3efbcdba" kind="dir">
+ <compoundname>src</compoundname>
+ <innerfile refid="_foo_8java">Foo.java</innerfile>
+ <briefdescription>
+ </briefdescription>
+ <detaileddescription>
+ </detaileddescription>
+ <location file="%SOURCE_DIRECTORY%/"/>
+ </compounddef>
+</doxygen>
--- /dev/null
+<?xml version='1.0' encoding='UTF-8' standalone='no'?>
+<doxygenindex xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="index.xsd" version="1.8.8">
+ <compound refid="class_foo" kind="class"><name>Foo</name>
+ </compound>
+ <compound refid="_foo_8java" kind="file"><name>Foo.java</name>
+ </compound>
+ <compound refid="dir_68267d1309a1af8e8297ef4c3efbcdba" kind="dir"><name>src</name>
+ </compound>
+</doxygenindex>
--- /dev/null
+<?xml version='1.0' encoding='utf-8' ?>
+<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
+ <xsd:element name="doxygenindex" type="DoxygenType"/>
+
+ <xsd:complexType name="DoxygenType">
+ <xsd:sequence>
+ <xsd:element name="compound" type="CompoundType" minOccurs="0" maxOccurs="unbounded"/>
+ </xsd:sequence>
+ <xsd:attribute name="version" type="xsd:string" use="required"/>
+ </xsd:complexType>
+
+ <xsd:complexType name="CompoundType">
+ <xsd:sequence>
+ <xsd:element name="name" type="xsd:string"/>
+ <xsd:element name="member" type="MemberType" minOccurs="0" maxOccurs="unbounded"/>
+ </xsd:sequence>
+ <xsd:attribute name="refid" type="xsd:string" use="required"/>
+ <xsd:attribute name="kind" type="CompoundKind" use="required"/>
+ </xsd:complexType>
+
+ <xsd:complexType name="MemberType">
+ <xsd:sequence>
+ <xsd:element name="name" type="xsd:string"/>
+ </xsd:sequence>
+ <xsd:attribute name="refid" type="xsd:string" use="required"/>
+ <xsd:attribute name="kind" type="MemberKind" use="required"/>
+ </xsd:complexType>
+
+ <xsd:simpleType name="CompoundKind">
+ <xsd:restriction base="xsd:string">
+ <xsd:enumeration value="class"/>
+ <xsd:enumeration value="struct"/>
+ <xsd:enumeration value="union"/>
+ <xsd:enumeration value="interface"/>
+ <xsd:enumeration value="protocol"/>
+ <xsd:enumeration value="category"/>
+ <xsd:enumeration value="exception"/>
+ <xsd:enumeration value="file"/>
+ <xsd:enumeration value="namespace"/>
+ <xsd:enumeration value="group"/>
+ <xsd:enumeration value="page"/>
+ <xsd:enumeration value="example"/>
+ <xsd:enumeration value="dir"/>
+ </xsd:restriction>
+ </xsd:simpleType>
+
+ <xsd:simpleType name="MemberKind">
+ <xsd:restriction base="xsd:string">
+ <xsd:enumeration value="define"/>
+ <xsd:enumeration value="property"/>
+ <xsd:enumeration value="event"/>
+ <xsd:enumeration value="variable"/>
+ <xsd:enumeration value="typedef"/>
+ <xsd:enumeration value="enum"/>
+ <xsd:enumeration value="enumvalue"/>
+ <xsd:enumeration value="function"/>
+ <xsd:enumeration value="signal"/>
+ <xsd:enumeration value="prototype"/>
+ <xsd:enumeration value="friend"/>
+ <xsd:enumeration value="dcop"/>
+ <xsd:enumeration value="slot"/>
+ </xsd:restriction>
+ </xsd:simpleType>
+
+</xsd:schema>
+
import minilang_test_parser
+# An naive recursive stack-based interpreter of the minilang language.
class Interpretor
super Visitor
+
+ # A stack of numeric values
var stack = new Array[Int]
+
+ # A stack of boolean values
var bstack = new Array[Bool]
+
+ # The current values assigned to each variable
var vars = new HashMap[String, Int]
redef fun visit(n) do n.accept_calculator(self)
end
redef class Node
+ # Execution of the node by the interpreter `v`
fun accept_calculator(v: Interpretor) do visit_children(v)
end
# The start state
var start: State
- # State that are accect states
+ # State that are accept states
var accept = new Array[State]
# All states
var states = new Array[State]
- # Tokens associated on accept states
- # use `add_tag` to update
+ # Tokens associated on accept states.
+ # Use `add_tag` to update
var tags = new HashMap[State, Set[Token]]
- # Accept states associated on tokens
- # use `add_tag` to update
+ # Accept states associated on tokens.
+ # Use `add_tag` to update
var retrotags = new HashMap[Token, Set[State]]
# Tag all accept states
assert retrotags[t].has(s)
end
- # Remove all occurences of a tag in an automaton
+ # Remove all occurrences of a tag in an automaton
fun clear_tag(t: Token)
do
if not retrotags.has_key(t) then return
retrotags.keys.remove(t)
end
- # Remove tokens from conflicting state according the the inclusion of language
+ # Remove tokens from conflicting state according the inclusion of language.
# REQUIRE: self isa DFA automaton
fun solve_token_inclusion
do
end
end
- # Initialize a new automaton for the empty language
- # one state, no accept, no transition
+ # Initialize a new automaton for the empty language.
+ # One state, no accept, no transition.
init empty
do
var state = new State
states.add state
end
- # Initialize a new automaton for the empty-string language
- # one state, is accept, no transition
+ # Initialize a new automaton for the empty-string language.
+ # One state, is accept, no transition.
init epsilon
do
var state = new State
states.add state
end
- # Initialize a new automation for the language that accepts only a single symbol
- # Two state, the second is accept, one transition on `symbol`
+ # Initialize a new automation for the language that accepts only a single symbol.
+ # Two state, the second is accept, one transition on `symbol`.
init atom(symbol: Int)
do
var s = new State
states.add a
end
- # Contatenate `other` to `self`
- # other is modified and invalidated.
+ # Concatenate `other` to `self`.
+ # Other is modified and invalidated.
fun concat(other: Automaton)
do
var s2 = other.start
states.add_all other.states
end
- # `self` become the alternation of `self` and `other`
+ # `self` become the alternation of `self` and `other`.
# `other` is modified and invalidated.
fun alternate(other: Automaton)
do
states.add_all other.states
end
- # Return a new automaton that recognize `self` but not `other`
- # For a theorical POV, this is the substraction of languages.
- # Note: the implementation use `to_dfa` internally, so the theorical complexity is not cheap.
+ # Return a new automaton that recognize `self` but not `other`.
+ # For a theoretical POV, this is the subtraction of languages.
+ # Note: the implementation use `to_dfa` internally, so the theoretical complexity is not cheap.
fun except(other: Automaton): Automaton
do
var ta = new Token("1")
return c
end
- # `self` absorbs all states, transisions, tags, and acceptations of `other`
- # An epsilon transition is added between `self.start` and `other.start`
+ # `self` absorbs all states, transitions, tags, and acceptations of `other`.
+ # An epsilon transition is added between `self.start` and `other.start`.
fun absorb(other: Automaton)
do
states.add_all other.states
f.close
end
- # Transform a NFA to a DFA
- # note: the DFA is not miminized
+ # Transform a NFA to a DFA.
+ # note: the DFA is not minimized.
fun to_dfa: Automaton
do
trim
return dfa
end
- # epsilon-closure on a state of states
- # used by `to_dfa`
+ # Epsilon-closure on a state of states.
+ # Used by `to_dfa`.
private fun eclosure(states: Collection[State]): Set[State]
do
var res = new ArraySet[State]
return res
end
- # trans on a set of states
- # Used by `to_dfa`
+ # Trans on a set of states.
+ # Used by `to_dfa`.
fun trans(states: Collection[State], symbol: Int): Set[State]
do
var res = new ArraySet[State]
return res
end
- # Generate the Nit source code of the lexer
- # `filepath` is the name of the ouptit file
- # `parser` is the name of the parser module (used to import the token classes)
+ # Generate the Nit source code of the lexer.
+ # `filepath` is the name of the output file.
+ # `parser` is the name of the parser module (used to import the token classes).
fun gen_to_nit(filepath: String, name: String, parser: nullable String)
do
var gen = new DFAGenerator(filepath, name, self, parser)
var automaton: Automaton
var parser: nullable String
- var out: OStream
- init(filepath: String, name: String, automaton: Automaton, parser: nullable String) do
- self.filepath = filepath
- self.name = name
- self.automaton = automaton
- self.parser = parser
+ var out: OStream is noinit
+
+ init do
self.out = new OFStream.open(filepath)
end
# A state in a finite automaton
class State
# Outgoing transitions
-
var outs = new Array[Transition]
- # Ingoing tyransitions
+
+ # Ingoing transitions
var ins = new Array[Transition]
# Add a transitions to `to` on `symbol` (null means epsilon)
return t
end
+ # Get the first state following the transition `i`.
+ # Null if no transition for `i`.
fun trans(i: Int): nullable State
do
for t in outs do
# A range of symbols on a transition
class TSymbol
+ # The first symbol in the range
var first: Int
+
+ # The last symbol if any.
+ #
+ # `null` means infinity.
var last: nullable Int
redef fun to_s
# The symbol on the transition (null means epsilon)
var symbol: nullable TSymbol
- # Remove the transition from the automaton
- # Detash from `from` and `to`
+ # Remove the transition from the automaton.
+ # Detach from `from` and `to`.
fun delete
do
from.outs.remove(self)
# See the License for the specific language governing permissions and
# limitations under the License.
-# A gramar describing a language
+# A grammar describing a language
class Gram
- # The productions (non-terminal) of the conctete grammar
+ # The productions (non-terminal) of the concrete grammar
var prods = new Array[Production]
- # The additionnal abstract productions of the grammar
+ # The additional abstract productions of the grammar
# TODO clean AST
var ast_prods = new Array[Production]
res.append("{p.name} =\n")
end
var last = null
- if not p.alts.is_empty then p.alts.last
+ if not p.alts.is_empty then last = p.alts.last
for a in p.alts do
res.append("\t\{{a.name}:\} {a.elems.join(" ")}")
if a.codes == null then a.make_codes
return res.to_s
end
- # Inline (ie. remove from the conctete grammar) some production
+ # Inline (ie. remove from the concrete grammar) some production
# REQUIRE: no circular production in `prods`
fun inline(prods: Collection[Production])
do
# The alternative of the production
var alts = new Array[Alternative]
- # Additionnal alternatives in the AST
+ # Additional alternatives in the AST
var ast_alts = new Array[Alternative]
# Is self the accept production
var accept = false
# Is self transformed to a other production for the AST
- # FIXME: cleaup AST
+ # FIXME: cleanup AST
var spe: nullable Production = null is writable
# Is self contains only a single alternative (then no need for a abstract production class in the AST)
# Is the production nullable
var is_nullable = false
+
# The first tokens of the production
var firsts = new HashSet[Item]
+
# The tokens that may follows the production (as in SLR)
var afters = new HashSet[Item]
# Is the alternative unparsable? (ie not in the automaton)
var phony = false is writable
- # Imitialize codes with the elements
+ # Initialize codes with the elements
fun make_codes
do
if codes != null then return
end
end
-# A step in the construction of the AST. used to modelize transformations
+# A step in the construction of the AST.
+# Used to model transformations
interface Code
end
+
# Get a element from the stack
class CodePop
super Code
redef fun to_s do return "pop"
end
-# Allocate a new AST node for an alternative using the correct number of poped elements
+
+# Allocate a new AST node for an alternative using the correct number of popped elements
class CodeNew
super Code
+
+ # The associated alternative
var alt: Alternative
+
redef fun to_s do return "New {alt.name}/{alt.elems.length}"
end
+
# Get null
class CodeNull
super Code
# The mangled name of the element
fun cname: String do return "N{name.to_cmangle}"
- # the name of the class in the AST
+ # The name of the class in the AST
fun acname: String do
var res = acname_cache
if res == null then
end
return res
end
+
+ # The name of the class in the AST
fun acname=(s: String) do acname_cache = s
end
# A terminal element
class Token
super Element
- # States of the LR automatio that shift on self
+ # States of the LR automaton that shift on self
var shifts = new ArraySet[LRState]
- # States of the LR automatio that reduce on self in the lookahead(1)
+ # States of the LR automaton that reduce on self in the lookahead(1)
var reduces = new ArraySet[LRState]
end
# A state in a LR automaton
class LRState
- # name of the automaton (short part from the start)
+ # Name of the automaton (short part from the start)
var name: String
- # malglen name
+ # Mangled name
fun cname: String do return name.to_cmangle
- # number
+ # Number
var number: Int = -1
# Set of all items
# Ingoing transitions
var outs = new Array[LRTransition]
- # trans function
+ # Trans function
fun trans(e: Element): nullable LRState
do
for t in outs do if t.elem == e then return t.to
return true
end
- # Recusively extends item outside the core
+ # Recursively extends item outside the core
fun extends(i: Item)
do
var e = i.next
var gotos = new ArraySet[Production]
# Reduction guarded by tokens
var guarded_reduce = new HashMap[Token, Set[Item]]
- # Shitfs guarded by tokens
+ # Shifts guarded by tokens
var guarded_shift = new HashMap[Token, Set[Item]]
# Does the state need a guard to perform an action?
# Is the state LR0?
fun is_lr0: Bool do return reduces.length <= 1 and shifts.is_empty or reduces.is_empty
- # compute guards and conflicts
+ # Compute guards and conflicts
fun analysis
do
# Extends the core
end
end
- # Return `i` and all other items of the state that expands, directly or undirectly, to `i`
+ # Return `i` and all other items of the state that expands, directly or indirectly, to `i`
fun back_expand(i: Item): Set[Item]
do
var res = new ArraySet[Item]
class LRTransition
# The origin state
var from: LRState
- # The testination state
+ # The destination state
var to: LRState
# The element labeling the transition
var elem: Element
return b.to_s
end
- # The element thatr follow the dot, null if the fdot is at the end
+ # The element that follows the dot, null if the dot is at the end
fun next: nullable Element
do
if pos >= alt.elems.length then return null
return alt.elems[pos]
end
- # SLR loohahead
+ # SLR lookahead
fun lookahead: Set[Token]
do
var res = new HashSet[Token]
# See the License for the specific language governing permissions and
# limitations under the License.
-# Ad-hoc hand-writen lexer for nitcc
-# This avoid to commit (and relyon ) a generated lexer
-#
+# Ad-hoc hand-written lexer for nitcc
+# This avoid to commit (and rely on) a generated lexer
module nitcc_lexer0
# Required for the tokens definitions
import nitcc_parser
-# Hand-writen lexer of nitcc
-# Used only for the boostrap of the tool.
+# Hand-written lexer of nitcc.
+# Used only for the bootstrap of the tool.
class Lexer_nitcc
+ # The text to tokenize
var text: String
- var iter: Iterator[Char] = "".chars.iterator
+ # The iterator on text
+ private var iter: Iterator[Char] is noinit
+
+ # The current position
var pos = 0
- var tokens = new Array[NToken]
+ # The tokens currently produced
+ private var tokens = new Array[NToken]
+ # Tokenize and returns the tokens
fun lex: Array[NToken]
do
iter = text.chars.iterator
return tokens
end
- fun error(c: Char)
+ private fun error(c: Char)
do
print "pos {pos}: Lexer error on '{c}'."
abort
end
- fun str
+ private fun str
do
var b = new FlatBuffer
b.add('\'')
abort
end
- fun id(c: Char)
+ private fun id(c: Char)
do
var b = new FlatBuffer
b.add c
tokens.add token
end
- fun kw(c: Char)
+ private fun kw(c: Char)
do
var b = new FlatBuffer
b.add c
tokens.add token
end
- fun trim
+ private fun trim
do
while iter.is_ok and iter.item <= ' ' do
iter.next
class CollectNameVisitor
super Visitor
+ # All the productions
var nprods = new Array[Nprod]
# Symbol table to associate things (prods and exprs) with their name
# The current production, used to initialize priorities
var prod: nullable Production = null
- # The current priority counter to name tranformed productions
+ # The current priority counter to name transformed productions
var pricpt: Int = 0
# Run the semantic analysis of the grammar
# First visit to collect names
enter_visit(n)
- # Second visit to use collectec names and build rhings
+ # Second visit to use collected names and build things
var v2 = new CheckNameVisitor(self)
v2.enter_visit(n)
- # Inline all the ?
+ # Inline all the `?`
gram.inline(v2.quesizes.values)
- # Inlile all the prods sufixed by '_imline' #TODO use a real keyword
+ # Inline all the prods suffixed by '_inline' #TODO use a real keyword
for p in gram.prods do
if not p.name.has_suffix("_inline") then continue
print "inline {p}"
# The collected element names, for the alternative
var elems_names = new Array[nullable String]
- # The collected elementname, for the nelem
+ # The collected element names, for the nelem
var elemname: nullable String = null
# Is the alternative transformed, for the alternative
var trans = false
# The current priority class
- # Used the check, and tranform the grammar
+ # Used the check, and transform the grammar
var pri: nullable Npriority = null
# Known ignored tokens
var rejecteds = new Array[Element]
# Pool of elements that are modified with + (reuse them!)
- private var plusizes = new HashMap[Element, Production]
+ var plusizes = new HashMap[Element, Production]
# Create a + version of an element
fun plusize(e: Element): Production
end
# Pool of elements that are modified with ? (reuse them!)
- private var quesizes = new HashMap[Element, Production]
+ var quesizes = new HashMap[Element, Production]
# Create a ? version of an element
fun quesize(e: Element): Production
end
# The current nexpr, used to track dependency on named expressions (see `Nexpr::precs`)
- var nexpr: nullable Nexpr
+ var nexpr: nullable Nexpr = null
# The current production, used to initialize alternatives
- var prod: nullable Production
+ var prod: nullable Production = null
# The main visitor, used to access the grammar of the symbol table
var v1: CollectNameVisitor
- init(v1: CollectNameVisitor) do self.v1 = v1
redef fun visit(n) do n.accept_check_name_visitor(self)
end
# The associated NFA (cached, see `build_nfa`)
private var nfa: nullable Automaton
- # Build the NFA, possibily building the NFA of required expressions
+ # Build the NFA, possibly building the NFA of required expressions
# Print an error if there is a circular dependency
# The result is cached
fun build_nfa: Automaton do
abort
else if e isa Token then
# The token was build and registered during the visit
- # So, unregister then, the bit Ignred token will be build later
+ # So, unregister them, the big Ignored token will be build later
v.v1.gram.tokens.remove(e)
else
abort
end
redef class Nprod
- # The associated main production
- # ie the last priority class
+ # The associated main production.
+ # i.e. the last priority class.
var prod: nullable Production
- # The associated most-priority production
- # ie the first priority class
- # If there is no priority then `sub_prod == prod`
+ # The associated most-priority production.
+ # i.e. the first priority class.
+ # If there is no priority then `sub_prod == prod`.
var sub_prod: nullable Production
redef fun accept_collect_prod(v) do
end
redef class Npriority
+ # It is the last priority group?
var is_last = false
# The associated production
var prod: nullable Production
- # The production in the with the next less priority class
- # null is there is no priority or if the first priority class
+ # The production in the with the next less priority class.
+ # `null` if there is no priority or if the first priority class.
var next: nullable Production
redef fun accept_collect_prod(v) do
v.pri = self
super
- # Inject a new alternative that goes to the next less prioty class
+ # Inject a new alternative that goes to the next less priority class
var alt = prod.new_alt2(prod.name + "_" + prod.alts.length.to_s, [next.as(not null)])
alt.trans = true
alt.codes = [new CodePop]
end
redef class Alternative
+ # The short name of the alternative.
+ # Used for errors
var short_name: nullable String
end
redef fun make_rfa: Automaton
do
var a = new Automaton.epsilon
- var val
for c in self.value.chars do
var b = new Automaton.atom(c.ascii)
a.concat(b)
--- /dev/null
+all: nitiwiki
+
+nitiwiki:
+ mkdir -p bin
+ ../../bin/nitc src/nitiwiki.nit -o bin/nitiwiki
+
+tests: nitiwiki
+ cd tests; make
+
+doc:
+ ../../bin/nitdoc -d doc src/nitiwiki.nit
+
+clean:
+ rm -rf bin
+ rm -rf -- .nit_compile 2> /dev/null || true
--- /dev/null
+# nitiwiki, a simple wiki manager based on markdown.
+
+Basically, nitiwiki compiles a set of markdown files into an HTML wiki.
+
+The wiki content is structured by `sections` represented by the wiki folders. Sections can contain `articles` represented by markdown files.
+
+Features:
+
+* automatic wiki structure from folders hierarchy
+* automatic site menu
+* automatic sitemap
+* automatic summaries
+* easy and rapid templating
+* customizable section templates and menus
+* rsync synchronization
+* git synchronization
+
+## Wiki structure
+
+Basic wiki structure:
+
+ root
+ |- assets
+ |- out
+ |- pages
+ |- templates
+ | |- footer.html
+ | |- header.html
+ | |- menu.html
+ | `- template.html
+ `- config.ini
+
+### pages
+
+This is where goes all the content of your wiki.
+Nitiwiki will render an article for each markdown file found in `pages`.
+
+You can categorize your content in sections using sub-folders:
+
+ pages
+ |- section1
+ | `- index.md
+ |- section2
+ | `- index.md
+ |- page1.md
+ |- page2.md
+ `- index.md
+
+### assets
+
+This is where you store CSS and JavaScript files used in the design of your site.
+
+You can also use this directory to put some images or other files that will be
+used in all your pages.
+
+ assets
+ |- css
+ |- js
+ `- logo.png
+
+### templates
+
+This folder contains the templates used to generate the HTML pages of your wiki.
+
+The main template is called `template.html`.
+It contains the HTML structure of your pages and some macros that will be replaced
+by the wiki articles.
+
+### out
+
+This is where your wiki will be rendered by nitiwiki.
+Do not put anything in this folder since it will be overwritten at the
+next wiki rendering.
+
+The wiki rendering consists in:
+
+1. copy the `assets` directory to `out`
+2. copy attached article files from `pages` to `out`
+3. translate markdown files from `pages` to html files in `out`
+
+### config.ini
+
+This is the main config file of your wiki. For more details see [Configure the wiki](#Configure_the_wiki).
+
+## Manage the wiki
+
+### Create a new wiki
+
+Just move to the directory where you want to store your source files and type:
+
+ nitiwiki init
+
+This command will import the base structure of your wiki in the current directory.
+At this point nitiwiki has created the main configuration file of your site:
+`config.ini`.
+
+### Configure the wiki
+
+All the nitiwiki configuration is done using
+[ini files](http://en.wikipedia.org/wiki/INI_file).
+
+The wiki configuration is contained in the `config.ini` file located at the root
+directory of your wiki.
+This file can be edited to change nitiwiki settings.
+
+Settings:
+
+* `wiki.name`: Displayed name
+* `wiki.desc`: Long description
+* `wiki.logo`: Logo image url
+* `wiki.root_url`: Base url used to resolve links
+* `wiki.root_dir`: Absolute path of base directory
+* `wiki.source_dir`: Source directory (relative path from `wiki.root_dir`)
+* `wiki.out_dir`: Output directory (relative)
+* `wiki.assets_dir`: Assets directory (relative)
+* `wiki.templates_dir`: Templates directory (relative)
+* `wiki.template`: Wiki main template file
+* `wiki.header`: Wiki main header template file
+* `wiki.footer`: Wiki main footer template file
+* `wiki.menu`: Wiki main menu template file
+* `wiki.rsync_dir`: Directory used to rsync output
+* `wiki.git_origin`: Git origin used to fetch data
+* `wiki.git_branch`: Git branch used to fetch data
+
+For more details on each option see `WikiConfig`.
+
+### Add content
+
+To add content in your wiki simply add markdown files (with `.md` extension) into the `pages/` folder.
+
+Once you have done your changes, use:
+
+ nitiwiki --status
+
+This will show the impacts of your changes on the wiki structure.
+
+Then type:
+
+ nitiwiki --render
+
+This will the generate the html output of your new content.
+The option `--force` can be used to regenerate all the wiki.
+This can be uselful when you perform changes on the template files.
+
+### Configure sections
+
+Section appearance can be customized using config files.
+
+Each section in the `pages/` folder can contain a `config.ini` file.
+Options set on a section will be propagated to all its children unless
+they have their own config file.
+
+Allowed options are:
+
+* `section.title`: Custom title for this section
+* `section.template`: Custom template file
+* `section.header`: Custom header template file
+* `section.footer`: Custom footer template file
+* `section.menu`: Custom menu template file
+* `section.is_hidden`: Set this to `true` will hide the section in all menus and
+ sitemaps.
+
+## Customize templates
+
+Templating your wiki involves modifying 4 template files:
+
+* `template.html`
+* `header.html`
+* `footer.html`
+* `menu.html`
+
+Each of these file contains an HTML skeletton used by nitiwiki to render your files.
+Templates can contains macros marked `%MACRO%` that will be replaced by dynamic content.
+
+Every template can access to:
+
+* `ROOT_URL`: Wiki root url
+* `TITLE`: Wiki name
+* `SUBTITLE`: Wiki description
+* `LOGO`: Wiki logo image path
+
+Additionnal macros can be used in specialized templates.
+
+### Main template
+
+The template file `template.html` represents the overall structure of your wiki pages.
+
+ <!DOCTYPE html>
+ <html>
+ <head>
+ <title>%TITLE%</title>
+ <link href="%ROOT_URL%/assets/css/main.css" rel="stylesheet">
+ </head>
+ <body>
+ %HEADER%
+ %TOP_MENU%
+ <div>
+ %BODY%
+ %FOOTER%
+ </div>
+ </body>
+ </html>
+
+Additionnal macros:
+
+* `HEADER`: Wiki header (see [Header template](#Header_template))
+* `FOOTER`: Wiki footer (see [Footer template](#Footer_template))
+* `TOP_MENU`: Wiki top menu (see [Topmenu template](#Topmenu_template))
+* `HEADER`: Wiki header (see [Header template](#Header_template))
+* `BODY`: Wiki body content
+
+### Header template
+
+The template file `header.html` is generated on top of all the wiki pages.
+
+ <header>
+ <a href="#"><img src="%ROOT_URL%/%LOGO%" alt="logo"/></a>
+ <h2>%SUBTITLE%</h2>
+ <h1>%TITLE%</h1>
+ </header>
+
+### Footer template
+
+The template file `footer.html` is generated on the bottom of all the wiki pages.
+
+ <footer>
+ <p>%TITLE% © %YEAR%</p>
+ <p>last modification %GEN_TIME%</p>
+ </footer>
+
+Additionnal macros:
+
+* `YEAR`: Current year
+* `GEN_TIME`: Page generation date
+
+### Topmenu template
+
+The template file `menu.html` contains the menu structure generated on all your pages.
+
+Its content can be static:
+
+ <nav class="menu">
+ <ul class="nav navbar-nav">
+ <li><a href="#">Home</a></li>
+ <li><a href="#">Page1</a></li>
+ <li><a href="#">Page2</a></li>
+ </ul>
+ </nav>
+
+Or dynamic using the macro `MENUS`:
+
+ <nav class="menu">
+ <ul class="nav navbar-nav">
+ %MENUS%
+ </ul>
+ </nav>
+
+## Advanced usages
+
+### Working with git
+
+nitiwiki allows you to store your wiki changes in git.
+Using the option `--fetch` will update the local wiki instance
+according to git informations found in the config file.
+
+Be sure to set `wiki.git_origin` and `wiki.git_branch`
+in order to correctly pull changes.
+
+To automatically update your wiki when changes are pushed on the
+origin repository you can use the following command in a git hook:
+
+ nitiwiki --fetch --render
+
+### Working with a remote server
+
+Sometimes you cannot do what you want on your webserver (like setting crons).
+For this purpose, nitiwiki provide a quick way to update a distant instance
+through `ssh` using `rsync`.
+
+With the option `--rsync`, nitwiki will update a distant location with the
+last rendered output. This way you can manually update your webserver
+after changes or set a cron on a different server that you can control.
+
+Using the following command in your cron will update the web server instance
+from git:
+
+ nitiwiki --fetch --render --rsync
+
+Be sure to set `wiki.rsync_dir` in order to correctly push your changes.
+When using `--rsync`, keep in mind that the rendered output must be configured
+to work on the web server and set `wiki.root_url` accordingly.
--- /dev/null
+wiki.name=MyWiki
+wiki.desc=proudly powered by nit
+wiki.logo=assets/logo.png
+wiki.root_url=http://localhost/
+wiki.root_dir=/full/path/to/your/wiki/root/dir
--- /dev/null
+# Welcome on nitiwiki
--- /dev/null
+<footer>
+ <p>%TITLE% © %YEAR%</p>
+ <p>last modification %GEN_TIME%</p>
+</footer>
--- /dev/null
+<header>
+ <a href="#"><img src="%ROOT_URL%/%LOGO%" alt="logo"/></a>
+ <h2>%SUBTITLE%</h2>
+ <h1>%TITLE%</h1>
+</header>
--- /dev/null
+<nav class="menu">
+ <ul class="nav navbar-nav">
+ %MENUS%
+ </ul>
+</nav>
--- /dev/null
+<!DOCTYPE html>
+<html>
+ <head>
+ <title>%TITLE%</title>
+ <link href="%ROOT_URL%/assets/css/main.css" rel="stylesheet">
+ </head>
+ <body>
+ %HEADER%
+ %TOP_MENU%
+ <div>
+ %BODY%
+ %FOOTER%
+ </div>
+ </body>
+</html>
--- /dev/null
+header { margin: 15px 0; }
+header img {
+ padding: 10px;
+ float: left;
+}
+header h1, header h2 { display: none; }
+
+footer {
+ margin-top: 30px;
+ text-align: center;
+}
+
+.menu {
+ border-top: 6px solid #47CA42;
+ background-color: #0d8921;
+}
+
+.menu .navbar-brand, .menu a { color: #fff; }
+.menu .navbar-nav>.active>a, .menu .navbar-nav>li>a:hover { background-color: #47CA42; }
+
+.sidebar { margin-top: 20px; }
+
+.summary a { color: #333; }
+.summary a:hover { text-decoration: none; }
+.summary a:hover, .summary li:active>a { color: #428bca; }
+.summary li { padding: 2px 0; font-weight: bold }
+.summary li li { font-size: 13px;}
+.summary li li li { font-size: 12px; font-weight: normal }
+
+.breadcrumb { margin-top: 20px; }
--- /dev/null
+wiki.name=nitiwiki
+wiki.desc=proudly powered by nit
+wiki.logo=assets/logo.png
+wiki.root_url=http://moz-code.org/nitiwiki/
+wiki.root_dir=.
+wiki.rsync_dir=moz-code.org:nitiwiki/
--- /dev/null
+../../../README.md
\ No newline at end of file
--- /dev/null
+<footer class="row">
+ <div class="container-fluid">
+ <div class="well well-sm">
+ <p><strong>%TITLE% © %YEAR%</strong></p>
+ <p class="text-muted"><em>last modification %GEN_TIME%</em></p>
+ <p class="text-muted">Proudly powered by
+ <a href="http://nitlanguage.org">nit</a>!</p>
+ </div>
+ </div>
+</footer>
--- /dev/null
+<div class="container-fluid header">
+ <div class="container">
+ <header>
+ <a href="http://uqam.ca"><img src="%ROOT_URL%/%LOGO%" alt="logo" /></a>
+ <h2>%SUBTITLE%</h2>
+ <h1>%TITLE%</h1>
+ </header>
+ </div>
+</div>
--- /dev/null
+<nav class="menu" role="navigation">
+ <div class="container">
+ <!-- Brand and toggle get grouped for better mobile display -->
+ <div class="navbar-header">
+ <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1">
+ <span class="sr-only">Toggle navigation</span>
+ <span class="icon-bar"></span>
+ <span class="icon-bar"></span>
+ <span class="icon-bar"></span>
+ </button>
+ <a class="navbar-brand" href="%ROOT_URL%index.html">%TITLE%</a>
+ </div>
+ <!-- Collect the nav links, forms, and other content for toggling -->
+ <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
+ <ul class="nav navbar-nav">
+ %MENUS%
+ </ul>
+ </div><!-- /.navbar-collapse -->
+ </div>
+</nav>
--- /dev/null
+<!DOCTYPE html>
+<html lang="en">
+ <head>
+ <meta charset="utf-8">
+ <meta http-equiv="X-UA-Compatible" content="IE=edge">
+ <meta name="viewport" content="width=device-width, initial-scale=1">
+ <title>%TITLE%</title>
+
+ <link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.1/css/bootstrap.min.css" rel="stylesheet">
+ <link href="%ROOT_URL%/assets/css/main.css" rel="stylesheet">
+
+ <!-- HTML5 Shim and Respond.js IE8 support of HTML5 elements and media queries -->
+ <!-- WARNING: Respond.js doesn't work if you view the page via file:// -->
+ <!--[if lt IE 9]>
+ <script src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script>
+ <script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
+ <![endif]-->
+ </head>
+ <body>
+ %HEADER%
+ %TOP_MENU%
+ <div class="container">
+ <div class="row">
+ %BODY%
+ </div>
+ %FOOTER%
+ </div>
+
+ <script src="http://code.jquery.com/jquery-1.11.1.min.js"></script>
+ <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.1/js/bootstrap.min.js"></script>
+ </body>
+</html>
--- /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.
+
+# A wiki engine based on markdown files and git.
+module nitiwiki
+
+import wiki_html
+
+# Locate nit directory
+private fun compute_nit_dir(opt_nit_dir: OptionString): String do
+ # the option has precedence
+ var res = opt_nit_dir.value
+ if res != null then
+ if not check_nit_dir(res) then
+ print "Fatal Error: --nit-dir does not seem to be a valid base Nit directory: {res}"
+ exit 1
+ end
+ return res
+ end
+
+ # then the environ variable has precedence
+ res = "NIT_DIR".environ
+ if not res.is_empty then
+ if not check_nit_dir(res) then
+ print "Fatal Error: NIT_DIR does not seem to be a valid base Nit directory: {res}"
+ exit 1
+ end
+ return res
+ end
+
+ # find the runpath of the program from argv[0]
+ res = "{sys.program_name.dirname}/.."
+ if check_nit_dir(res) then return res.simplify_path
+
+ # find the runpath of the process from /proc
+ var exe = "/proc/self/exe"
+ if exe.file_exists then
+ res = exe.realpath
+ res = res.dirname.join_path("..")
+ if check_nit_dir(res) then return res.simplify_path
+ end
+
+ # search in the PATH
+ var ps = "PATH".environ.split(":")
+ for p in ps do
+ res = p/".."
+ if check_nit_dir(res) then return res.simplify_path
+ end
+
+ print "Fatal Error: Cannot locate a valid base nit directory. It is quite unexpected. Try to set the environment variable `NIT_DIR` or to use the `--nit-dir` option."
+ exit 1
+ abort
+end
+
+private fun check_nit_dir(res: String): Bool do
+ return res.file_exists and "{res}/src/nit.nit".file_exists
+end
+
+var opt_help = new OptionBool("Display this help message", "-h", "--help")
+var opt_verbose = new OptionCount("Verbose level", "-v")
+var opt_config = new OptionString("Path to config.ini file", "-c", "--config")
+var opt_init = new OptionBool("Initialize a new wiki in the current directory", "--init")
+var opt_status = new OptionBool("Display wiki status", "-s", "--status")
+var opt_render = new OptionBool("Render the out directory from markdown sources", "-r", "--render")
+var opt_force = new OptionBool("Force render even if source files are unchanged", "-f", "--force")
+var opt_clean = new OptionBool("Clean the output directory", "--clean")
+var opt_rsync = new OptionBool("Synchronize outdir with distant wiki using rsync", "-s", "--rsync")
+var opt_fetch = new OptionBool("Render local source from git repo", "--fetch")
+var opt_nit_dir = new OptionString("Nit base directory", "--nit-dir")
+
+var context = new OptionContext
+context.add_option(opt_help, opt_verbose, opt_config)
+context.add_option(opt_init, opt_status, opt_render, opt_force)
+context.add_option(opt_clean, opt_rsync, opt_fetch, opt_nit_dir)
+context.parse(args)
+
+var config_filename = "config.ini"
+
+# --help
+if opt_help.value then
+ context.usage
+ exit 0
+end
+
+# --init
+if opt_init.value then
+ if config_filename.file_exists then
+ print "Already in a nitiwiki directory."
+ exit 0
+ end
+ var nitiwiki_home = "{compute_nit_dir(opt_nit_dir)}/contrib/nitiwiki"
+ var tpl = "{nitiwiki_home}/examples/default/"
+ if not tpl.file_exists then
+ print "Cannot find {tpl} files."
+ print "Maybe your NIT_DIR is not set properly?"
+ print "You can initialize nitiwiki manually by copying the default skeletton here."
+ exit 1
+ end
+ sys.system "cp -R {tpl}/* ."
+ print "Initialized new nitiwiki."
+ print "Set wiki settings by editing {config_filename}."
+ exit 0
+end
+
+# load config files
+
+# --config
+var config_file = opt_config.value
+if config_file == null then
+ config_file = config_filename
+end
+
+if not config_file.file_exists then
+ print "Not in a nitiwiki directory."
+ print "Use --init to initialize one here."
+ exit 0
+end
+
+var config = new WikiConfig(config_file)
+var wiki = new Nitiwiki(config)
+
+# --verbose
+wiki.verbose_level = opt_verbose.value
+
+# --clean
+if opt_clean.value then
+ wiki.clean
+end
+
+# --fetch
+if opt_fetch.value then
+ wiki.fetch
+end
+
+# --render
+if opt_render.value then
+ wiki.parse
+ # --force
+ wiki.force_render = opt_force.value
+ wiki.render
+end
+
+# --rsync
+if opt_rsync.value then
+ wiki.sync
+end
+
+# --status
+if opt_status.value or args.is_empty then
+ wiki.parse
+ wiki.status
+end
--- /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.
+
+# Base entities of a nitiwiki.
+module wiki_base
+
+import template::macro
+import markdown
+import opts
+import ini
+
+# A Nitiwiki instance.
+#
+# Nitiwiki provide all base services used by `WikiSection` and `WikiArticle`.
+# It manages content and renders pages.
+#
+# Each nitiwiki instance is linked to a config file.
+# This file show to `nitiwiki` that a wiki is present in the current directory.
+# Without it, nitiwiki will consider the directory as empty.
+class Nitiwiki
+
+ # Wiki config object.
+ var config: WikiConfig
+
+ # Default config filename.
+ var config_filename = "config.ini"
+
+ # Force render on all file even if the source is unmodified.
+ var force_render = false is writable
+
+ # Verbosity level.
+ var verbose_level = 0 is writable
+
+ # Delete all the output files.
+ fun clean do
+ var out_dir = expand_path(config.root_dir, config.out_dir)
+ if out_dir.file_exists then out_dir.rmdir
+ end
+
+ # Synchronize local output with the distant `WikiConfig::rsync_dir`.
+ fun sync do
+ var root = expand_path(config.root_dir, config.out_dir)
+ sys.system "rsync -vr --delete {root}/ {config.rsync_dir}"
+ end
+
+ fun fetch do
+ sys.system "git pull {config.git_origin} {config.git_branch}"
+ end
+
+ # Analyze wiki files from `dir` to build wiki entries.
+ #
+ # This method build a hierarchical structure of `WikiSection` and `WikiArticle`
+ # based on the markdown source structure.
+ fun parse do
+ var dir = expand_path(config.root_dir, config.source_dir)
+ root_section = new_section(dir)
+ var files = list_md_files(dir)
+ for file in files do
+ new_article(file)
+ end
+ end
+
+ # Show wiki status.
+ fun status do
+ print "nitiWiki"
+ print "name: {config.wiki_name}"
+ print "config: {config.ini_file}"
+ print "url: {config.root_url}"
+ print ""
+ if root_section.is_dirty then
+ print "There is modified files:"
+ var paths = entries.keys.to_a
+ var s = new DefaultComparator
+ s.sort(paths)
+ for path in paths do
+ var entry = entries[path]
+ if not entry.is_dirty then continue
+ var name = entry.name
+ if entry.has_source then name = entry.src_path.to_s
+ if entry.is_new then
+ print " + {name}"
+ else
+ print " * {name}"
+ end
+ end
+ print ""
+ print "Use nitiwiki --render to render modified files"
+ else
+ print "Wiki is up-to-date"
+ print ""
+ print "Use nitiwiki --fetch to pull modification from origin"
+ print "Use nitiwiki --rsync to synchronize distant output"
+ end
+ end
+
+ # Display msg if `level >= verbose_level`
+ fun message(msg: String, level: Int) do
+ if level <= verbose_level then print msg
+ end
+
+ # List markdown source files from a directory.
+ fun list_md_files(dir: String): Array[String] do
+ var files = new Array[String]
+ var pipe = new IProcess("find", dir, "-name", "*.md")
+ while not pipe.eof do
+ var file = pipe.read_line
+ if file == "" then break # last line
+ file = file.substring(0, file.length - 1) # strip last oef
+ var name = file.basename(".md")
+ if name == "header" or name == "footer" or name == "menu" then continue
+ files.add file
+ end
+ pipe.close
+ pipe.wait
+ if pipe.status != 0 then exit 1
+ var s = new DefaultComparator
+ s.sort(files)
+ return files
+ end
+
+ # Does `src` have been modified since `target` creation?
+ #
+ # Always returns `true` if `--force` is on.
+ fun need_render(src, target: String): Bool do
+ if force_render then return true
+ if not target.file_exists then return true
+ return src.file_stat.mtime >= target.file_stat.mtime
+ end
+
+ # Create a new `WikiSection`.
+ #
+ # `path` is used to determine the place in the wiki hierarchy.
+ protected fun new_section(path: String): WikiSection do
+ path = path.simplify_path
+ if entries.has_key(path) then return entries[path].as(WikiSection)
+ var root = expand_path(config.root_dir, config.source_dir)
+ var name = path.basename("")
+ var section = new WikiSection(self, name)
+ entries[path] = section
+ if path == root then return section
+ var ppath = path.dirname
+ if ppath != path then
+ var parent = new_section(ppath)
+ parent.add_child(section)
+ end
+ section.try_load_config
+ return section
+ end
+
+ # Create a new `WikiArticle`.
+ #
+ # `path` is used to determine the ancestor sections.
+ protected fun new_article(path: String): WikiArticle do
+ if entries.has_key(path) then return entries[path].as(WikiArticle)
+ var article = new WikiArticle.from_source(self, path)
+ var section = new_section(path.dirname)
+ section.add_child(article)
+ entries[path] = article
+ return article
+ end
+
+ # Wiki entries found in the last `lookup_hierarchy`.
+ var entries = new HashMap[String, WikiEntry]
+
+ # The root `WikiSection` of the site found in the last `lookup_hierarchy`.
+ var root_section: WikiSection is noinit
+
+ # Does a template named `name` exists for this wiki?
+ fun has_template(name: String): Bool do
+ return expand_path(config.root_dir, config.templates_dir, name).file_exists
+ end
+
+ # Load a template file as a `TemplateString`.
+ #
+ # REQUIRE: `has_template`
+ fun load_template(name: String): TemplateString do
+ assert has_template(name)
+ var file = expand_path(config.root_dir, config.templates_dir, name)
+ var tpl = new TemplateString.from_file(file)
+ if tpl.has_macro("ROOT_URL") then
+ tpl.replace("ROOT_URL", config.root_url)
+ end
+ if tpl.has_macro("TITLE") then
+ tpl.replace("TITLE", config.wiki_name)
+ end
+ if tpl.has_macro("SUBTITLE") then
+ tpl.replace("SUBTITLE", config.wiki_desc)
+ end
+ if tpl.has_macro("LOGO") then
+ tpl.replace("LOGO", config.wiki_logo)
+ end
+ return tpl
+ end
+
+ # Join `parts` as a path and simplify it
+ fun expand_path(parts: String...): String do
+ var path = ""
+ for part in parts do
+ path = path.join_path(part)
+ end
+ return path.simplify_path
+ end
+
+ fun pretty_name(name: String): String do
+ name = name.replace("_", " ")
+ name = name.capitalized
+ return name
+ end
+end
+
+# A wiki is composed of hierarchical entries.
+abstract class WikiEntry
+
+ # `Nitiwiki` this entry belongs to.
+ var wiki: Nitiwiki
+
+ # Entry data
+
+ # Entry internal name.
+ #
+ # Mainly used in urls.
+ var name: String
+
+ # Displayed title for `self`.
+ #
+ # If `self` is the root entry then display the wiki `WikiConfig::wiki_name` instead.
+ fun title: String do
+ if is_root then return wiki.config.wiki_name
+ return wiki.pretty_name(name)
+ end
+
+ # Is this section rendered from a source document?
+ #
+ # Source is an abstract concept at this level.
+ # It can represent a directory, a source file,
+ # a part of a file, everything needed to
+ # extend this base framework.
+ fun has_source: Bool do return src_path != null
+
+ # Entry creation time.
+ #
+ # Returns `-1` if not `has_source`.
+ fun create_time: Int do
+ if not has_source then return -1
+ return src_full_path.file_stat.ctime
+ end
+
+ # Entry last modification time.
+ #
+ # Returns `-1` if not `has_source`.
+ fun last_edit_time: Int do
+ if not has_source then return -1
+ return src_full_path.file_stat.mtime
+ end
+
+ # Entry list rendering time.
+ #
+ # Returns `-1` if `is_new`.
+ fun last_render_time: Int do
+ if is_new then return -1
+ return out_full_path.file_stat.mtime
+ end
+
+ # Entries hierarchy
+
+ # Type of the parent entry.
+ type PARENT: WikiEntry
+
+ # Parent entry if any.
+ var parent: nullable PARENT = null
+
+ # Does `self` have a parent?
+ fun is_root: Bool do return parent == null
+
+ # Children labelled by `name`.
+ var children = new HashMap[String, WikiEntry]
+
+ # Does `self` have a child nammed `name`?
+ fun has_child(name: String): Bool do return children.keys.has(name)
+
+ # Retrieve the child called `name`.
+ fun child(name: String): WikiEntry do return children[name]
+
+ # Add a sub-entry to `self`.
+ fun add_child(entry: WikiEntry) do
+ entry.parent = self
+ children[entry.name] = entry
+ end
+
+ # Paths and urls
+
+ # Breadcrumbs from the `Nitiwiki::root_section` to `self`.
+ #
+ # Result is returned as an array containg ordered entries:
+ # `breadcrumbs.first` is the root entry and
+ # `breadcrumbs.last == self`
+ fun breadcrumbs: Array[WikiEntry] is cached do
+ var path = new Array[WikiEntry]
+ var entry: nullable WikiEntry = self
+ while entry != null and not entry.is_root do
+ path.add entry
+ entry = entry.parent
+ end
+ return path.reversed
+ end
+
+ # Relative path from `wiki.config.root_dir` to source if any.
+ fun src_path: nullable String is abstract
+
+ # Absolute path to the source if any.
+ fun src_full_path: nullable String do
+ var src = src_path
+ if src == null then return null
+ return wiki.config.root_dir.join_path(src)
+ end
+
+ # Relative path from `wiki.config.root_dir` to rendered output.
+ #
+ # Like `src_path`, this method can represent a
+ # directory or a file.
+ fun out_path: String is abstract
+
+ # Absolute path to the output.
+ fun out_full_path: String do return wiki.config.root_dir.join_path(out_path)
+
+ # Rendering
+
+ # Does `self` have already been rendered?
+ fun is_new: Bool do return not out_full_path.file_exists
+
+ # Does `self` rendered output is outdated?
+ #
+ # Returns `true` if `is_new` then check in children.
+ fun is_dirty: Bool do
+ if is_new then return true
+ if has_source then
+ if last_edit_time >= last_render_time then return true
+ end
+ for child in children.values do
+ if child.is_dirty then return true
+ end
+ return false
+ end
+
+ # Render `self` and `children` is needed.
+ fun render do for child in children.values do child.render
+
+ # Templating
+
+ # Template file for `self`.
+ #
+ # Each entity can use a custom template.
+ # By default the template is inherited from the parent.
+ #
+ # If the root does not have a custom template,
+ # then returns the main wiki template file.
+ fun template_file: String do
+ if is_root then return wiki.config.template_file
+ return parent.template_file
+ end
+
+ # Header template file for `self`.
+ #
+ # Behave like `template_file`.
+ fun header_file: String do
+ if is_root then return wiki.config.header_file
+ return parent.header_file
+ end
+
+ # Footer template file for `self`.
+ #
+ # Behave like `template_file`.
+ fun footer_file: String do
+ if is_root then return wiki.config.footer_file
+ return parent.footer_file
+ end
+
+ # Menu template file for `self`.
+ #
+ # Behave like `template_file`.
+ fun menu_file: String do
+ if is_root then return wiki.config.menu_file
+ return parent.menu_file
+ end
+
+ # Display the entry `name`.
+ redef fun to_s do return name
+end
+
+# Each WikiSection is related to a source directory.
+#
+# A section can contain other sub-sections or pages.
+class WikiSection
+ super WikiEntry
+
+ # A section can only have another section as parent.
+ redef type PARENT: WikiSection
+
+ redef fun title do
+ if has_config then
+ var title = config.title
+ if title != null then return title
+ end
+ return super
+ end
+
+ # Is this section hidden?
+ #
+ # Hidden section are rendered but not linked in menus.
+ fun is_hidden: Bool do
+ if has_config then return config.is_hidden
+ return false
+ end
+
+ # Source directory.
+ redef fun src_path: String do
+ if parent == null then
+ return wiki.config.source_dir
+ else
+ return wiki.expand_path(parent.src_path, name)
+ end
+ end
+
+ # Config
+
+ # Custom configuration file for this section.
+ var config: nullable SectionConfig = null
+
+ # Does this section have its own config file?
+ fun has_config: Bool do return config != null
+
+ # Try to load the config file for this section.
+ private fun try_load_config do
+ var cfile = wiki.expand_path(wiki.config.root_dir, src_path, wiki.config_filename)
+ if not cfile.file_exists then return
+ wiki.message("Custom config for section {name}", 2)
+ config = new SectionConfig(cfile)
+ end
+
+ # Templating
+
+ # Also check custom config.
+ redef fun template_file do
+ if has_config then
+ var tpl = config.template_file
+ if tpl != null then return tpl
+ end
+ if is_root then return wiki.config.template_file
+ return parent.template_file
+ end
+
+ # Also check custom config.
+ redef fun header_file do
+ if has_config then
+ var tpl = config.header_file
+ if tpl != null then return tpl
+ end
+ if is_root then return wiki.config.header_file
+ return parent.header_file
+ end
+
+ # Also check custom config.
+ redef fun footer_file do
+ if has_config then
+ var tpl = config.footer_file
+ if tpl != null then return tpl
+ end
+ if is_root then return wiki.config.footer_file
+ return parent.footer_file
+ end
+
+ # Also check custom config.
+ redef fun menu_file do
+ if has_config then
+ var tpl = config.menu_file
+ if tpl != null then return tpl
+ end
+ if is_root then return wiki.config.menu_file
+ return parent.menu_file
+ end
+end
+
+# Each WikiArticle is related to a HTML file.
+#
+# Article can be created from scratch using this API or
+# automatically from a markdown source file (see: `from_source`).
+class WikiArticle
+ super WikiEntry
+
+ # Articles can only have `WikiSection` as parents.
+ redef type PARENT: WikiSection
+
+ redef fun title: String do
+ if name == "index" and parent != null then return parent.title
+ return super
+ end
+
+ # Page content.
+ #
+ # What you want to be displayed in the page.
+ var content: nullable Streamable = null
+
+ # Headlines ids and titles.
+ var headlines = new ArrayMap[String, HeadLine]
+
+ # Create a new articleu sing a markdown source file.
+ init from_source(wiki: Nitiwiki, md_file: String) do
+ src_full_path = md_file
+ init(wiki, md_file.basename(".md"))
+ var md_proc = new MarkdownProcessor
+ content = md_proc.process(md)
+ headlines = md_proc.emitter.decorator.headlines
+ end
+
+ redef var src_full_path: nullable String = null
+
+ redef fun src_path do
+ if src_full_path == null then return null
+ return src_full_path.substring_from(wiki.config.root_dir.length)
+ end
+
+ # The page markdown source content.
+ #
+ # Extract the markdown text from `source_file`.
+ #
+ # REQUIRE: `has_source`.
+ fun md: String is cached do
+ assert has_source
+ var file = new IFStream.open(src_full_path.to_s)
+ var md = file.read_all
+ file.close
+ return md
+ end
+
+ # Returns true if has source and
+ # `last_edit_date` > 'last_render_date'.
+ redef fun is_dirty do
+ if super then return true
+ if has_source then
+ return wiki.need_render(src_full_path.to_s, out_full_path)
+ end
+ return false
+ end
+
+ redef fun to_s do return "{name} ({parent or else "null"})"
+end
+
+# Wiki configuration class.
+#
+# This class provides services that ensure static typing when accessing the `config.ini` file.
+class WikiConfig
+ super ConfigTree
+
+ # Returns the config value at `key` or return `default` if no key was found.
+ private fun value_or_default(key: String, default: String): String do
+ if not has_key(key) then return default
+ return self[key]
+ end
+
+ # Site name displayed.
+ #
+ # The title is used as home title and in headers.
+ #
+ # * key: `wiki.name`
+ # * default: `MyWiki`
+ fun wiki_name: String is cached do return value_or_default("wiki.name", "MyWiki")
+
+ # Site description.
+ #
+ # Displayed in header.
+ #
+ # * key: `wiki.desc`
+ # * default: ``
+ fun wiki_desc: String is cached do return value_or_default("wiki.desc", "")
+
+ # Site logo url.
+ #
+ # Url of the image to be displayed in header.
+ #
+ # * key: `wiki.logo`
+ # * default: ``
+ fun wiki_logo: String is cached do return value_or_default("wiki.logo", "")
+
+ # Root url of the wiki.
+ #
+ # * key: `wiki.root_url`
+ # * default: `http://localhost/`
+ fun root_url: String is cached do return value_or_default("wiki.root_url", "http://localhost/")
+
+
+ # Root directory of the wiki.
+ #
+ # Directory where the wiki files are stored locally.
+ #
+ # * key: `wiki.root_dir`
+ # * default: `./`
+ fun root_dir: String is cached do return value_or_default("wiki.root_dir", "./").simplify_path
+
+ # Pages directory.
+ #
+ # Directory where markdown source files are stored.
+ #
+ # * key: `wiki.source_dir
+ # * default: `pages/`
+ fun source_dir: String is cached do
+ return value_or_default("wiki.source_dir", "pages/").simplify_path
+ end
+
+ # Output directory.
+ #
+ # Directory where public wiki files are generated.
+ # **This path MUST be relative to `root_dir`.**
+ #
+ # * key: `wiki.out_dir`
+ # * default: `out/`
+ fun out_dir: String is cached do return value_or_default("wiki.out_dir", "out/").simplify_path
+
+ # Asset files directory.
+ #
+ # Directory where public assets like JS scripts or CSS files are stored.
+ # **This path MUST be relative to `root_dir`.**
+ #
+ # * key: `wiki.assets_dir`
+ # * default: `assets/`
+ fun assets_dir: String is cached do
+ return value_or_default("wiki.assets_dir", "assets/").simplify_path
+ end
+
+ # Template files directory.
+ #
+ # Directory where template used in HTML generation are stored.
+ # **This path MUST be relative to `root_dir`.**
+ #
+ # * key: `wiki.templates_dir`
+ # * default: `templates/`
+ fun templates_dir: String is cached do
+ return value_or_default("wiki.templates_dir", "templates/").simplify_path
+ end
+
+ # Main template file.
+ #
+ # The main template is used to specify the overall structure of a page.
+ #
+ # * key: `wiki.template`
+ # * default: `template.html`
+ fun template_file: String is cached do
+ return value_or_default("wiki.template", "template.html")
+ end
+
+ # Main header template file.
+ #
+ # Used to specify the structure of the page header.
+ # This is generally the place where you want to put your logo and wiki title.
+ #
+ # * key: `wiki.header`
+ # * default: `header.html`
+ fun header_file: String is cached do
+ return value_or_default("wiki.header", "header.html")
+ end
+
+ # Main menu template file.
+ #
+ # Used to specify the menu structure.
+ #
+ # * key: `wiki.menu`
+ # * default: `menu.html`
+ fun menu_file: String is cached do
+ return value_or_default("wiki.menu", "menu.html")
+ end
+
+ # Main footer file.
+ #
+ # The main footer is used to specify the structure of the page footer.
+ # This is generally the place where you want to put your copyright.
+ #
+ # * key: `wiki.footer`
+ # * default: `footer.html`
+ fun footer_file: String is cached do
+ return value_or_default("wiki.footer", "footer.html")
+ end
+
+ # Directory used by rsync to upload wiki files.
+ #
+ # This information is used to update your distant wiki files (like the webserver).
+ #
+ # * key: `wiki.rsync_dir`
+ # * default: ``
+ fun rsync_dir: String is cached do return value_or_default("wiki.rsync_dir", "")
+
+ # Remote repository used to pull modifications on sources.
+ #
+ # * key: `wiki.git_origin`
+ # * default: `origin`
+ fun git_origin: String is cached do return value_or_default("wiki.git_origin", "origin")
+
+ # Remote branch used to pull modifications on sources.
+ #
+ # * key: `wiki.git_branch`
+ # * default: `master`
+ fun git_branch: String is cached do return value_or_default("wiki.git_branch", "master")
+end
+
+# WikiSection custom configuration.
+#
+# Each section can provide its own config file to customize
+# appearance or behavior.
+class SectionConfig
+ super ConfigTree
+
+ # Returns the config value at `key` or `null` if no key was found.
+ private fun value_or_null(key: String): nullable String do
+ if not has_key(key) then return null
+ return self[key]
+ end
+
+ # Is this section hidden in sitemap and trees and menus?
+ fun is_hidden: Bool do return value_or_null("section.hidden") == "true"
+
+ # Custom section title if any.
+ fun title: nullable String do return value_or_null("section.title")
+
+ # Custom template file if any.
+ fun template_file: nullable String do return value_or_null("section.template")
+
+ # Custom header file if any.
+ fun header_file: nullable String do return value_or_null("section.header")
+
+ # Custom menu file if any.
+ fun menu_file: nullable String do return value_or_null("section.menu")
+
+ # Custom footer file if any.
+ fun footer_file: nullable String do return value_or_null("section.footer")
+end
--- /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.
+
+# HTML wiki rendering
+module wiki_html
+
+import wiki_base
+
+redef class Nitiwiki
+
+ # Render HTML output looking for changes in the markdown sources.
+ fun render do
+ if not root_section.is_dirty and not force_render then return
+ var out_dir = expand_path(config.root_dir, config.out_dir)
+ out_dir.mkdir
+ copy_assets
+ root_section.add_child make_sitemap
+ root_section.render
+ end
+
+ # Copy the asset directory to the (public) output directory.
+ private fun copy_assets do
+ var src = expand_path(config.root_dir, config.assets_dir)
+ var out = expand_path(config.root_dir, config.out_dir)
+ if need_render(src, expand_path(out, config.assets_dir)) then
+ if src.file_exists then sys.system "cp -R {src} {out}"
+ end
+ end
+
+ # Build the wiki sitemap page.
+ private fun make_sitemap: WikiSitemap do
+ var sitemap = new WikiSitemap(self, "sitemap")
+ sitemap.is_dirty = true
+ return sitemap
+ end
+end
+
+redef class WikiEntry
+
+ # Url to `self` once generated.
+ fun url: String do return wiki.config.root_url.join_path(breadcrumbs.join("/"))
+
+ # Get a `<a>` template link to `self`
+ fun tpl_link: Streamable do
+ return "<a href=\"{url}\">{title}</a>"
+ end
+end
+
+redef class WikiSection
+
+ # Output directory (where to ouput the HTML pages for this section).
+ redef fun out_path: String do
+ if parent == null then
+ return wiki.config.out_dir
+ else
+ return wiki.expand_path(parent.out_path, name)
+ end
+ end
+
+ redef fun render do
+ if not is_dirty and not wiki.force_render then return
+ if is_new then
+ out_full_path.mkdir
+ else
+ sys.system "touch {out_full_path}"
+ end
+ if has_source then
+ wiki.message("Render section {out_path}", 1)
+ copy_files
+ end
+ var index = self.index
+ if index isa WikiSectionIndex then
+ index.is_dirty = true
+ add_child index
+ end
+ super
+ end
+
+ # Copy attached files from `src_path` to `out_path`.
+ private fun copy_files do
+ assert has_source
+ var dir = src_full_path.to_s
+ for name in dir.files do
+ if name == wiki.config_filename then continue
+ if name.has_suffix(".md") then continue
+ if has_child(name) then continue
+ var src = wiki.expand_path(dir, name)
+ var out = wiki.expand_path(out_full_path, name)
+ if not wiki.need_render(src, out) then continue
+ sys.system "cp -R {src} {out_full_path}"
+ end
+ end
+
+ # The index page for this section.
+ #
+ # If no file `index.md` exists for this section,
+ # a summary is generated using contained articles.
+ fun index: WikiArticle is cached do
+ for child in children.values do
+ if child isa WikiArticle and child.is_index then return child
+ end
+ return new WikiSectionIndex(wiki, self)
+ end
+
+ redef fun tpl_link do return index.tpl_link
+
+ # Render the section hierarchy as a html tree.
+ #
+ # `limit` is used to specify the max-depth of the tree.
+ #
+ # The generated tree will be something like this:
+ #
+ # ~~~html
+ # <ul>
+ # <li>section 1</li>
+ # <li>section 2
+ # <ul>
+ # <li>section 2.1</li>
+ # <li>section 2.2</li>
+ # </ul>
+ # </li>
+ # </ul>
+ # ~~~
+ fun tpl_tree(limit: Int): Template do
+ return tpl_tree_intern(limit, 1)
+ end
+
+ # Build the template tree for this section recursively.
+ protected fun tpl_tree_intern(limit, count: Int): Template do
+ var out = new Template
+ var index = index
+ out.add "<li>"
+ out.add tpl_link
+ if (limit < 0 or count < limit) and
+ (children.length > 1 or (children.length == 1)) then
+ out.add " <ul>"
+ for child in children.values do
+ if child == index then continue
+ if child isa WikiArticle then
+ out.add "<li>"
+ out.add child.tpl_link
+ out.add "</li>"
+ else if child isa WikiSection and not child.is_hidden then
+ out.add child.tpl_tree_intern(limit, count + 1)
+ end
+ end
+ out.add " </ul>"
+ end
+ out.add "</li>"
+ return out
+ end
+end
+
+redef class WikiArticle
+
+ redef fun out_path: String do
+ if parent == null then
+ return wiki.expand_path(wiki.config.out_dir, "{name}.html")
+ else
+ return wiki.expand_path(parent.out_path, "{name}.html")
+ end
+ end
+
+ redef fun url do
+ if parent == null then
+ return wiki.config.root_url.join_path("{name}.html")
+ else
+ return parent.url.join_path("{name}.html")
+ end
+ end
+
+ # Is `self` an index page?
+ #
+ # Checks if `self.name == "index"`.
+ fun is_index: Bool do return name == "index"
+
+ redef fun render do
+ if not is_dirty and not wiki.force_render then return
+ wiki.message("Render article {name}", 2)
+ var file = out_full_path
+ file.dirname.mkdir
+ tpl_page.write_to_file file
+ super
+ end
+
+
+ # Replace macros in the template by wiki data.
+ private fun tpl_page: TemplateString do
+ var tpl = wiki.load_template(template_file)
+ if tpl.has_macro("TOP_MENU") then
+ tpl.replace("TOP_MENU", tpl_menu)
+ end
+ if tpl.has_macro("HEADER") then
+ tpl.replace("HEADER", tpl_header)
+ end
+ if tpl.has_macro("BODY") then
+ tpl.replace("BODY", tpl_article)
+ end
+ if tpl.has_macro("FOOTER") then
+ tpl.replace("FOOTER", tpl_footer)
+ end
+ return tpl
+ end
+
+ # Generate the HTML header for this article.
+ fun tpl_header: Streamable do
+ var file = header_file
+ if not wiki.has_template(file) then return ""
+ return wiki.load_template(file)
+ end
+
+ # Generate the HTML page for this article.
+ fun tpl_article: TplArticle do
+ var article = new TplArticle
+ article.body = content
+ article.breadcrumbs = new TplBreadcrumbs(self)
+ tpl_sidebar.blocks.add tpl_summary
+ article.sidebar = tpl_sidebar
+ return article
+ end
+
+ # Sidebar for this page.
+ var tpl_sidebar = new TplSidebar
+
+ # Generate the HTML summary for this article.
+ #
+ # Based on `headlines`
+ fun tpl_summary: Streamable do
+ var headlines = self.headlines
+ var tpl = new Template
+ tpl.add "<ul class=\"summary list-unstyled\">"
+ var iter = headlines.iterator
+ while iter.is_ok do
+ var hl = iter.item
+ # parse title as markdown
+ var title = hl.title.md_to_html.to_s
+ title = title.substring(3, title.length - 8)
+ tpl.add "<li><a href=\"#{hl.id}\">{title}</a>"
+ iter.next
+ if iter.is_ok then
+ if iter.item.level > hl.level then
+ tpl.add "<ul class=\"list-unstyled\">"
+ else if iter.item.level < hl.level then
+ tpl.add "</li>"
+ tpl.add "</ul>"
+ end
+ else
+ tpl.add "</li>"
+ end
+ end
+ tpl.add "</ul>"
+ return tpl
+ end
+
+ # Generate the HTML menu for this article.
+ fun tpl_menu: Streamable do
+ var file = menu_file
+ if not wiki.has_template(file) then return ""
+ var tpl = wiki.load_template(file)
+ if tpl.has_macro("MENUS") then
+ var items = new Template
+ for child in wiki.root_section.children.values do
+ if child isa WikiArticle and child.is_index then continue
+ if child isa WikiSection and child.is_hidden then continue
+ items.add "<li"
+ if self == child or self.breadcrumbs.has(child) then
+ items.add " class=\"active\""
+ end
+ items.add ">"
+ items.add child.tpl_link
+ items.add "</li>"
+ end
+ tpl.replace("MENUS", items)
+ end
+ return tpl
+ end
+
+ # Generate the HTML footer for this article.
+ fun tpl_footer: Streamable do
+ var file = footer_file
+ if not wiki.has_template(file) then return ""
+ var tpl = wiki.load_template(file)
+ var time = new Tm.gmtime
+ if tpl.has_macro("YEAR") then
+ tpl.replace("YEAR", (time.year + 1900).to_s)
+ end
+ if tpl.has_macro("GEN_TIME") then
+ tpl.replace("GEN_TIME", time.to_s)
+ end
+ return tpl
+ end
+end
+
+# A `WikiArticle` that contains the sitemap tree.
+class WikiSitemap
+ super WikiArticle
+
+ redef fun tpl_article do
+ var article = new TplArticle.with_title("Sitemap")
+ article.body = new TplPageTree(wiki.root_section, -1)
+ return article
+ end
+
+ redef var is_dirty = false
+end
+
+# A `WikiArticle` that contains the section index tree.
+class WikiSectionIndex
+ super WikiArticle
+
+ # The section described by `self`.
+ var section: WikiSection
+
+ init(wiki: Nitiwiki, section: WikiSection) do
+ super(wiki, "index")
+ self.section = section
+ end
+
+ redef var is_dirty = false
+
+ redef fun tpl_article do
+ var article = new TplArticle.with_title(section.title)
+ article.body = new TplPageTree(section, -1)
+ article.breadcrumbs = new TplBreadcrumbs(self)
+ return article
+ end
+end
+
+# Article HTML output.
+class TplArticle
+ super Template
+
+ var title: nullable Streamable = null
+ var body: nullable Streamable = null
+ var sidebar: nullable TplSidebar = null
+ var breadcrumbs: nullable TplBreadcrumbs = null
+
+ init with_title(title: Streamable) do
+ self.title = title
+ end
+
+ redef fun rendering do
+ if sidebar != null then
+ add "<div class=\"col-sm-3 sidebar\">"
+ add sidebar.as(not null)
+ add "</div>"
+ add "<div class=\"col-sm-9 content\">"
+ else
+ add "<div class=\"col-sm-12 content\">"
+ end
+ if body != null then
+ add "<article>"
+ if breadcrumbs != null then
+ add breadcrumbs.as(not null)
+ end
+ if title != null then
+ add "<h1>"
+ add title.as(not null)
+ add "</h1>"
+ end
+ add body.as(not null)
+ add " </article>"
+ end
+ add "</div>"
+ end
+end
+
+# A collection of HTML blocks displayed on the side of a page.
+class TplSidebar
+ super Template
+
+ # Blocks are `Stremable` pieces that will be rendered in the sidebar.
+ var blocks = new Array[Streamable]
+
+ redef fun rendering do
+ for block in blocks do
+ add "<div class=\"sideblock\">"
+ add block
+ add "</div>"
+ end
+ end
+end
+
+# An HTML breadcrumbs that show the path from a `WikiArticle` to the `Nitiwiki` root.
+class TplBreadcrumbs
+ super Template
+
+ # Bread crumb article.
+ var article: WikiArticle
+
+ redef fun rendering do
+ var path = article.breadcrumbs
+ if path.is_empty or path.length <= 2 and article.is_index then return
+ add "<ol class=\"breadcrumb\">"
+ for entry in path do
+ if entry == path.last then
+ add "<li class=\"active\">"
+ add entry.title
+ add "</li>"
+ else
+ if article.parent == entry and article.is_index then continue
+ add "<li>"
+ add entry.tpl_link
+ add "</li>"
+ end
+ end
+ add "</ol>"
+ end
+end
+
+# An HTML tree that show the section pages structure.
+class TplPageTree
+ super Template
+
+ # Builds the page tree from `root`.
+ var root: WikiSection
+
+ # Limits the tree depth to `max_depth` levels.
+ var max_depth: Int
+
+ redef fun rendering do
+ add "<ul>"
+ add root.tpl_tree(-1)
+ add "</ul>"
+ end
+end
--- /dev/null
+# Copyright 2013 Alexandre Terrasa <alexandre@moz-code.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.
+
+all: tests
+
+tests: clean
+ ./tests.sh
+
+clean:
+ rm -rf out/
--- /dev/null
+nitiwiki --config wiki1/config.ini --clean --render -v
--- /dev/null
+nitiwiki --config wiki1/config.ini --clean --status
--- /dev/null
+Not in a nitiwiki directory.
+Use --init to initialize one here.
--- /dev/null
+Render section out
--- /dev/null
+nitiWiki
+name: wiki1
+config: wiki1/config.ini
+url: http://localhost/
+
+There is modified files:
+ + pages
+ + /pages/index.md
+
+Use nitiwiki --render to render modified files
--- /dev/null
+#!/bin/bash
+
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Copyright 2014 Alexandre Terrasa <alexandre@moz-code.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.
+
+BIN=../bin
+OUT=./out
+RES=./res
+
+# check args files
+test_args()
+{
+ local test="$1"
+ local args=`cat $test.args`
+ local outdir=$OUT/$test.files
+
+ echo $BIN/$args > $OUT/$test.bin
+ chmod +x $OUT/$test.bin
+ OUTDIR=$outdir $OUT/$test.bin > $OUT/$test.res 2> $OUT/$test.err
+
+ if [ -r $outdir ]; then
+ ls -aR $outdir >> $OUT/$test.res
+ fi
+
+ diff $OUT/$test.res $RES/$test.res > $OUT/$test.diff 2> /dev/null
+}
+
+# return
+# 0 if the sav not exists
+# 1 if the file does match
+# 2 if the file does not match
+check_result() {
+ local test="$1"
+
+ if [ ! -r "$RES/$test.res" ]; then
+ return 0
+ elif [ ! -s $OUT/$test.diff ]; then
+ return 1
+ else
+ return 2
+ fi
+}
+
+echo "Testing..."
+echo ""
+
+rm -rf $OUT 2>/dev/null
+mkdir $OUT 2>/dev/null
+
+all=0
+ok=0
+ko=0
+sk=0
+
+for file in `ls *.args`; do
+ ((all++))
+ test="${file%.*}"
+ echo -n "* $test: "
+
+ test_args $test
+ check_result $test
+
+ case "$?" in
+ 0)
+ echo "skip ($test.res not found)"
+ ((sk++))
+ continue;;
+ 1)
+ echo "success"
+ ((ok++))
+ ;;
+ 2)
+ echo "error (diff $OUT/$test.res $RES/$test.res)"
+ ((ko++))
+ ;;
+ esac
+done
+echo ""
+echo "==> success $ok/$all ($ko tests failed, $sk skipped)"
--- /dev/null
+dummy { margin: 0 }
--- /dev/null
+wiki.name=wiki1
+wiki.root_dir=wiki1/
--- /dev/null
+wiki.name=wiki2
+wiki.desc=the one used by nit/tests.sh
+wiki.root_dir=../contrib/nitiwiki/tests/wiki1/
--- /dev/null
+# Hello World!
--- /dev/null
+<div class="row footer">
+ <div class="container-fluid">
+ <div class="well well-sm">
+ <p><strong>%TITLE% © %YEAR%</strong></p>
+ <p class="text-muted"><em>last modification %GEN_TIME%</em></p>
+ <p class="text-muted">Proudly powered by
+ <a href="http://nitlanguage.org">nit</a>!</p>
+ </div>
+ </div>
+</div>
--- /dev/null
+<div class="container-fluid header">
+ <div class="container">
+ <div class="header">
+ <a href="http://uqam.ca"><img src="%ROOT_URL%/%LOGO%" alt="logo" /></a>
+ <h2>%SUBTITLE%</h2>
+ <h1>%TITLE%</h1>
+ </div>
+ </div>
+</div>
--- /dev/null
+<nav class="menu" role="navigation">
+ <div class="container">
+ <!-- Brand and toggle get grouped for better mobile display -->
+ <div class="navbar-header">
+ <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1">
+ <span class="sr-only">Toggle navigation</span>
+ <span class="icon-bar"></span>
+ <span class="icon-bar"></span>
+ <span class="icon-bar"></span>
+ </button>
+ <a class="navbar-brand" href="%ROOT_URL%index.html">%TITLE%</a>
+ </div>
+ <!-- Collect the nav links, forms, and other content for toggling -->
+ <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
+ <ul class="nav navbar-nav">
+ %MENUS%
+ </ul>
+ </div><!-- /.navbar-collapse -->
+ </div>
+</nav>
--- /dev/null
+<!DOCTYPE html>
+<html lang="en">
+ <head>
+ <meta charset="utf-8">
+ <meta http-equiv="X-UA-Compatible" content="IE=edge">
+ <meta name="viewport" content="width=device-width, initial-scale=1">
+ <title>%TITLE%</title>
+
+ <link href="%ROOT_URL%/assets/vendors/bootstrap/bootstrap-3.2.0-dist/css/bootstrap.min.css" rel="stylesheet">
+ <link href="%ROOT_URL%/assets/css/main.css" rel="stylesheet">
+
+ <!-- HTML5 Shim and Respond.js IE8 support of HTML5 elements and media queries -->
+ <!-- WARNING: Respond.js doesn't work if you view the page via file:// -->
+ <!--[if lt IE 9]>
+ <script src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script>
+ <script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
+ <![endif]-->
+ </head>
+ <body>
+ %HEADER%
+ %TOP_MENU%
+ <div class="container">
+ <div class="row">
+ %BODY%
+ </div>
+ %FOOTER%
+ </div>
+
+ <script src="%ROOT_URL%/vendors/jquery/jquery-1.11.1.min.js"></script>
+ <script src="%ROOT_URL%/vendors/bootstrap/bootstrap-3.2.0-dist/js/bootstrap.min.js"></script>
+ </body>
+</html>
import interpreter::debugger
import pnacl
intrude import toolcontext
-intrude import modelbuilder
+intrude import loader
intrude import standard::file
# We redefine exit to start a new thread before killing the one that called exit.
--- /dev/null
+all:
+ ${MAKE} docs -C ..
+++ /dev/null
-This directory contains various documentation for Nit
-
-* advanced_options [TXT]: documentation for advanced options of the compiler and run-time execution.
-* stdlib [HTML]: Autodocumentation for the Nit standard library.
-
-For more documentation, visit http://nitlanguage.org/doc/
--- /dev/null
+This directory contains auto-documentation generated by nitdoc.
+
+ * [stdlib](http://nitlanguage.org/doc/stdlib/): the Nit libraries (from `../lib/`).
+ * [nitc](http://nitlanguage.org/doc/nitc/): the Nit tools (from `../src/`).
+
+Run `make` to produce them.
+
+Specific documentation can be found elsewhere:
+
+ * The manpages of the Nit tools are in the directory `../share/man`
+ * The documentation of the other tools and programs are in their subdirectories in `../examples` and `../contrib`
+ * For more documentation, visit <http://nitlanguage.org/doc/>
all:
mkdir -p bin/
- ../../bin/nitg --dir bin/ src/calculator_test.nit src/calculator_gtk.nit
+ ../../bin/nitg --dir bin/ src/calculator_gtk.nit src/calculator_test.nit
+
+android:
+ mkdir -p bin/ res/
+ ../../contrib/inkscape_tools/bin/svg_to_icons art/icon.svg --android --out res/
+ ../../bin/nitg -o bin/calculator.apk src/calculator_android.nit
--- /dev/null
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="512"
+ height="512"
+ id="svg2"
+ version="1.1"
+ inkscape:version="0.48.5 r10040"
+ sodipodi:docname="icon.svg">
+ <defs
+ id="defs4" />
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="0.9899495"
+ inkscape:cx="58.64005"
+ inkscape:cy="380.00465"
+ inkscape:document-units="px"
+ inkscape:current-layer="layer1"
+ showgrid="false"
+ inkscape:window-width="1601"
+ inkscape:window-height="1316"
+ inkscape:window-x="2646"
+ inkscape:window-y="84"
+ inkscape:window-maximized="0" />
+ <metadata
+ id="metadata7">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title />
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:label="Layer 1"
+ inkscape:groupmode="layer"
+ id="layer1"
+ transform="translate(0,-540.36218)">
+ <rect
+ style="fill:#4d4d4d;fill-opacity:1;stroke:#000000;stroke-opacity:1;stroke-width:5;stroke-miterlimit:4;stroke-dasharray:none"
+ id="rect2987"
+ width="500"
+ height="500"
+ x="5.9999847"
+ y="546.36218"
+ rx="64"
+ ry="64" />
+ <rect
+ ry="48"
+ rx="48"
+ y="569.2193"
+ x="32.42857"
+ height="211.42856"
+ width="211.42856"
+ id="rect2989"
+ style="fill:#cccccc;fill-opacity:1;stroke:#000000;stroke-opacity:1;stroke-width:5;stroke-miterlimit:4;stroke-dasharray:none" />
+ <rect
+ style="fill:#cccccc;fill-opacity:1;stroke:#000000;stroke-opacity:1;stroke-width:5;stroke-miterlimit:4;stroke-dasharray:none"
+ id="rect2991"
+ width="211.42856"
+ height="211.42856"
+ x="268.14285"
+ y="569.2193"
+ rx="48"
+ ry="48" />
+ <rect
+ style="fill:#cccccc;fill-opacity:1;stroke:#000000;stroke-opacity:1;stroke-width:5;stroke-miterlimit:4;stroke-dasharray:none"
+ id="rect2993"
+ width="211.42856"
+ height="211.42856"
+ x="32.42857"
+ y="806.36218"
+ rx="48"
+ ry="48" />
+ <rect
+ ry="48"
+ rx="48"
+ y="806.36218"
+ x="268.14285"
+ height="211.42856"
+ width="211.42856"
+ id="rect2995"
+ style="fill:#cccccc;fill-opacity:1;stroke:#000000;stroke-opacity:1;stroke-width:5;stroke-miterlimit:4;stroke-dasharray:none" />
+ <text
+ xml:space="preserve"
+ style="font-size:269.1137085px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Droid Sans;-inkscape-font-specification:Droid Sans"
+ x="299.74573"
+ y="770.06946"
+ id="text2997"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan2999"
+ x="299.74573"
+ y="770.06946">+</tspan></text>
+ <path
+ inkscape:connector-curvature="0"
+ id="path3018"
+ style="font-size:269.1137085px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Droid Sans;-inkscape-font-specification:Droid Sans"
+ d="m 313.14886,921.9317 0,-19.71047 121.41654,0 0,19.71047"
+ sodipodi:nodetypes="cccc" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path2995"
+ style="font-size:202.30386353px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Droid Sans;-inkscape-font-specification:Droid Sans"
+ d="m 170.83821,674.43965 c -1e-4,11.65624 -0.8562,22.0941 -2.56831,31.31363 -1.64645,9.21961 -4.34646,17.02331 -8.10005,23.41114 -3.68792,6.38786 -8.46234,11.26106 -14.32328,14.61962 -5.86108,3.35856 -12.97332,5.03783 -21.33673,5.03784 -7.77084,-10e-6 -14.5538,-1.67928 -20.34892,-5.03784 -5.729341,-3.35856 -10.50376,-8.23176 -14.323274,-14.61962 -3.753702,-6.38783 -6.585427,-14.19153 -8.495182,-23.41114 -1.843926,-9.21953 -2.765883,-19.65739 -2.765873,-31.31363 -10e-6,-11.6561 0.823166,-22.09397 2.46953,-31.31364 1.712193,-9.21946 4.379282,-16.99024 8.001275,-23.31236 3.687807,-6.38772 8.4293,-11.26092 14.224494,-14.61961 5.86097,-3.35842 12.94028,-5.0377 21.23795,-5.03784 7.83658,1.4e-4 14.65247,1.67942 20.4477,5.03784 5.79508,3.29284 10.60243,8.13311 14.42206,14.52083 3.81944,6.32212 6.68409,14.09289 8.59396,23.31236 1.90967,9.21967 2.86455,19.69047 2.86465,31.41242 m -73.9871,0 c -2.8e-5,9.87818 0.493877,18.50506 1.481718,25.88067 0.987781,7.3757 2.568282,13.53305 4.741492,18.47208 2.17315,4.87322 5.00488,8.56105 8.49518,11.06349 3.55608,2.43662 7.86952,3.65492 12.94034,3.6549 5.07071,2e-5 9.38415,-1.21828 12.94033,-3.6549 3.55605,-2.43658 6.45363,-6.09148 8.69275,-10.96471 2.30481,-4.87317 3.95116,-10.9976 4.93906,-18.3733 1.05358,-7.44146 1.58041,-16.1342 1.5805,-26.07823 -9e-5,-9.87804 -0.52692,-18.50492 -1.5805,-25.88068 -0.9879,-7.37555 -2.63425,-13.49998 -4.93906,-18.3733 -2.23912,-4.87308 -5.1367,-8.52798 -8.69275,-10.96471 -3.55618,-2.43647 -7.86962,-3.65477 -12.94033,-3.6549 -5.07082,1.3e-4 -9.38426,1.21843 -12.94034,3.6549 -3.4903,2.43673 -6.32203,6.09163 -8.49518,10.96471 -2.17321,4.87332 -3.753711,10.99775 -4.741492,18.3733 -0.987841,7.37576 -1.481746,16.00264 -1.481718,25.88068" />
+ <path
+ inkscape:connector-curvature="0"
+ id="path2997"
+ style="font-size:202.30386353px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Droid Sans;-inkscape-font-specification:Droid Sans"
+ d="m 179.68975,735.88154 c -1e-5,-2.50244 0.32926,-4.60977 0.98782,-6.32199 0.65852,-1.77805 1.54755,-3.19391 2.66709,-4.2476 1.1195,-1.11949 2.43658,-1.90974 3.95125,-2.37074 1.51462,-0.52681 3.16097,-0.79023 4.93905,-0.79025 1.71218,2e-5 3.32561,0.26344 4.84028,0.79025 1.58047,0.461 2.93048,1.25125 4.05003,2.37074 1.11948,1.05369 2.00851,2.46955 2.66709,4.2476 0.65851,1.71222 0.98778,3.81955 0.98782,6.32199 -4e-5,2.43661 -0.32931,4.54394 -0.98782,6.322 -0.65858,1.71221 -1.54761,3.12807 -2.66709,4.24759 -1.11955,1.11952 -2.46956,1.94269 -4.05003,2.46953 -1.51467,0.52683 -3.1281,0.79024 -4.84028,0.79025 -1.77808,-10e-6 -3.42443,-0.26342 -4.93905,-0.79025 -1.51467,-0.52684 -2.83175,-1.35001 -3.95125,-2.46953 -1.11954,-1.11952 -2.00857,-2.53538 -2.66709,-4.24759 -0.65856,-1.77806 -0.98783,-3.88539 -0.98782,-6.322" />
+ <text
+ xml:space="preserve"
+ style="font-size:269.1137085px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Droid Sans;-inkscape-font-specification:Droid Sans"
+ x="64.031456"
+ y="1006.8839"
+ id="text3013"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan3015"
+ x="64.031456"
+ y="1006.8839">=</tspan></text>
+ </g>
+</svg>
--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Copyright 2014 Alexis Laferrière <alexis.laf@xymus.net>
+#
+# 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.
+
+# Android calculator application
+module calculator_android is
+ app_name "app.nit Calc."
+ app_version(0, 1, git_revision)
+ java_package "org.nitlanguage.calculator"
+
+ # Use a translucent background and lock in portrait mode
+ android_manifest_activity """
+ android:theme="@android:style/Theme.Holo.Wallpaper"
+ android:screenOrientation="portrait""""
+end
+
+import android
+import android::ui
+
+import calculator_logic
+
+redef class App
+ private var context = new CalculatorContext
+
+ # The main display, at the top of the screen
+ private var display: EditText
+
+ # Maps operators as `String` to their `Button`
+ private var op2but = new HashMap[String, Button]
+
+ # Has this window been initialized?
+ private var inited = false
+
+ redef fun init_window
+ do
+ super
+
+ if inited then return
+ inited = true
+
+ # Setup UI
+ var context = native_activity
+ var layout = new NativeLinearLayout(context)
+ layout.set_vertical
+
+ # Display screen
+ var display = new EditText
+ layout.add_view_with_weight(display.native, 1.0)
+ display.text_size = 36.0
+ self.display = display
+
+ # Buttons; numbers and operators
+ var ops = [["7", "8", "9", "+"],
+ ["4", "5", "6", "-"],
+ ["1", "2", "3", "*"],
+ ["0", ".", "C", "/"],
+ ["="]]
+
+ for line in ops do
+ var buts_layout = new NativeLinearLayout(context)
+ buts_layout.set_horizontal
+ layout.add_view_with_weight(buts_layout, 1.0)
+
+ for op in line do
+ var but = new Button
+ but.text = op
+ but.text_size = 40
+ buts_layout.add_view_with_weight(but.native, 1.0)
+ op2but[op] = but
+ end
+ end
+
+ context.content_view = layout
+ end
+
+ redef fun catch_event(event)
+ do
+ if event isa ClickEvent then
+ var sender = event.sender
+ var op = sender.text
+
+ if op == "." then
+ sender.enabled = false
+ context.switch_to_decimals
+ else if op.is_numeric then
+ var n = op.to_i
+ context.push_digit n
+ else
+ op2but["."].enabled = true
+ context.push_op op.chars.first
+ end
+
+ display.text = context.display_text
+ end
+ end
+end
# Testing the assets manager
fun test_assets
do
- assert asset_manager.bitmap("fighter.png") != null
+ assert asset_manager.bitmap("fighter.png").width == 32
end
# Testing the resources manager
fun test_resources do
assert resource_manager.string("string_test") == "string test"
assert resource_manager.boolean("test_bool") == true
- assert resource_manager.dimension("test_dimen_1") != null
- assert resource_manager.dimension("test_dimen_2") != null
+ assert resource_manager.dimension("test_dimen_1") == 25
+ assert resource_manager.dimension("test_dimen_2") == 150
end
end
--- /dev/null
+#!/usr/bin/env nit
+#
+# This file is part of NIT ( http://www.nitlanguage.org ).
+# This program is public domain
+
+# Task: Empty program
+# SEE: <http://rosettacode.org/wiki/Empty_program>
--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.org ).
+# This program is public domain
+# Copyright 2014 amineorion <amineorion@gmail.com>
+#
+# 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.
+#
+# Task: Hailstone sequence
+# SEE: <http://rosettacode.org/wiki/Hailstone_sequence>
+#
+# Not optimize version.
+
+module hailstone
+
+fun hailstone (n: Int): Array[Int]
+do
+ var sequence = [n]
+ while n != 1 do
+ if n.bin_and(0x01) == 0 then
+ n = n / 2
+ else
+ n = 3 * n + 1
+ end
+ sequence.add(n)
+ end
+ return sequence
+end
+var sequence27 = hailstone(27)
+var size27 = sequence27.length
+print "Sequence for 27 has {size27} begin with: {sequence27[0]}, " +
+ "{sequence27[1]}, {sequence27[2]}, {sequence27[3]} " +
+ "and end with: {sequence27[size27 - 4]}, {sequence27[size27 - 3]}, " +
+ "{sequence27[size27 - 2]}, {sequence27[size27 - 1]}"
+
+var max: Int = hailstone(1).length
+var max_sequence = hailstone(1)
+var max_element = 1
+
+for i in [2..100000] do
+ var sequence = hailstone(i)
+ if max < sequence.length then
+ max = sequence.length
+ max_element = i
+ max_sequence = sequence
+ end
+end
+print "The number with longest sequence is {max_element} " +
+ "with length of {max_sequence.length}"
--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.org ).
+# This program is public domain
+# Copyright 2014 amineorion <amineorion@gmail.com>
+#
+# 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.
+#
+# Task: Hamming numbers
+# SEE: <http://rosettacode.org/wiki/Hamming_numbers>
+#
+# Version that don't support 1,000,000th position of Hamming number yet.
+
+module hamming_number
+
+class HammingTriple
+ super Comparable
+
+ var a: Int
+ var b: Int
+ var c: Int
+
+ redef type OTHER: HammingTriple
+
+ init(a: Int, b: Int, c: Int)
+ do
+ self.a = a
+ self.b = b
+ self.c = c
+ end
+
+ redef fun >(other: OTHER): Bool
+ do
+ if a > other.a and b > other.b and c > other.c then
+ return true
+ end
+
+ if a < other.a and b < other.b and c < other.c then
+ return false
+ end
+
+ if self == other then
+ return false
+ end
+
+ var log1 = log
+ var log2 = other.log
+
+ if not log1.is_approx(log2, 0.000001) then
+ return log1 > log2
+ end
+ return false
+ end
+
+ fun log: Float
+ do
+ return a.to_f * 2.0.log + b.to_f * 3.0.log + c.to_f * 5.0.log
+ end
+
+ redef fun ==(o)
+ do
+ return o isa HammingTriple and a == o.a and b == o.b and c == o.c
+ end
+
+ fun calcul: Int
+ do
+ return (2 ** a) * (3 ** b) * (5 ** c)
+ end
+
+ redef fun to_s: String
+ do
+ return "a: {a}, b: {b}, c: {c}"
+ end
+end
+
+class HammingArray
+ super Array[HammingTriple]
+
+ fun get_min: HammingTriple
+ do
+ var min = self[0]
+ var min_index = 0
+ for i in [1..length[ do
+ if min > self[i] then
+ min = self[i]
+ min_index = i
+ end
+ end
+ remove_at(min_index)
+ return min
+ end
+end
+
+fun hamming(limit_position: Int): Int
+do
+ var hamming_triple = new HammingArray
+ hamming_triple.add(new HammingTriple(0, 0, 0))
+ loop
+ var current = hamming_triple.get_min
+ limit_position -= 1
+ if limit_position == 0 then
+ return current.calcul
+ end
+
+ if current.a == 0 and current.b == 0 then
+ hamming_triple.add(new HammingTriple(current.a, current.b, current.c + 1))
+ end
+
+ if current.a == 0 then
+ hamming_triple.add(new HammingTriple(current.a, current.b + 1, current.c))
+ end
+
+ hamming_triple.add(new HammingTriple(current.a + 1, current.b, current.c))
+ end
+end
+
+for i in [1..20] do
+ print "{i}: {hamming(i)}"
+end
+
+print "1691: {hamming(1691)}"
--- /dev/null
+#!/usr/bin/env nit
+#
+# This file is part of NIT ( http://www.nitlanguage.org ).
+# This program is public domain
+
+# Task: Hello World/Text
+# SEE: <http://rosettacode.org/wiki/Hello_world/Text>
+print "Goodbye, World!"
# General graph node
class Node
+ # Type of the others nodes in the `graph`
type N: Node
# parent graph
var graph: Graph[N, Link]
- init(graph: Graph[N, Link])
+ init
do
- self.graph = graph
graph.add_node(self)
end
loop
var frontier_node: nullable N = null
- var bucket_searched: Int = 0
+ var bucket_searched = 0
# find next valid node in frontier/buckets
loop
# Link between two nodes and associated to a graph
class Link
+ # Type of the nodes in `graph`
type N: Node
+
+ # Type of the other links in `graph`
type L: Link
+ # The graph to which belongs `self`
var graph: Graph[N, L]
+ # Origin of this link
var from: N
+
+ # Endpoint of this link
var to: N
- init(graph: Graph[N, L], from, to: N)
+ init
do
- self.graph = graph
- self.from = from
- self.to = to
-
graph.add_link(self)
end
end
# General graph
class Graph[N: Node, L: Link]
+ # Nodes in this graph
var nodes: Set[N] = new HashSet[N]
+
+ # Links in this graph
var links: Set[L] = new HashSet[L]
+ # Add a `node` to this graph
fun add_node(node: N): N
do
nodes.add(node)
return node
end
+ # Add a `link` to this graph
fun add_link(link: L): L
do
links.add(link)
return link
end
- # used to check if nodes have been searched in one pathfinding
- var pathfinding_current_evocation: Int = 0
+ # Used to check if nodes have been searched in one pathfinding
+ private var pathfinding_current_evocation: Int = 0
end
-# Result from pathfinding, a walkable path
+# Result from path finding and a walkable path
class Path[N]
+ # The total cost of this path
var total_cost: Int
+ # The list of nodes composing this path
var nodes = new List[N]
- init (cost: Int) do total_cost = cost
+ private var at: Int = 0
- var at: Int = 0
+ # Step on the path and get the next node to travel
fun step: N
do
assert nodes.length >= at else print "a_star::Path::step failed, is at_end_of_path"
return s
end
+ # Peek at the next step of the path
fun peek_step: N do return nodes[at]
+ # Are we at the end of this path?
fun at_end_of_path: Bool do return at >= nodes.length
end
# Context related to an evocation of pathfinding
class PathContext
+ # Type of the nodes in `graph`
type N: Node
+
+ # Type of the links in `graph`
type L: Link
+ # Graph to which is associated `self`
var graph: Graph[N, L]
# Worst cost of all the link's costs
# Heuristic
fun heuristic_cost(a, b: N): Int is abstract
+ # The worst cost suggested by the heuristic
fun worst_heuristic_cost: Int is abstract
end
redef fun worst_heuristic_cost do return 0
end
+# A `PathContext` for graphs with `WeightedLink`
class WeightedPathContext
super PathContext
redef type L: WeightedLink
- init(graph: Graph[N, L])
+ init
do
super
self.worst_cost = worst_cost
end
- redef var worst_cost: Int
+ redef var worst_cost: Int is noinit
redef fun cost(l) do
return l.weight
redef fun worst_heuristic_cost do return 0
end
+# A `Link` with a `weight`
class WeightedLink
super Link
+ # The `weight`, or cost, of this link
var weight: Int
-
- init(graph: Graph[N, L], from, to: N, weight: Int)
- do
- super
-
- self.weight = weight
- end
end
# Advanced path conditions with customizable accept states
# 2. Apply the method `run`, that will search and return a solution.
# 3. Retrieve information from the solution.
#
-# ~~~~
+# ~~~~nitish
# var p: BacktrackProblem = new MyProblem
# var solver = p.solve
# var res = solver.run
# The constraint is that two queens cannot be on the same row, column or diagonal.
#
# Eg. a solution to the 8-queens problem is
-# ~~~
+# ~~~raw
# +--------+
# |Q.......|
# |....Q...|
# 2. Apply the method `run`, that will search and return a solution.
# 3. Retrieve information from the solution.
#
-# ~~~~
+# ~~~~nitish
# var p: SearchProblem = new MyProblem
# var res = p.astar.run
# if res != null then print "Found plan with {res.depth} actions, that cost {res.cost}: {res.plan.join(", ")}"
# This is a low-level class, use `AssetManager` instead
extern class NativeAssetManager in "Java" `{ android.content.res.AssetManager `}
super JavaObject
- redef type SELF: NativeAssetManager
fun close in "Java" `{ recv.close(); `}
# This is a low-level class, use `ResourcesManager` instead
extern class NativeResources in "Java" `{ android.content.res.Resources `}
super JavaObject
- redef type SELF: NativeResources
fun get_assets:NativeAssetManager in "Java" `{ return recv.getAssets(); `}
fun get_color(id: Int): Int in "Java" `{ return recv.getColor((int)id); `}
# An android Bitmap, get an instance using the AssetManager or the ResourceManager
extern class NativeBitmap in "Java" `{ android.graphics.Bitmap `}
super JavaObject
- redef type SELF: NativeBitmap
# Create a NativeBitmap from a NativeInputStream retrieved with `open` function of the AssetManager
# Called by the AssetManager
# Android AssetFileDescriptor, can be retrieve by AssetManager and used to load a sound in a SoundPool
extern class NativeAssetFileDescriptor in "Java" `{ android.content.res.AssetFileDescriptor `}
super JavaObject
- redef type SELF: NativeAssetFileDescriptor
fun close in "Java" `{
try {
# AudioManager of the application, used to manage the audio mode
extern class NativeAudioManager in "Java" `{ android.media.AudioManager `}
super JavaObject
- redef type SELF: NativeAudioManager
fun mode: Int in "Java" `{ return recv.getMode(); `}
fun mode=(i: Int) in "Java" `{ recv.setMode((int)i); `}
# This is a low-level class, use `MediaPlater` instead
extern class NativeMediaPlayer in "Java" `{ android.media.MediaPlayer `}
super JavaObject
- redef type SELF: NativeMediaPlayer
new in "Java" `{ return new MediaPlayer(); `}
fun start in "Java" `{ recv.start(); `}
# This is a low-level class, use `SoundPool`instead
extern class NativeSoundPool in "Java" `{ android.media.SoundPool `}
super JavaObject
- redef type SELF: NativeSoundPool
new(max_streams, stream_type, src_quality: Int) in "Java" `{
return new SoundPool((int)max_streams, (int)stream_type, (int)src_quality);
extern class NativeBundle in "Java" `{ android.os.Bundle `}
super JavaObject
- redef type SELF: NativeBundle
fun clone: JavaObject in "Java" `{ return recv.clone(); `}
fun size: Int in "Java" `{ return recv.size(); `}
--- /dev/null
+android:
+ mkdir -p bin/ res/
+ ../../../contrib/inkscape_tools/bin/svg_to_icons art/icon.svg --android --out res/
+ ../../../bin/nitg --dir bin/ src/ui_test.nit
+ adb install -r bin/ui_test.apk
+
+install: android
+ adb install -r bin/ui.apk
+
+clean:
+ rm -rf bin
--- /dev/null
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="512"
+ height="512"
+ id="svg2"
+ version="1.1"
+ inkscape:version="0.48.5 r10040"
+ sodipodi:docname="icon.svg">
+ <defs
+ id="defs4" />
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#000000"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="0.98994949"
+ inkscape:cx="309.32788"
+ inkscape:cy="302.66563"
+ inkscape:document-units="px"
+ inkscape:current-layer="layer1"
+ showgrid="false"
+ inkscape:window-width="1311"
+ inkscape:window-height="960"
+ inkscape:window-x="3037"
+ inkscape:window-y="440"
+ inkscape:window-maximized="0" />
+ <metadata
+ id="metadata7">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title />
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:label="Layer 1"
+ inkscape:groupmode="layer"
+ id="layer1"
+ transform="translate(0,-540.36218)">
+ <path
+ style="font-size:320.10992432px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:-55.78796005px;word-spacing:0px;fill:#ffffff;fill-opacity:1;stroke:none;font-family:Droid Sans;-inkscape-font-specification:Droid Sans"
+ d="M 116.09375,542.95593 C 95.970238,546.76157 75.866352,550.69664 55.75,554.54968 37.271066,654.48453 18.600595,754.38392 0.1875,854.33093 c 4.5670667,-0.0224 11.88925,-3.92217 14.989244,-1.88564 2.348097,12.30965 6.527711,24.13426 7.951802,36.55472 4.55774,23.64215 8.603147,47.44405 14.058954,70.86217 20.446729,-3.97475 40.892439,-7.95532 61.34375,-11.90625 0.806348,-6.01877 0.340643,-13.9623 0.6875,-18.84375 5.52874,12.6291 21.06261,15.98721 33.375,12.9375 18.4814,-4.95238 37.89007,-7.63966 56.75,-11.59375 -0.61826,-2.8783 4.8827,-0.79167 7.02749,-1.68038 14.16686,-1.03878 27.37606,-6.02271 41.41001,-7.38212 46.67851,-52.63829 -1.21449,-16.83212 30.65625,78.40625 17.19389,35.71392 58.70592,54.88142 97.40613,52.07812 21.55059,0.3486 43.28622,-5.5501 61.25012,-17.3281 0,7.9479 0,15.8958 0,23.8437 12.8637,-12.8518 32.06959,-10.4444 48.6875,-10.5625 12.08275,-0.4504 26.74579,-3.3417 33.09375,-14.75 2.84788,-8.0897 -0.35571,-16.9124 0.875,-25.25 0,-68.40622 0,-136.81247 0,-205.21872 -12.80081,2.58433 -25.80422,3.15955 -39,2.65625 -4.49542,-0.0745 -2.70343,-6.71819 -9.375,-2.8125 -14.41967,4.34039 -29.68137,2.22535 -44.53125,3.3125 -1.97068,-10.5394 -3.89878,-21.08667 -5.875,-31.625 43.54527,5.39974 90.52353,-22.98463 100.5,-66.625 11.74182,-45.53602 0.57063,-96.29858 -28.34375,-133 -18.76502,-21.52312 -47.96855,-34.21533 -76.77629,-30.338 -17.82405,1.69881 -35.28672,8.34732 -49.69246,18.74425 -12.97547,-7.86574 -27.99494,0.14323 -41.46466,1.78058 -8.5847,1.6356 -17.16935,3.2715 -25.75409,4.90692 2.25786,4.53438 -2.9589,1.63366 -5.28125,1.90625 -24.37251,-2.08163 -49.75835,4.12727 -69.28125,18.9375 -12.98942,-8.01584 -28.14096,-0.0134 -41.65179,1.65749 -7.26996,1.39739 -14.54254,2.78105 -21.81696,4.15501 C 140.087,578.41196 128.739,560.57354 117.4375,542.70593 l -0.98313,0.18291 z"
+ id="path3034"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="ccccccccccccccccccccccccccccccccccccc" />
+ <text
+ transform="matrix(1.0172511,-0.19643198,0.1830023,0.94770357,0,0)"
+ sodipodi:linespacing="125%"
+ id="text2999"
+ y="843.55823"
+ x="-121.33073"
+ style="font-size:338.93121338px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:-0.06177186px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+ xml:space="preserve"><tspan
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;letter-spacing:-59.06808853px;font-family:Droid Sans;-inkscape-font-specification:Droid Sans"
+ y="843.55823"
+ x="-121.33073"
+ id="tspan3001"
+ sodipodi:role="line">App</tspan></text>
+ <text
+ transform="matrix(1.0172511,-0.19643198,0.1830023,0.94770357,0,0)"
+ xml:space="preserve"
+ style="font-size:171.81326294px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+ x="-132.6741"
+ y="958.20111"
+ id="text3003"
+ sodipodi:linespacing="125%"><tspan
+ style="letter-spacing:-22.57948303px"
+ sodipodi:role="line"
+ id="tspan3005"
+ x="-132.6741"
+ y="958.20111">nit</tspan></text>
+ <text
+ transform="scale(1.0360431,0.96521081)"
+ sodipodi:linespacing="125%"
+ id="text3007"
+ y="1056.8173"
+ x="253.55678"
+ style="font-size:265.30044556px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
+ xml:space="preserve"><tspan
+ y="1056.8173"
+ x="253.55678"
+ id="tspan3009"
+ sodipodi:role="line"
+ style="letter-spacing:-34.865448px">UI</tspan></text>
+ </g>
+</svg>
--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Copyright 2014 Alexis Laferrière <alexis.laf@xymus.net>
+#
+# 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.
+
+# Test for app.nit's UI services
+module ui_test is
+ app_name("app.nit UI test")
+ app_version(0, 1, git_revision)
+ java_package("org.nitlanguage.ui_test")
+ android_manifest_activity """android:theme="@android:style/Theme.Light""""
+end
+
+import android
+import android::ui
+import android::toast
+import android::notification
+
+redef class App
+
+ var but_notif: Button
+ var but_toast: Button
+
+ var notif: nullable Notification = null
+
+ var inited = false
+ redef fun init_window
+ do
+ super
+
+ if inited then return
+ inited = true
+
+ # Setup UI
+ var context = native_activity
+ var layout = new NativeLinearLayout(context)
+ layout.set_vertical
+
+ but_notif = new Button
+ but_notif.text = "Show Notification"
+ layout.add_view but_notif.native
+
+ but_toast = new Button
+ but_toast.text = "Show Toast"
+ layout.add_view but_toast.native
+
+ context.content_view = layout
+ end
+
+ fun act_notif
+ do
+ var notif = self.notif
+ if notif == null then
+ notif = new Notification("From app.nit", "Some content...")
+ notif.ticker = "Ticker text..."
+ notif.show
+ self.notif = notif
+ else
+ notif.cancel
+ self.notif = null
+ end
+ end
+
+ fun act_toast
+ do
+ toast("Sample toast from app.nit at {get_time}", false)
+ end
+
+ redef fun catch_event(event)
+ do
+ if event isa ClickEvent then
+ var sender = event.sender
+ if sender == but_notif then
+ act_notif
+ else if sender == but_toast then
+ act_toast
+ end
+ end
+ end
+end
extern class NativeIntent in "Java" `{ android.content.Intent `}
super JavaObject
- redef type SELF: NativeIntent
fun add_category(category: JavaString) in "Java" `{ recv.addCategory(category); `}
fun add_flags(flags: Int) in "Java" `{ recv.addFlags((int)flags); `}
# The general action to be performed
#
- # Example :
- # ~~~
+ # ~~~nitish
+ # # TODO better example
# intent.action = intent_action.view.to_s
# ~~~
fun action=(action: String)
# Add category to the intent
# Only activities providing all of the requested categories will be used
#
- # Example :
- # ~~~
+ # ~~~nitish
+ # # TODO better example
# intent.add_category(intent_category.home.to_s)
# ~~~
# Returns `self` allowing fluent programming
# Add a flag to be used by the intent
#
- # Example :
- # ~~~
+ # ~~~nitish
+ # # TODO better example
# intent.add_flags(intent_flag.activity_new_task)
# ~~~
# Returns `self` allowing fluent programming
}
`}
+# An Android activity context
+extern class NativeContext in "Java" `{ android.content.Context `}
+ super JavaObject
+end
+
+# A wrapper of context
+extern class NativeContextWrapper in "Java" `{ android.content.ContextWrapper `}
+ super NativeContext
+end
+
# Android SDK's `android.app.NativeActivity`.
#
# Can be used to get anything related to the `Context` of the activity in Java
# and as anchor to execute Java UI code.
extern class NativeActivity in "Java" `{ android.app.NativeActivity `}
- super JavaObject
+ super NativeContextWrapper
end
redef class App
# The `NativeActivity`, as in the Java object, associated to `self`
fun java_native_activity: NativeActivity `{ return recv->clazz; `}
- # Path to this application's internal data directory.
+ # Path to this application's internal data directory.
fun internal_data_path: NativeString `{ return (char*)recv->internalDataPath; `}
# Path to this application's external (removable/mountable) data directory.
- fun external_data_path: NativeString `{ return (char*)recv->externalDataPath; `}
+ fun external_data_path: NativeString `{ return (char*)recv->externalDataPath; `}
# The platform's SDK version code.
fun sdk_version: Int `{ return recv->sdkVersion; `}
--- /dev/null
+# This file is part of NIT (http://www.nitlanguage.org).
+#
+# Copyright 2014 Alexis Laferrière <alexis.laf@xymus.net>
+#
+# 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.
+
+# Native Java classes for notifications
+module native_notification is min_api_version 11
+
+import android::assets_and_resources
+
+in "Java" `{
+ import android.content.Context;
+ import android.app.NotificationManager;
+ import android.app.Notification;
+`}
+
+redef class NativeActivity
+ fun notification_manager: NativeNotificationManager in "Java" `{
+ return (NotificationManager)recv.getSystemService(Context.NOTIFICATION_SERVICE);
+ `}
+end
+
+extern class NativeNotificationManager in "Java" `{ android.app.NotificationManager `}
+
+ fun notify(tag: JavaString, id: Int, notif: NativeNotification) in "Java" `{
+ recv.notify(tag, (int)id, notif);
+ `}
+
+ fun cancel(tag: JavaString, id: Int) in "Java" `{ recv.cancel(tag, (int)id); `}
+
+ fun cancel_all in "Java" `{ recv.cancelAll(); `}
+end
+
+extern class NativeNotification in "Java" `{ android.app.Notification `}
+end
+
+extern class NativeNotificationBuilder in "Java" `{ android.app.Notification$Builder `}
+
+ new (context: NativeActivity) in "Java" `{ return new Notification.Builder(context); `}
+
+ fun create: NativeNotification in "Java" `{
+ // Deprecated since API 16, which introduces `build`,
+ // refinement and global compilation should prevent warnings.
+ return recv.getNotification();
+ `}
+
+ fun title=(value: JavaString) in "Java" `{ recv.setContentTitle(value); `}
+
+ fun text=(value: JavaString) in "Java" `{ recv.setContentText(value); `}
+
+ fun ticker=(value: JavaString) in "Java" `{ recv.setTicker(value); `}
+
+ fun small_icon=(value: Int) in "Java" `{ recv.setSmallIcon((int)value); `}
+
+ fun auto_cancel=(value: Bool) in "Java" `{ recv.setAutoCancel(value); `}
+
+ fun number=(value: Int) in "Java" `{ recv.setNumber((int)value); `}
+
+ fun ongoing=(value: Bool) in "Java" `{ recv.setOngoing(value); `}
+end
--- /dev/null
+# This file is part of NIT (http://www.nitlanguage.org).
+#
+# Copyright 2014 Alexis Laferrière <alexis.laf@xymus.net>
+#
+# 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.
+
+# Services to show notification in the Android status bar
+#
+# ~~~~nitish
+# # Create and show a notification
+# var notif = new Notification("My Title", "Some content")
+# notif.ticker = "Ticker text"
+# notif.show
+#
+# # Update the notification
+# notif.text = "New content!"
+# notif.ongoing = true # Make it un-dismissable
+# notif.show
+#
+# # Hide the notification
+# notif.cancel
+# ~~~~
+#
+# For more information, see:
+# http://developer.android.com/guide/topics/ui/notifiers/notifications.html
+module notification
+
+import standard
+private import native_notification
+
+# An Android notification, shown at the top of the screen
+class Notification
+ # Title of this notification
+ var title: nullable Text is writable
+
+ # Text content of this notification
+ var text: nullable Text is writable
+
+ # Text to show in the bar as the notification appears
+ var ticker: nullable Text = null is writable
+
+ # Name of a resource found in the `res/drawable-*` folders to use for the small icon
+ #
+ # By default, we use the app's icon, named "icon". A valid icon must be used
+ # to display notifications.
+ var small_icon: nullable Text = null is writable
+
+ # Number to display on the bottom right part of the notification
+ var number: nullable Int = null is writable
+
+ # Is this notification ongoing? Not user dismissable.
+ var ongoing: Bool = false is writable
+
+ private var id: nullable Int = null
+ private var tag = "app.nit notification"
+
+ # Show the notification
+ fun show
+ do
+ sys.jni_env.push_local_frame(8)
+
+ var context = app.native_activity
+ var builder = new NativeNotificationBuilder(context)
+
+ # If no custom icon is specified, use app's
+ var small_icon = self.small_icon
+ if small_icon == null then small_icon = "icon"
+ var small_icon_id = app.resource_manager.other_id(small_icon.to_s, "drawable")
+ builder.small_icon = small_icon_id
+
+ # Other options
+ if title != null then builder.title = title.to_java_string
+ if text != null then builder.text = text.to_java_string
+ if ticker != null then builder.ticker = ticker.to_java_string
+ builder.ongoing = ongoing
+
+ var notif = builder.create
+ var manager = context.notification_manager
+
+ var id = self.id
+ if id == null then id = sys.next_notification_id
+ manager.notify(tag.to_java_string, id, notif)
+
+ self.id = id
+
+ sys.jni_env.pop_local_frame
+ end
+
+ # Was this notification shown with `show`?
+ #
+ # This does not indicates whether is has been dismissed or not. Only that
+ # it was shown at least once.
+ private fun was_shown: Bool do return id != null
+
+ # Cancel this notification and hide it if it is currently displayed
+ fun cancel
+ do
+ var id = self.id
+ if id != null then
+ sys.jni_env.push_local_frame(8)
+
+ var manager = app.native_activity.notification_manager
+ manager.cancel(tag.to_java_string, id)
+
+ self.id = null
+
+ sys.jni_env.pop_local_frame
+ end
+ end
+end
+
+redef class Sys
+ private var next_notification_id_cache = 0
+
+ # Returns a unique ID for new notifications
+ private fun next_notification_id: Int
+ do
+ var id = next_notification_id_cache
+ next_notification_id_cache = id + 1
+ return id
+ end
+end
new_annotation max_api_version
new_annotation target_api_version
new_annotation android_manifest
+ new_annotation android_manifest_application
+ new_annotation android_manifest_activity
end
import java
# The sensor support is implemented in android_app module, so the user can enable the type of sensor he wants to use.
# There is an example of how you can use the android sensors in nit/examples/mnit_ballz :
#
-# ~~~~
+# ~~~~nitish
+# #FIXME rewrite the example
# var app = new MyApp
# app.sensors_support_enabled = true
# app.accelerometer.enabled = true
extern class NativeSharedPreferences in "Java" `{ android.content.SharedPreferences `}
super JavaObject
- redef type SELF: NativeSharedPreferences
fun contains(key: JavaString): Bool in "Java" `{ return recv.contains(key); `}
fun get_all: HashMap[JavaString, JavaObject] import HashMap[JavaString, JavaObject],
extern class NativeSharedPreferencesEditor in "Java" `{ android.content.SharedPreferences$Editor `}
super JavaObject
- redef type SELF: NativeSharedPreferencesEditor
fun clear: NativeSharedPreferencesEditor in "Java" `{ return recv.clear(); `}
fun commit: Bool in "Java" `{ return recv.commit(); `}
#
# User has to manage local stack deallocation himself
#
- # Example :
- # ~~~
+ # ~~~nitish
# var foo = new HashMap[JavaString, JavaObject]
# # ...
# for key, value in foo do
# key.delete_local_ref
# value.delete_local_ref
# end
- # ~~~
+ # ~~~
# *You should use Nit getters instead and get each value one by one*
fun all: nullable HashMap[JavaString, JavaObject]
do
#
# User has to manage local stack deallocation himself
#
- # Example :
- # ~~~
- # var a_hash_set = shared_preferences.string_set("A key")
- # ...
+ # ~~~nitish
+ # var a_hash_set = app.shared_preferences.string_set("A key")
+ # # ...
# for element in a_hash_set do element.delete_local_ref
# ~~~
fun string_set(key: String): HashSet[JavaString]
#
# User has to manage local stack deallocation himself
#
- # Example :
- # ~~~
+ # ~~~nitish
# var foo = new HashSet[JavaString]
- # shared_preferences.add_string_set("A key", foo)
+ # app.shared_preferences.add_string_set("A key", foo)
# for element in foo do element.delete_local_ref
# ~~~
fun add_string_set(key: String, value: HashSet[JavaString]): SharedPreferences
--- /dev/null
+# This file is part of NIT (http://www.nitlanguage.org).
+#
+# Copyright 2014 Alexis Laferrière <alexis.laf@xymus.net>
+#
+# 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.
+
+# Services to display a _toast_, a small popup on Android
+module toast
+
+import native_app_glue
+
+in "Java" `{
+ import android.widget.Toast;
+`}
+
+redef class App
+ # Display a _toast_ with `message`, for longer if `is_long`
+ fun toast(message: String, is_long: Bool)
+ do
+ var jstr = message.to_java_string
+ native_toast(jstr, is_long)
+ jstr.delete_local_ref
+ end
+
+ private fun native_toast(message: JavaString, is_long: Bool)
+ import native_activity in "Java" `{
+ final android.app.NativeActivity context = App_native_activity(recv);
+ final CharSequence final_message = message;
+ final int duration = is_long? Toast.LENGTH_LONG: Toast.LENGTH_SHORT;
+
+ context.runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ Toast toast = Toast.makeText(context, final_message, duration);
+ toast.show();
+ }
+ });
+ `}
+end
--- /dev/null
+# This file is part of NIT (http://www.nitlanguage.org).
+#
+# Copyright 2014 Alexis Laferrière <alexis.laf@xymus.net>
+#
+# 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.
+
+# Views and services to use the Android native user interface
+#
+# Events, such as a button click, come from the UI thread and are then
+# passed to the main thread. It is recommended to specialize one of the
+# methods of the main thread to customize the response to a given event.
+#
+# This graph shows the path of a button click:
+# ~~~raw
+# UI Thread # Main thread
+#
+# User
+# |
+# V
+# Button::click_ui --> Button::click
+# |
+# V
+# App::catch_event
+# ~~~
+module ui is min_api_version 14
+
+import native_app_glue
+import pthreads::concurrent_collections
+
+in "Java" `{
+ import android.app.NativeActivity;
+
+ import android.view.Gravity;
+ import android.view.MotionEvent;
+ import android.view.ViewGroup;
+ import android.view.ViewGroup.MarginLayoutParams;
+
+ import android.widget.Button;
+ import android.widget.LinearLayout;
+ import android.widget.GridLayout;
+ import android.widget.PopupWindow;
+ import android.widget.TextView;
+
+ import java.lang.*;
+ import java.util.*;
+`}
+
+# An event from the `app.nit` framework
+interface AppEvent
+ # Reaction to this event
+ fun react do end
+end
+
+# A control click event
+class ClickEvent
+ super AppEvent
+
+ # Sender of this event
+ var sender: Button
+
+ redef fun react do sender.click self
+end
+
+# Receiver of events not handled directly by the sender
+interface EventCatcher
+ fun catch_event(event: AppEvent) do end
+end
+
+redef class App
+ super EventCatcher
+
+ # Queue of events to be received by the main thread
+ var event_queue = new ConcurrentList[AppEvent]
+
+ # Call `react` on all `AppEvent` available in `event_queue`
+ protected fun loop_on_ui_callbacks
+ do
+ var queue = event_queue
+ while not queue.is_empty do
+ var event = queue.pop
+ event.react
+ end
+ end
+
+ redef fun run
+ do
+ loop
+ # Process Android events
+ poll_looper 100
+
+ # Process app.nit events
+ loop_on_ui_callbacks
+ end
+ end
+end
+
+redef extern class NativeActivity
+
+ # Fill this entire `NativeActivity` with `popup`
+ #
+ # This is a workaround for the use on `takeSurface` in `NativeActivity.java`
+ #
+ # TODO replace NativeActivity by our own NitActivity
+ private fun dedicate_to_popup(popup: NativePopupWindow, popup_layout: NativeViewGroup) in "Java" `{
+ final LinearLayout final_main_layout = new LinearLayout(recv);
+ final ViewGroup final_popup_layout = popup_layout;
+ final PopupWindow final_popup = popup;
+ final NativeActivity final_recv = recv;
+
+ recv.runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ MarginLayoutParams params = new MarginLayoutParams(
+ LinearLayout.LayoutParams.MATCH_PARENT,
+ LinearLayout.LayoutParams.MATCH_PARENT);
+
+ final_recv.setContentView(final_main_layout, params);
+
+ final_popup.showAtLocation(final_popup_layout, Gravity.TOP, 0, 40);
+ }
+ });
+ `}
+
+ # Set the main layout of this activity
+ fun content_view=(layout: NativeViewGroup)
+ do
+ var popup = new NativePopupWindow(self)
+ popup.content_view = layout
+ dedicate_to_popup(popup, layout)
+ end
+
+ # Set the real content view of this activity, without hack
+ #
+ # TODO bring use this instead of the hack with `dedicate_to_pupup`
+ private fun real_content_view=(layout: NativeViewGroup) in "Java" `{
+ final ViewGroup final_layout = layout;
+ final NativeActivity final_recv = recv;
+
+ recv.runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ final_recv.setContentView(final_layout);
+
+ final_layout.requestFocus();
+ }
+ });
+ `}
+end
+
+# An `Object` that raises events
+abstract class Eventful
+ var event_catcher: EventCatcher = app is lazy, writable
+end
+
+#
+## Nity classes and services
+#
+
+# An Android control with text
+abstract class TextView
+ super Finalizable
+ super Eventful
+
+ # Native Java variant to this Nity class
+ type NATIVE: NativeTextView
+
+ # The native Java object encapsulated by `self`
+ var native: NATIVE is noinit
+
+ # Get the text of this view
+ fun text: String
+ do
+ var jstr = native.text
+ var str = jstr.to_s
+ jstr.delete_local_ref
+ return str
+ end
+
+ # Set the text of this view
+ fun text=(value: Text)
+ do
+ var jstr = value.to_s.to_java_string
+ native.text = jstr
+ jstr.delete_local_ref
+ end
+
+ # Get whether this view is enabled or not
+ fun enabled: Bool do return native.enabled
+
+ # Set if this view is enabled
+ fun enabled=(val: Bool) do native.enabled = val
+
+ # Set the size of the text in this view at `dpi`
+ fun text_size=(dpi: Numeric) do native.text_size = dpi.to_f
+
+ private var finalized = false
+ redef fun finalize
+ do
+ if not finalized then
+ native.delete_global_ref
+ finalized = true
+ end
+ end
+end
+
+# An Android button
+class Button
+ super TextView
+
+ redef type NATIVE: NativeButton
+
+ init
+ do
+ var native = new NativeButton(app.native_activity, app.event_queue, self)
+ self.native = native.new_global_ref
+ end
+
+ # Click event on the Main thread
+ #
+ # By default, this method calls `app.catch_event`. It can be specialized
+ # with custom behavior or the receiver of `catch_event` can be changed
+ # with `event_catcher=`.
+ fun click(event: AppEvent) do event_catcher.catch_event(event)
+
+ # Click event on the UI thread
+ #
+ # This method is called on the UI thread and redirects the event to `click`
+ # throught `App::event_queue`. In most cases, you should implement `click`
+ # and leave `click_ui` as is.
+ fun click_ui do app.event_queue.add(new ClickEvent(self))
+end
+
+# An Android editable text field
+class EditText
+ super TextView
+
+ redef type NATIVE: NativeEditText
+
+ init
+ do
+ var native = new NativeEditText(app.native_activity)
+ self.native = native.new_global_ref
+ end
+end
+
+#
+## Native classes
+#
+
+# A `View` for Android
+extern class NativeView in "Java" `{ android.view.View `}
+ super JavaObject
+
+ fun minimum_width=(val: Int) in "Java" `{ recv.setMinimumWidth((int)val); `}
+ fun minimum_height=(val: Int) in "Java" `{ recv.setMinimumHeight((int)val); `}
+end
+
+# A collection of `NativeView`
+extern class NativeViewGroup in "Java" `{ android.view.ViewGroup `}
+ super NativeView
+
+ fun add_view(view: NativeView) in "Java" `{ recv.addView(view); `}
+end
+
+# A `NativeViewGroup` organized in a line
+extern class NativeLinearLayout in "Java" `{ android.widget.LinearLayout `}
+ super NativeViewGroup
+
+ new(context: NativeActivity) in "Java" `{ return new LinearLayout(context); `}
+
+ fun set_vertical in "Java" `{ recv.setOrientation(LinearLayout.VERTICAL); `}
+ fun set_horizontal in "Java" `{ recv.setOrientation(LinearLayout.HORIZONTAL); `}
+
+ redef fun add_view(view) in "Java"
+ `{
+ MarginLayoutParams params = new MarginLayoutParams(
+ LinearLayout.LayoutParams.MATCH_PARENT,
+ LinearLayout.LayoutParams.WRAP_CONTENT);
+ recv.addView(view, params);
+ `}
+
+ fun add_view_with_weight(view: NativeView, weight: Float)
+ in "Java" `{
+ recv.addView(view, new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.MATCH_PARENT, (float)weight));
+ `}
+end
+
+# A `NativeViewGroup` organized as a grid
+extern class NativeGridLayout in "Java" `{ android.widget.GridLayout `}
+ super NativeViewGroup
+
+ new(context: NativeActivity) in "Java" `{ return new android.widget.GridLayout(context); `}
+
+ fun row_count=(val: Int) in "Java" `{ recv.setRowCount((int)val); `}
+
+ fun column_count=(val: Int) in "Java" `{ recv.setColumnCount((int)val); `}
+
+ redef fun add_view(view) in "Java" `{ recv.addView(view); `}
+end
+
+extern class NativePopupWindow in "Java" `{ android.widget.PopupWindow `}
+ super NativeView
+
+ new (context: NativeActivity) in "Java" `{
+ PopupWindow recv = new PopupWindow(context);
+ recv.setWindowLayoutMode(LinearLayout.LayoutParams.MATCH_PARENT,
+ LinearLayout.LayoutParams.MATCH_PARENT);
+ recv.setClippingEnabled(false);
+ return recv;
+ `}
+
+ fun content_view=(layout: NativeViewGroup) in "Java" `{ recv.setContentView(layout); `}
+end
+
+extern class NativeTextView in "Java" `{ android.widget.TextView `}
+ super NativeView
+
+ new (context: NativeActivity) in "Java" `{ return new TextView(context); `}
+
+ fun text: JavaString in "Java" `{ return recv.getText().toString(); `}
+
+ fun text=(value: JavaString) in "Java" `{
+
+ android.util.Log.d("Nity", "1");
+ final TextView final_recv = recv;
+ final String final_value = value;
+
+ android.util.Log.d("Nity", "4");
+ ((NativeActivity)recv.getContext()).runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ android.util.Log.d("Nity", "-5");
+ android.util.Log.d("Nity", final_value);
+ android.util.Log.d("Nity", "-5.5");
+ final_recv.setText(final_value);
+ android.util.Log.d("Nity", "-6");
+ }
+ });
+ android.util.Log.d("Nity", "7");
+ `}
+
+ fun enabled: Bool in "Java" `{ return recv.isEnabled(); `}
+ fun enabled=(value: Bool) in "Java" `{
+ final TextView final_recv = recv;
+ final boolean final_value = value;
+
+ ((NativeActivity)recv.getContext()).runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ final_recv.setEnabled(final_value);
+ }
+ });
+ `}
+
+ fun gravity_center in "Java" `{
+ recv.setGravity(Gravity.CENTER);
+ `}
+
+ fun text_size=(dpi: Float) in "Java" `{
+ recv.setTextSize(android.util.TypedValue.COMPLEX_UNIT_DIP, (float)dpi);
+ `}
+end
+
+extern class NativeEditText in "Java" `{ android.widget.EditText `}
+ super NativeTextView
+
+ redef type SELF: NativeEditText
+
+ new (context: NativeActivity) in "Java" `{ return new android.widget.EditText(context); `}
+
+ fun width=(val: Int) in "Java" `{ recv.setWidth((int)val); `}
+
+ fun input_type_text in "Java" `{ recv.setInputType(android.text.InputType.TYPE_CLASS_TEXT); `}
+
+ redef fun new_global_ref: SELF import sys, Sys.jni_env `{
+ Sys sys = NativeEditText_sys(recv);
+ JNIEnv *env = Sys_jni_env(sys);
+ return (*env)->NewGlobalRef(env, recv);
+ `}
+end
+
+extern class NativeButton in "Java" `{ android.widget.Button `}
+ super NativeTextView
+
+ redef type SELF: NativeButton
+
+ new (context: NativeActivity, queue: ConcurrentList[AppEvent], sender_object: Object) import Button.click_ui in "Java" `{
+ final int final_sender_object = sender_object;
+
+ return new Button(context){
+ @Override
+ public boolean onTouchEvent(MotionEvent event) {
+ if(event.getAction() == MotionEvent.ACTION_DOWN) {
+ Button_click_ui(final_sender_object);
+ return true;
+ }
+ return false;
+ }
+ };
+ `}
+
+ redef fun new_global_ref: SELF import sys, Sys.jni_env `{
+ Sys sys = NativeButton_sys(recv);
+ JNIEnv *env = Sys_jni_env(sys);
+ return (*env)->NewGlobalRef(env, recv);
+ `}
+end
# Handle to an Android vibrator
extern class Vibrator in "Java" `{ android.os.Vibrator `}
super JavaObject
- redef type SELF: Vibrator
# Vibrate for `n` miliseconds
fun vibrate(n: Int) in "Java" `{ recv.vibrate(n); `}
fun [](key: String): nullable Object is abstract
# Store `value` at `key`
- fun []=(key: String, value: Serializable) is abstract
+ fun []=(key: String, value: nullable Serializable) is abstract
end
# Encodes the receiver string to base64.
# By default, uses "=" for padding.
fun encode_base64 : String do return encode_base64_custom_padding( '=' )
+
+ # Encodes the receiver string to base64 using a custom padding character.
+ #
+ # If using the default padding character `=`, see `encode_base64`.
fun encode_base64_custom_padding( padding : Char ) : String
do
var base64_chars = once base64_chars
# Decodes the receiver string from base64.
# By default, uses "=" for padding.
fun decode_base64 : String do return decode_base64_custom_padding( '=' )
+
+ # Decodes the receiver string to base64 using a custom padding character.
+ #
+ # If using the default padding character `=`, see `decode_base64`.
fun decode_base64_custom_padding( padding : Char ) : String
do
var inverted_base64_chars = once inverted_base64_chars
# Something acting on the game
class Turnable[G: Game]
+
+ # Execute `turn` for this instance.
fun do_turn(turn: GameTurn[G]) is abstract
end
fun cancel_act do act_at = null
end
-# Optiomized organization of `Bucketable` instances
+# Optimized organization of `Bucketable` instances
class Buckets[G: Game]
super Turnable[G]
+
+ # Bucket type used in this implementation.
type BUCKET: HashSet[Bucketable[G]]
private var buckets: Array[BUCKET] is noinit
end
end
+ # Add the Bucketable event `e` at `at_tick`.
fun add_at(e: Bucketable[G], at_tick: Int)
do
var at_key = key_for_tick(at_tick)
# Game related event
interface GameEvent
+
+ # Apply `self` to `game` logic.
fun apply( game : ThinGame ) is abstract
end
# Game logic on the client
class ThinGame
+
+ # Game tick when `self` should act.
+ #
+ # Default is 0.
var tick: Int = 0 is protected writable
end
# Game turn on the client
class ThinGameTurn[G: ThinGame]
- var tick: Int = 0 is protected writable
- var events: List[GameEvent] = new List[GameEvent] is protected writable
+ # Game tick when `self` should act.
+ var tick: Int is protected writable
- init (t: Int) do tick = t
+ # List of game events occured for `self`.
+ var events = new List[GameEvent] is protected writable
end
# Game turn on the full logic
class GameTurn[G: Game]
super ThinGameTurn[G]
+
+ # Game that `self` belongs to.
var game: G
- init (g: G)
- do
- super(g.tick)
- game = g
+ # Create a new game turn for `game`.
+ init (game: G) is old_style_init do
+ super(game.tick)
+ self.game = game
end
- fun act_next(e: Bucketable[G])
- do
- game.buckets.add_at(e, tick + 1)
- end
+ # Insert the Bucketable event `e` to be executed at next tick.
+ fun act_next(e: Bucketable[G]) do game.buckets.add_at(e, tick + 1)
- fun act_in(e: Bucketable[G], t: Int)
- do
- game.buckets.add_at(e, tick + t)
- end
+ # Insert the Bucketable event `e` to be executed at tick `t`.
+ fun act_in(e: Bucketable[G], t: Int) do game.buckets.add_at(e, tick + t)
+ # Add and `apply` a game `event`.
fun add_event( event : GameEvent )
do
event.apply( game )
# Full game logic
class Game
super ThinGame
+
+ # Game type used in this implementation.
type G: Game
+ # Bucket list in this game.
var buckets: Buckets[G] = new Buckets[G]
# Last turn executed in this game
init do end
+ # Execute and return a new GameTurn.
+ #
+ # This method calls `do_pre_turn` before executing the GameTurn
+ # and `do_post_turn` after.
fun do_turn: GameTurn[G]
do
var turn = new GameTurn[G](self)
return turn
end
+ # Execute something before executing the current GameTurn.
+ #
+ # Should be redefined by clients to add a pre-turn behavior.
+ # See `Game::do_turn`.
fun do_pre_turn(turn: GameTurn[G]) do end
+
+ # Execute something after executing the current GameTurn.
+ #
+ # Should be redefined by clients to add a post-turn behavior.
+ # See `Game::do_turn`.
fun do_post_turn(turn: GameTurn[G]) do end
end
private class LeafSubstrings
super IndexedIterator[Text]
- var str: String
+ var leaf: Leaf
+ var str: String is noinit
var avail = true
- init(l: Leaf) do str = new FlatString.with_infos(l.buf.ns, l.length, 0, l.length - 1)
+ init do
+ str = new FlatString.with_infos(leaf.buf.ns, leaf.length, 0, leaf.length - 1)
+ end
redef fun is_ok do return avail
private class Leaf
super RopeString
- private var buf: ManualBuffer
- private var bns: NativeString is noinit
+ var buf: ManualBuffer
+ var bns: NativeString is noinit
redef var length: Int is noinit
redef fun empty do return new Leaf(new ManualBuffer)
redef fun +(o) do
var s = o.to_s
- var mlen = length
var slen = s.length
if s isa FlatString then
var r = right
return new Concat(sl + self, s.right)
else if s isa Leaf then
if slen + mlen > maxlen then return new Concat(self, s)
- var mits = items
var mifrom = index_from
var sb = s.buf
var b = new ManualBuffer
abstract class CArray[E]
super AbstractArrayRead[E]
- private init(length: Int) do self._length = length
+ # The corresponding C type
+ type NATIVE: NativeCArray
+
+ # Pointer to the real C array
+ var native_array: NATIVE is noinit
+
+ private init(length: Int) is old_style_init do self._length = length
+
+ redef fun [](index)
+ do
+ assert not destroyed
+ assert index >= 0 and index < length
+ return native_array[index]
+ end
+
+ # Set `val` at `index`.
+ fun []=(index: Int, val: E)
+ do
+ assert not destroyed
+ assert index >= 0 and index < length
+ native_array[index] = val
+ end
+
+ # Was this instance destroyed?
+ #
+ # See `CArray::destroy`.
+ var destroyed = false
+
+ # Free used memory used by `native_array`.
+ #
+ # Also set `destroyed` to true.
+ fun destroy
+ do
+ if destroyed then return
+
+ native_array.free
+ destroyed = true
+ end
end
# A native C array, as in a pointer to the first element of the array
extern class NativeCArray `{ void * `}
+
+ # Type of contained elements.
type E: nullable Object
- type SELF: NativeCArray
+ # Get element at `index`.
fun [](index: E): E is abstract
+
+ # Set `val` at `index`.
fun []=(index: E, val: E) is abstract
# Return pointer to the address to the second element of this array
# Wrapper around an array of `int` in C (`int*`) with length and destroy state
class CIntArray
super CArray[Int]
+ redef type NATIVE: NativeCIntArray
- var native_array: NativeCIntArray
- init(size: Int)
- do
+ # Initialize a new CIntArray of `size` elements.
+ init(size: Int) is old_style_init do
native_array = new NativeCIntArray(size)
super size
end
- redef fun [](index)
+ # Build from an `Array[Int]`
+ new from(array: Array[Int])
do
- assert not destroyed
- assert index >= 0 and index < length
- return native_array[index]
+ var carray = new CIntArray(array.length)
+ for i in array.length.times do
+ carray[i] = array[i]
+ end
+ return carray
end
+end
- fun []=(index: Int, val: Int)
- do
- assert not destroyed
- assert index >= 0 and index < length
- native_array[index] = val
+# An array of `int` in C (`int*`)
+extern class NativeCIntArray `{ int* `}
+ super NativeCArray
+ redef type E: Int
+
+ # Initialize a new NativeCIntArray of `size` elements.
+ new(size: Int) `{ return calloc(size, sizeof(int)); `}
+
+ redef fun [](index) `{ return recv[index]; `}
+ redef fun []=(index, val) `{ recv[index] = val; `}
+
+ redef fun +(offset) `{ return recv + offset; `}
+end
+
+# Wrapper around an array of `unsigned char` in C (`unsigned char*`) with length and destroy state
+class CByteArray
+ super CArray[Int]
+ redef type NATIVE: NativeCByteArray
+
+ # Allocate a new array of `size`
+ init(size: Int) is old_style_init do
+ native_array = new NativeCByteArray(size)
+ super size
end
- var destroyed = false
- fun destroy
+ # Build from an `Array[Int]`
+ new from(array: Array[Int])
do
- if destroyed then return
-
- native_array.free
- destroyed = true
+ var carray = new CByteArray(array.length)
+ for i in array.length.times do
+ carray[i] = array[i]
+ end
+ return carray
end
end
-# An array of `int` in C (`int*`)
-extern class NativeCIntArray `{ int* `}
+# An array of `unsigned char` in C (`unsigned char*`)
+extern class NativeCByteArray `{ unsigned char* `}
super NativeCArray
redef type E: Int
- redef type SELF: NativeCIntArray
- new(size: Int) `{ return calloc(size, sizeof(int)); `}
+ # Allocate a new array of `size`
+ new(size: Int) `{ return calloc(size, sizeof(unsigned char)); `}
+
redef fun [](index) `{ return recv[index]; `}
redef fun []=(index, val) `{ recv[index] = val; `}
redef class NativeString
super NativeCArray
redef type E: Char
- redef type SELF: NativeString
redef fun +(offset) `{ return recv + offset; `}
end
--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Copyright 2014 Alexis Laferrière <alexis.laf@xymus.net>
+#
+# 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.
+
+# The Application Kit provides services to create GUI
+module app_kit is c_linker_option "-framework AppKit"
+
+import foundation
+
+in "ObjC Header" `{
+ #import <AppKit/AppKit.h>
+`}
+
+# A simple message box
+extern class NSAlert in "ObjC" `{ NSAlert * `}
+ super NSObject
+
+ # Allocate and instanciate a new `NSAlert`
+ new in "ObjC" `{ return [[NSAlert alloc] init]; `}
+
+ # Set the content of this message box
+ fun message_text=(text: NSString) in "ObjC" `{ [recv setMessageText:text]; `}
+
+ # Show this message box
+ fun run_modal in "ObjC" `{ [recv runModal]; `}
+end
--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Copyright 2014 Alexis Laferrière <alexis.laf@xymus.net>
+#
+# 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.
+
+# The Cocoa API is the development layer of OS X
+#
+# This module is only compatible with OS X.
+#
+# This wrapper of the Cocoa API regroups the Foundation Kit and the
+# Application Kit.
+module cocoa is c_linker_option "-framework Cocoa"
+
+import foundation
+import app_kit
--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Copyright 2014 Alexis Laferrière <alexis.laf@xymus.net>
+#
+# 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.
+
+# Test extern classes from the Cocoa framework and extern factories
+module cocoa_extern_types
+
+import cocoa
+
+in "ObjC Header" `{
+ // for `NSString::hello`
+ #import <Foundation/Foundation.h>
+`}
+
+redef extern class NSString
+
+ # Additionnal factory
+ new hello in "ObjC" `{ return @"Factory Hello"; `}
+end
+
+# Print a custom string to the log
+fun nslog(text: NSString) in "ObjC" `{
+ NSLog(text);
+`}
+
+nslog "Hello using to_nsstring".to_nsstring
+nslog new NSString.hello
+
+var msg_box = new NSAlert
+msg_box.message_text = "From Nit".to_nsstring
+if "NIT_TESTING".environ != "true" then msg_box.run_modal
--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Copyright 2014 Alexis Laferrière <alexis.laf@xymus.net>
+#
+# 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.
+
+# Simple message box using the Cocoa framework
+module cocoa_message_box
+
+import cocoa
+
+in "ObjC" `{
+ #import <Cocoa/Cocoa.h>
+`}
+
+fun dialog in "ObjC" `{
+ NSAlert *alert = [[[NSAlert alloc] init] autorelease];
+ [alert setMessageText:@"Hello world!"];
+ [alert runModal];
+`}
+
+if "NIT_TESTING".environ != "true" then dialog
--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Copyright 2014 Alexis Laferrière <alexis.laf@xymus.net>
+#
+# 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.
+
+# Hello world using the Cocoa framework
+module hello_cocoa
+
+import cocoa::foundation
+
+in "ObjC" `{
+ #import <Foundation/Foundation.h>
+`}
+
+# Print `"Hello world!"` to the log
+fun hello_world in "ObjC" `{
+ @autoreleasepool {
+ NSLog(@"Hello World!");
+ }
+`}
+
+hello_world
--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Copyright 2014 Alexis Laferrière <alexis.laf@xymus.net>
+#
+# 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.
+
+# The Foundation Kit provides basic Objective-C classes and structures
+module foundation is c_linker_option "-framework Foundation"
+
+in "ObjC Header" `{
+ #import <Foundation/Foundation.h>
+`}
+
+# Base of the Foundation framework class hierarchy
+extern class NSObject in "ObjC" `{ NSObject * `}
+end
+
+# String of the Foundation Kit
+#
+# Created using `Text::to_nsstring`.
+extern class NSString in "ObjC" `{ NSString * `}
+ super NSObject
+end
+
+redef class NativeString
+ # Get a `NSString` from `self` with the specified `length`
+ fun to_nsstring(length: Int): NSString in "ObjC" `{
+ return [[NSString alloc] initWithBytes:recv
+ length:length
+ encoding:NSASCIIStringEncoding];
+ `}
+end
+
+redef class Text
+ # Get a `NSString` from `self`
+ fun to_nsstring: NSString do return to_cstring.to_nsstring(length)
+end
var collection: CartesianCollection[E]
# The array of iterations that will be increased in the lexicographic order.
- private var iterators = new Array[Iterator[E]]
+ var iterators = new Array[Iterator[E]]
init
do
super Iterator[SequenceRead[E]]
var product: CombinationCollection[E]
- private var iterators = new Array[Iterator[E]]
- private var indices = new Array[Int]
+ var iterators = new Array[Iterator[E]]
+ var indices = new Array[Int]
var are_sorted: Bool is noinit
var are_unique: Bool is noinit
end
end
- private fun next_free(rank: Int, start: Int): Int
+ fun next_free(rank: Int, start: Int): Int
do
loop
for i in [0..rank[ do
return start
end
- private fun reset_iterator(rank: Int): Iterator[E]
+ fun reset_iterator(rank: Int): Iterator[E]
do
var it = product.collection.iterator
iterators[rank] = it
class TermMoveUp
super TermDirectionalMove
- init do end
-
# Move by the specified number of cells.
init by(magnitude: Int) do self.magnitude = magnitude
class TermMoveDown
super TermDirectionalMove
- init do end
-
# Move by the specified number of cells.
init by(magnitude: Int) do self.magnitude = magnitude
class TermMoveFoward
super TermDirectionalMove
- init do end
-
# Move by the specified number of cells.
init by(magnitude: Int) do self.magnitude = magnitude
class TermMoveBackward
super TermDirectionalMove
- init do end
-
# Move by the specified number of cells.
init by(magnitude: Int) do self.magnitude = magnitude
# 1 is the left.
var column: Int = 1
- init do end
-
# Move at the specified position.
#
# (1, 1) is the top-left corner of the display.
extern class CppString in "C++" `{ std::string* `}
end
-redef class String
- fun to_cpp_string: CppString do return to_cstring.to_cpp_string
+redef class Text
+ # Get `self` as a `CppString`
+ fun to_cpp_string: CppString do return to_cstring.to_cpp_string(length)
end
redef class NativeString
- fun to_cpp_string: CppString in "C++" `{
- return new std::string(recv);
+ # Get `self` as a `CppString`
+ fun to_cpp_string(length: Int): CppString in "C++" `{
+ return new std::string(recv, length);
`}
end
var rot = x % 26
if rot < 0 then rot += 26
var d = new FlatBuffer.with_capacity(length)
- var p = 0
for i in chars do
d.add i.rot(rot)
end
+++ /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.
-
-# CSV output facilities
-module csv
-
-# A CSV document representation
-class CSVDocument
- super Streamable
-
- var header: Array[String] = new Array[String] is writable
- var lines: Array[Array[String]] = new Array[Array[String]]
-
- fun set_header(values: Object...) do
- header.clear
- for value in values do
- header.add(value.to_s)
- end
- end
-
- fun add_line(values: Object...) do
- if values.length != header.length then
- print "CSV error: header declares {header.length} columns, line contains {values.length} values"
- abort
- end
- var line = new Array[String]
- for value in values do
- line.add(value.to_s)
- end
- lines.add(line)
- end
-
- private fun write_line_to(line: Collection[String], stream: OStream)
- do
- var i = line.iterator
- if i.is_ok then
- stream.write(i.item)
- i.next
- while i.is_ok do
- stream.write(";")
- stream.write(i.item)
- i.next
- end
- end
- stream.write("\n")
- end
-
- redef fun write_to(stream)
- do
- write_line_to(header, stream)
- for line in lines do write_line_to(line, stream)
- end
-
- # deprecated alias for `write_to_file`
- fun save(file: String) do write_to_file(file)
-end
--- /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.
+
+# CSV document handling.
+module csv
+
+# Specifies a CSV format.
+class CsvFormat
+ # The character that delimits escaped value.
+ #
+ # The delimiter is escaped by doubling it.
+ var delimiter: Char
+
+ # The character that split each cell in a row.
+ var separator: Char
+
+ # The character that ends a row (end of line).
+ var eol: String
+
+ # Escape sequence for the delimiter.
+ private var escaping = "{delimiter}{delimiter}" is lazy
+
+ # Escape the specified cell.
+ private fun escape_cell(cell: String): Text do
+ var result = new RopeBuffer
+ result.add delimiter
+ result.append cell.replace(delimiter, escaping)
+ result.add delimiter
+ return result
+ end
+
+ # Can the specified value be inserted without any escaping?
+ private fun is_value_clean(value: String): Bool do
+ for c in value.chars do
+ if c == delimiter then return false
+ if c == separator then return false
+ if eol.chars.has(c) then return false
+ end
+ return true
+ end
+end
+
+# A CSV document representation.
+class CsvDocument
+ super Streamable
+
+ # The format to use.
+ #
+ # Defaults to `rfc4180`.
+ var format: CsvFormat = rfc4180 is writable
+
+ # The header.
+ #
+ # Contains the name of all fields in this table.
+ var header: Array[String] = new Array[String] is writable
+
+ # The list of the records.
+ #
+ # All records must have the same length than `header`.
+ var records: Array[Array[String]] = new Array[Array[String]]
+
+ # Replace the header by the specified row.
+ fun set_header(values: Object...) do
+ header.clear
+ for value in values do header.add(value.to_s)
+ end
+
+ # Append the specfied record.
+ fun add_record(values: Object...) do
+ assert values.length == header.length else
+ sys.stderr.write "CSV error: Header declares {header.length} columns, record contains {values.length} values.\n"
+ end
+ var record = new Array[String]
+ for value in values do record.add(value.to_s)
+ records.add(record)
+ end
+
+ redef fun write_to(stream) do
+ var writer = new CsvWriter.with_format(stream, format)
+ writer.write_sequence(header)
+ for record in records do writer.write_sequence(record)
+ end
+
+ # Deprecated alias for `write_to_file`.
+ fun save(file: String) do write_to_file(file)
+
+ # Load from the specified stream.
+ #
+ # Parameters:
+ #
+ # * `stream`: Input stream.
+ # * `has_header`: Is the first row the header?
+ # * `skip_empty`: Do we skip the empty lines?
+ # For details, see `CsvReader.skip_empty`.
+ fun load_from(stream: IStream, has_header: Bool, skip_empty: Bool) do
+ var reader = new CsvReader.with_format(stream, format)
+ reader.skip_empty = skip_empty
+ if has_header then
+ if reader.is_ok then
+ header = reader.item
+ else
+ header.clear
+ end
+ end
+ records.clear
+ for record in reader do records.add(record)
+ end
+
+ # Load from the specified file.
+ #
+ # Parameters:
+ #
+ # * `path`: Path of the file.
+ # * `has_header`: Is the first row the header?
+ # * `skip_empty`: Do we skip the empty lines?
+ fun load(path: String, has_header: Bool, skip_empty: Bool) do
+ var istream = new IFStream.open(path)
+ load_from(istream, has_header, skip_empty)
+ istream.close
+ end
+end
+
+# Appends CSV rows to a file.
+#
+# By default, uses the format recommended by RFC 4180 (see `rfc4180`).
+#
+# Note: If a row contains only an empty cell, its representation is
+# undistinguishable from an empty line. This is because the empty values are
+# always written unescaped in order to avoid them to be interpreted as escaped
+# delimiters by some parsers.
+#
+# ~~~nit
+# var out = new StringOStream
+# var writer = new CsvWriter(out)
+# writer.write_row(1, 2.0, "foo\nbar")
+# writer.write_sequence([""])
+# assert out.to_s == """1,2.0,"foo\nbar"\r\n\r\n"""
+# ~~~
+class CsvWriter
+
+ # The output stream.
+ var ostream: OStream
+
+ # The format to use.
+ #
+ # Defaults to `rfc4180`.
+ var format: CsvFormat = rfc4180
+
+ # Do we escape all cells (except empty ones)?
+ #
+ # If `false` (the default), escape only cells that contain a metacharacter
+ # of the format. In all cases, empty cells are not escaped. This option
+ # permits to choose between the optimization of the performances (when
+ # `true`) and optimization of the size of the output (when `false`).
+ #
+ # Note: Escaping may not be correctly recognized by some parsers.
+ var always_escape = false is writable
+
+ # Create a new writer with the specified format.
+ init with_format(ostream:OStream, format: CsvFormat) do
+ self.ostream = ostream
+ self.format = format
+ end
+
+ # Append the specified sequence as a row.
+ #
+ # The representation of each cell is determined by `to_s`.
+ fun write_sequence(row: SequenceRead[Object]) do
+ if not row.is_empty then
+ var i = row.iterator
+ var separator = format.separator.to_s
+ write_cell i.item.to_s
+ i.next
+ for cell in i do
+ ostream.write separator
+ write_cell cell.to_s
+ end
+ end
+ ostream.write format.eol
+ end
+
+ # Append the specified row.
+ #
+ # The representation of each cell is determined by `to_s`.
+ fun write_row(row: Object...) do write_sequence(row)
+
+ # Close the output stream.
+ fun close do ostream.close
+
+ private fun write_cell(cell: String) do
+ if cell.is_empty then return
+ if not always_escape and format.is_value_clean(cell) then
+ ostream.write cell
+ else
+ ostream.write format.escape_cell(cell)
+ end
+ end
+end
+
+# Reads rows from a CSV file.
+#
+# By default, uses the format recommended by RFC 4180 (see `rfc4180`).
+#
+# ~~~nit
+# var example = new StringIStream("""
+# foo,bar\r
+# "Hello, word!",1234.5 + 42\r
+# "Something\r
+# ""else""\", baz\r
+# """)
+# var reader = new CsvReader(example)
+# var table = new Array[Array[String]]
+#
+# for row in reader do table.add row
+# assert table == [
+# ["foo","bar"],
+# ["Hello, word!","1234.5 + 42"],
+# ["Something\r\n\"else\""," baz"]
+# ]
+# ~~~
+class CsvReader
+ super Iterator[Array[String]]
+
+ # The input stream.
+ var istream: IStream
+
+ # The format to use.
+ #
+ # Defaults to `rfc4180`.
+ var format: CsvFormat = rfc4180 is lazy
+
+ # Do we skip the empty lines?
+ #
+ # Note: Even if this attribute is `false`, the presence of an line ending at
+ # end of the last row does not change the number of returned rows.
+ # This is because the line endings are processed as terminators, not as
+ # separators. Therefore, when there is more than one line ending at the end
+ # of the file, the additional lines are interpreted as empty rows that
+ # are skipped only if `skip_empty` is set to `true`.
+ #
+ # `false` by default.
+ var skip_empty: Bool = false is writable
+
+ # The last read row.
+ private var row: nullable Array[String] = null
+
+ # Did we read something?
+ private var started = false
+
+ # Create a new reader with the specified format.
+ init with_format(istream:IStream, format: CsvFormat) do
+ self.istream = istream
+ self.format = format
+ end
+
+ # Read the first row, if needed.
+ fun prepare do
+ if not started then
+ row = read_row
+ started = true
+ end
+ end
+
+ redef fun next do
+ prepare
+ assert is_ok else
+ sys.stderr.write "Already at the end of the stream.\n"
+ end
+ row = read_row
+ end
+
+ # Return the last read row.
+ redef fun item do
+ prepare
+ return row.as(not null)
+ end
+
+ redef fun is_ok do
+ prepare
+ return row != null
+ end
+
+ # Free some internal ressources and set `is_ok` to `false`.
+ #
+ # Do not close the input stream.
+ redef fun finish do row = null
+
+ # Close the input stream.
+ fun close do istream.close
+
+ private fun read_row: nullable Array[String] do
+ if istream.eof then return null
+ var row = new Array[String]
+ var value = new RopeBuffer
+
+ # Number of unescaped characters since the last delimiter or separator.
+ var unescaped = 0
+
+ # Do we read the start of a row?
+ var got_row = false
+
+ # Do we found a delimited string in the current cell?
+ var got_delimiter = false
+
+ loop
+ var i = istream.read_char
+ var c: Char
+
+ if i < 0 then
+ if got_row then
+ row.add value.to_s
+ return row
+ else
+ return null
+ end
+ end
+ c = i.ascii
+
+ if c == format.delimiter then
+ if got_delimiter and unescaped == 0 then
+ # Got an escaped delimiter.
+ value.add format.delimiter
+ end
+ # Read all bytes until the delimiter.
+ loop
+ i = istream.read_char
+ assert not_eof: i >= 0 else
+ sys.stderr.write "Unexpected end of file before the end of a delimited value.\n"
+ end
+ c = i.ascii
+ if c == format.delimiter then break
+ value.add c
+ end
+ unescaped = 0
+ got_row = true
+ got_delimiter = true
+ else if c == format.separator then
+ # Flush the value to the row.
+ row.add value.to_s
+ value.clear
+ unescaped = 0
+ got_delimiter = false
+ else
+ value.add c
+ unescaped += 1
+ if unescaped >= format.eol.length and
+ value.has_suffix(format.eol) then
+ var value_trimed = value.substring(0,
+ value.length - format.eol.length).to_s
+ if skip_empty and row.is_empty and
+ value_trimed.is_empty and
+ not got_delimiter then
+ # Skip the empty line.
+ value.clear
+ unescaped = 0
+ got_row = false
+ else
+ row.add value_trimed
+ return row
+ end
+ else
+ got_row = true
+ end
+ end
+ end
+ end
+end
+
+# The CSV format recommended by [RFC 4180](https://tools.ietf.org/html/rfc4180).
+#
+# * `delimiter`: `'"'`
+# * `separator`: `','`
+# * `eol`: `"\r\n"`
+fun rfc4180: CsvFormat do return once new CsvFormat('"', ',', "\r\n")
--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# This file is free software, which comes along with NIT. This software is
+# distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+# without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE. You can modify it is you want, provided this header
+# is kept unaltered, and a notification of the changes is added.
+# You are allowed to redistribute it and sell it, alone or is a part of
+# another product.
+
+# Tests for `csv`.
+module test_csv is test_suite
+
+import test_suite
+import csv
+
+class TestCsvWriter
+ super TestSuite
+
+ # The custom CSV format used in the tests.
+ private var custom_format = new CsvFormat('/', ':', "#")
+
+ # Expect to write `row` as `expected_rfc4180` and as `expected_custom`.
+ #
+ # Parameters:
+ #
+ # * `always_escape`: value of the `always_escape` option.
+ # * `row`: row to write.
+ # * `expected_rfc4180`: expected result in RFC 4180.
+ # * `expected_custom`: expected result in the custom CSV format.
+ private fun expect(always_escape: Bool, row: SequenceRead[String],
+ expected_rfc4180: String,
+ expected_custom: String) do
+ var out = new StringOStream
+ var writer = new CsvWriter(out)
+
+ writer.always_escape = always_escape
+ writer.write_sequence(row)
+ assert out.to_s == expected_rfc4180 else
+ sys.stderr.write "\nFormat: RFC 4180\n"
+ sys.stderr.write "Expecting: \"{expected_rfc4180.escape_to_nit}\"\n"
+ sys.stderr.write "Got: \"{out.to_s.escape_to_nit}\"\n"
+ end
+ writer.close
+
+ out = new StringOStream
+ writer = new CsvWriter.with_format(out, custom_format)
+ writer.always_escape = always_escape
+ writer.write_sequence(row)
+ assert out.to_s == expected_custom else
+ sys.stderr.write "\nFormat: {custom_format.delimiter}"
+ sys.stderr.write " {custom_format.separator}"
+ sys.stderr.write " {custom_format.eol.escape_to_nit}\n"
+ sys.stderr.write "Expecting: \"{expected_custom.escape_to_nit}\"\n"
+ sys.stderr.write "Got: \"{out.to_s.escape_to_nit}\"\n"
+ end
+ writer.close
+ end
+
+ fun test_empty do expect(true, new Array[String], "\r\n", "#")
+
+ fun test_one_cell do expect(true, ["foo/\"\r\n,"],
+ "\"foo/\"\"\r\n,\"\r\n",
+ "/foo//\"\r\n,/#")
+
+ fun test_optimize_size_escaped do expect(false, ["foo/\"\r\n,"],
+ "\"foo/\"\"\r\n,\"\r\n",
+ "/foo//\"\r\n,/#")
+
+ fun test_optimize_size_eol do expect(false, ["foo\r#\n"],
+ "\"foo\r#\n\"\r\n",
+ "/foo\r#\n/#")
+
+ fun test_optimize_size_unescaped do expect(false, ["foo"],
+ "foo\r\n",
+ "foo#")
+
+ fun test_multiple_cells do expect(true, ["1", "", "/"],
+ "\"1\",,\"/\"\r\n",
+ "/1/::////#")
+
+ fun test_multiple_cells_optimize_size do expect(false, ["1", "", "/"],
+ "1,,/\r\n",
+ "1::////#")
+end
+
+class TestCsvReader
+ super TestSuite
+
+ # The custom CSV format used in the tests.
+ private var custom_format = new CsvFormat('/', ':', "#")
+
+ # Expect to read `expected`.
+ #
+ # Parameters:
+ #
+ # * `skip_empty`: value of the `skip_empty` option.
+ # * `modal_escaping`: value of the `modal_escaping` option.
+ # * `input_rfc4180`: input in the RFC 4180 format.
+ # * `input_custom`: input in the custom CSV format.
+ # * `expected`: expected resulting table.
+ private fun expect(skip_empty: Bool,
+ input_rfc4180: String,
+ input_custom: String,
+ expected: SequenceRead[SequenceRead[String]]) do
+ var istream: IStream
+ var reader: CsvReader
+ var i = 0
+
+ istream = new StringIStream(input_rfc4180)
+ reader = new CsvReader(istream)
+ reader.skip_empty = skip_empty
+ assert_table_equals("RFC 4180", reader, expected.iterator)
+
+ istream = new StringIStream(input_custom)
+ reader = new CsvReader.with_format(istream, custom_format)
+ reader.skip_empty = skip_empty
+ assert_table_equals("{custom_format.delimiter} " +
+ "{custom_format.separator} " +
+ "{custom_format.eol.escape_to_nit}", reader, expected.iterator)
+ end
+
+ # Check if tables are equal.
+ private fun assert_table_equals(format: String,
+ actual: Iterator[SequenceRead[String]],
+ expected: Iterator[SequenceRead[String]]) do
+ var i = 0
+
+ for actual_row in actual do
+ assert expected.is_ok else fail(format,"Too many rows.")
+ var expected_row = expected.item
+ assert_row_equals(format, i, actual_row, expected_row)
+ expected.next
+ i += 1
+ end
+ assert not expected.is_ok else fail(format, "Not enough rows.")
+ expected.finish
+ end
+
+ # Check if rows are equal.
+ private fun assert_row_equals(format: String,
+ row_index: Int,
+ actual: SequenceRead[String],
+ expected: SequenceRead[String]) do
+ assert actual == expected else
+ fail(format, """
+At row {{{row_index}}}.
+Expecting: {{{expected.join("|")}}}
+Got: {{{actual.join("|")}}}""")
+ end
+ end
+
+ # Output an error message with an indication of the format used.
+ private fun fail(format: Text, message: Text) do
+ sys.stderr.write "\nFormat: {format}\n"
+ sys.stderr.write message
+ sys.stderr.write "\n"
+ end
+
+ fun test_empty do expect(false, "", "", new Array[Array[String]])
+
+ fun test_empty_eol do expect(false, "\r\n", "#", [[""]])
+
+ fun test_empty_skip do expect(true, "", "", new Array[Array[String]])
+
+ fun test_empty_skip1 do expect(true, "\r\n", "#", new Array[Array[String]])
+
+ fun test_empty_skip2 do expect(true, "\r\n\r\n", "##", new Array[Array[String]])
+
+ fun test_escaped do expect(false, "\"foo/\"\"\r\n,\"\r\n",
+ "/foo//\"\r\n,/#", [["foo/\"\r\n,"]])
+
+ fun test_unescaped do expect(false, "foo bar\r\n",
+ "foo bar#", [["foo bar"]])
+
+ fun test_escaped_no_eol do expect(false, "\"foo/\"\"\r\n,\"",
+ "/foo//\"\r\n,/", [["foo/\"\r\n,"]])
+
+ fun test_unescaped_no_eol do expect(false, "foo bar",
+ "foo bar", [["foo bar"]])
+
+ fun test_multiple_cells do expect(false, "\"1\",,\"/\"\r\n",
+ "/1/::////#", [["1", "", "/"]])
+
+ fun test_multiple_cells_unescaped do expect(false, "1,,/\r\n",
+ "1::////#", [["1", "", "/"]])
+
+ fun test_modal_escaping do expect(false, """a"b""/c","d"e""",
+ """/ab"///c:d/e/""", [["""ab"/c""", "de"]])
+
+ fun test_skip_start do expect(true, "\r\n1,,/\r\n",
+ "#1::////#", [["1", "", "/"]])
+
+ fun test_dont_skip_empty_delimited do expect(true, "\"\"\r\n",
+ "//#", [[""]])
+
+ fun test_dont_skip_multiple_empty_cells do expect(true, ",\r\n",
+ ":#", [["",""]])
+
+ fun test_mutiple_rows do expect(false, "\"a\r\nb#\",c\r\nd,\r\n,e\r\n",
+ "/a\r\nb#/:c#d:#:e#", [["a\r\nb#", "c"], ["d", ""], ["", "e"]])
+end
# This file is part of NIT ( http://www.nitlanguage.org ).
#
# Copyright 2008 Floréal Morandat <morandat@lirmm.fr>
+# Copyright 2014 Alexandre Terrasa <alexandre@moz-code.org>
#
# This file is free software, which comes along with NIT. This software is
# distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
# You are allowed to redistribute it and sell it, alone or is a part of
# another product.
+# A `Set` that contains only integers.
class DummyArray
super Set[Int]
private var capacity: Int
return _values[pos]
end
- init(capacity: Int)
- do
+ # initialize a new DummyArray with `capacity`.
+ init(capacity: Int) is old_style_init do
_capacity = capacity
_keys = new NativeArray[Int](capacity)
_values = new NativeArray[Int](capacity)
end
end
+# An iterator over a `DummyArray`.
class DummyIterator
super Iterator[Int]
private var array: DummyArray
redef fun next do _pos = _pos + 1 end
- init(array: DummyArray)
- do
+ # Initialize an iterator for `array`.
+ init(array: DummyArray) is old_style_init do
_pos = 0
_array = array
end
return NativeString_to_s((char *)eglQueryString(recv, name));
`}
- fun vendor: String do return query_string("3053".to_hex)
+ fun vendor: String do return query_string(0x3053)
- fun version: String do return query_string("3054".to_hex)
+ fun version: String do return query_string(0x3054)
- fun extensions: Array[String] do return query_string("3055".to_hex).split_with(" ")
+ fun extensions: Array[String] do return query_string(0x3055).split_with(" ")
- fun client_apis: Array[String] do return query_string("308D".to_hex).split_with(" ")
+ fun client_apis: Array[String] do return query_string(0x308D).split_with(" ")
fun swap_buffers(surface: EGLSurface) `{ eglSwapBuffers(recv, surface); `}
end
var display: EGLDisplay
var config: EGLConfig
- fun buffer_size: Int do return display.config_attrib(config, "3020".to_hex)
- fun alpha_size: Int do return display.config_attrib(config, "3021".to_hex)
- fun blue_size: Int do return display.config_attrib(config, "3022".to_hex)
- fun green_size: Int do return display.config_attrib(config, "3023".to_hex)
- fun red_size: Int do return display.config_attrib(config, "3024".to_hex)
- fun depth_size: Int do return display.config_attrib(config, "3025".to_hex)
- fun stencil_size: Int do return display.config_attrib(config, "3026".to_hex)
+ fun buffer_size: Int do return display.config_attrib(config, 0x3020)
+ fun alpha_size: Int do return display.config_attrib(config, 0x3021)
+ fun blue_size: Int do return display.config_attrib(config, 0x3022)
+ fun green_size: Int do return display.config_attrib(config, 0x3023)
+ fun red_size: Int do return display.config_attrib(config, 0x3024)
+ fun depth_size: Int do return display.config_attrib(config, 0x3025)
+ fun stencil_size: Int do return display.config_attrib(config, 0x3026)
- fun native_visual_id: Int do return display.config_attrib(config, "302E".to_hex)
- fun native_visual_type: Int do return display.config_attrib(config, "302F".to_hex)
+ fun native_visual_id: Int do return display.config_attrib(config, 0x302E)
+ fun native_visual_type: Int do return display.config_attrib(config, 0x302F)
fun caveat: EGLConfigCaveat do
- return new EGLConfigCaveat.from_i(display.config_attrib(config, "3027".to_hex))
+ return new EGLConfigCaveat.from_i(display.config_attrib(config, 0x3027))
end
fun conformant: EGLConformant do
- return new EGLConformant.from_i(display.config_attrib(config, "3042".to_hex))
+ return new EGLConformant.from_i(display.config_attrib(config, 0x3042))
end
end
var display: EGLDisplay
var surface: EGLSurface
- fun height: Int do return display.query_surface(surface, "3056".to_hex)
- fun width: Int do return display.query_surface(surface, "3057".to_hex)
- fun largest_pbuffer: Int do return display.query_surface(surface, "3058".to_hex)
- fun texture_format: Int do return display.query_surface(surface, "3080".to_hex)
- fun texture_target: Int do return display.query_surface(surface, "3081".to_hex)
- fun mipmap_texture: Int do return display.query_surface(surface, "3082".to_hex)
- fun mipmap_level: Int do return display.query_surface(surface, "3083".to_hex)
- fun render_buffer: Int do return display.query_surface(surface, "3086".to_hex)
- fun vg_colorspace: Int do return display.query_surface(surface, "3087".to_hex)
- fun vg_alpha_format: Int do return display.query_surface(surface, "3088".to_hex)
- fun horizontal_resolution: Int do return display.query_surface(surface, "3090".to_hex)
- fun vertical_resolution: Int do return display.query_surface(surface, "3091".to_hex)
- fun pixel_aspect_ratio: Int do return display.query_surface(surface, "3092".to_hex)
- fun swap_behavior: Int do return display.query_surface(surface, "3093".to_hex)
- fun multisample_resolve: Int do return display.query_surface(surface, "3099".to_hex)
+ fun height: Int do return display.query_surface(surface, 0x3056)
+ fun width: Int do return display.query_surface(surface, 0x3057)
+ fun largest_pbuffer: Int do return display.query_surface(surface, 0x3058)
+ fun texture_format: Int do return display.query_surface(surface, 0x3080)
+ fun texture_target: Int do return display.query_surface(surface, 0x3081)
+ fun mipmap_texture: Int do return display.query_surface(surface, 0x3082)
+ fun mipmap_level: Int do return display.query_surface(surface, 0x3083)
+ fun render_buffer: Int do return display.query_surface(surface, 0x3086)
+ fun vg_colorspace: Int do return display.query_surface(surface, 0x3087)
+ fun vg_alpha_format: Int do return display.query_surface(surface, 0x3088)
+ fun horizontal_resolution: Int do return display.query_surface(surface, 0x3090)
+ fun vertical_resolution: Int do return display.query_surface(surface, 0x3091)
+ fun pixel_aspect_ratio: Int do return display.query_surface(surface, 0x3092)
+ fun swap_behavior: Int do return display.query_surface(surface, 0x3093)
+ fun multisample_resolve: Int do return display.query_surface(surface, 0x3099)
end
extern class EGLError `{ EGLint `}
end
fun close do
- insert_attrib_key "3038".to_hex
+ insert_attrib_key 0x3038
closed = true
end
- fun surface_type=(flag: Int) do insert_attrib_with_val("3033".to_hex, flag)
+ fun surface_type=(flag: Int) do insert_attrib_with_val(0x3033, flag)
fun surface_type_egl do surface_type = 4
- fun blue_size=(size: Int) do insert_attrib_with_val("3022".to_hex, size)
- fun green_size=(size: Int) do insert_attrib_with_val("3023".to_hex, size)
- fun red_size=(size: Int) do insert_attrib_with_val("3024".to_hex, size)
+ fun blue_size=(size: Int) do insert_attrib_with_val(0x3022, size)
+ fun green_size=(size: Int) do insert_attrib_with_val(0x3023, size)
+ fun red_size=(size: Int) do insert_attrib_with_val(0x3024, size)
- fun buffer_size=(size: Int) do insert_attrib_with_val("3020".to_hex, size)
- fun alpha_size=(size: Int) do insert_attrib_with_val("3021".to_hex, size)
- fun depth_size=(size: Int) do insert_attrib_with_val("3025".to_hex, size)
- fun stencil_size=(size: Int) do insert_attrib_with_val("3026".to_hex, size)
- fun sample_buffers=(size: Int) do insert_attrib_with_val("3031".to_hex, size)
+ fun buffer_size=(size: Int) do insert_attrib_with_val(0x3020, size)
+ fun alpha_size=(size: Int) do insert_attrib_with_val(0x3021, size)
+ fun depth_size=(size: Int) do insert_attrib_with_val(0x3025, size)
+ fun stencil_size=(size: Int) do insert_attrib_with_val(0x3026, size)
+ fun sample_buffers=(size: Int) do insert_attrib_with_val(0x3031, size)
- fun caveat=(caveat: EGLConfigCaveat) do insert_attrib_with_val("3050".to_hex, caveat.to_i)
+ fun caveat=(caveat: EGLConfigCaveat) do insert_attrib_with_val(0x3050, caveat.to_i)
- fun conformant=(conformant: EGLConformant) do insert_attrib_with_val("3042".to_hex, conformant.to_i)
+ fun conformant=(conformant: EGLConformant) do insert_attrib_with_val(0x3042, conformant.to_i)
fun choose(display: EGLDisplay): nullable Array[EGLConfig]
do
# See the License for the specific language governing permissions and
# limitations under the License.
+# Platform for the _emscripten_ framework
+#
+# Importing this module from your project will tell _nitg_ to compile
+# to JavaScript for the _emscripten_ framework.
module emscripten is platform
`{
#include <gc.h>
`}
-redef class String
+redef class Text
+ # Run `self` as JavaScript code
fun run_js do run_js_native(self.escape_to_js.to_cstring)
+
private fun run_js_native(script: NativeString) `{ emscripten_run_script(script); `}
- fun escape_to_js: String do return self.replace('\n', "\\n")
+ # Escape the content of `self` to pass to JavaScript code
+ fun escape_to_js: Text do return replace('\n', "\\n")
+ # Raise a JavaScript alert
fun alert do "alert('{self.escape_to_js}')".run_js
end
self.top >= other.bottom and other.top >= self.bottom
end
- # Create a bounding box that englobes the actual bounding box.
+ # Create a bounding box that encloses the actual bounding box.
# `dist` is the distance between the inner boundaries and the outer boundaries.
# ~~~
# var p = new Point[Int](5,10)
# var b = p.padded(3)
- # assert b.top == 2 and b.bot = 8 and b.left == 7 and b.right == 13
+ # assert b.left == 2 and b.right == 8 and b.top == 13 and b.bottom == 7
# ~~~
fun padded(dist: N): Box[N] do return new Box[N].lrtb(left - dist, right + dist, top + dist, bottom - dist)
end
super Curl
# Headers to use on all requests
- var header: HeaderMap
+ var header: HeaderMap is noinit
# OAuth token
var auth: String
# Eg. "Awesome-Octocat-App"
var user_agent: String
- init(auth: String, user_agent: String)
- do
- super
- self.auth = auth
- self.user_agent = user_agent
-
+ init do
header = new HeaderMap
header["Authorization"] = "token {auth}"
end
# See the License for the specific language governing permissions and
# limitations under the License.
-# OpenGL graphics rendering library for embedded systems, version 2.0.
+# OpenGL graphics rendering library for embedded systems, version 2.0
+#
+# This is a low-level wrapper, it can be useful for developers already familiar
+# with the C API of OpenGL. Most developers will prefer to use higher level
+# wrappers such as `mnit` and `gammit`.
+#
+# Defines the annotations `glsl_vertex_shader` and `glsl_fragment_shader`
+# applicable on string literals to check shader code using `glslangValidator`.
+# The tool must be in PATH. It can be downloaded from
+# https://www.khronos.org/opengles/sdk/tools/Reference-Compiler/
#
# Most services of this module are a direct wrapper of the underlying
# C library. If a method or class is not documented in Nit, refer to
# the official documentation by the Khronos Group at:
# http://www.khronos.org/opengles/sdk/docs/man/
-module glesv2 is pkgconfig
+module glesv2 is
+ pkgconfig
+ new_annotation glsl_vertex_shader
+ new_annotation glsl_fragment_shader
+end
+
in "C Header" `{
#include <GLES2/gl2.h>
`}
-# Opengl ES program to which we attach shaders
+# OpenGL ES program to which we attach shaders
extern class GLProgram `{GLuint`}
+ # Create a new program
+ #
+ # The newly created instance should be checked using `is_ok`.
new `{ return glCreateProgram(); `}
+ # Is this a valid program?
fun is_ok: Bool `{ return glIsProgram(recv); `}
+ # Attach a `shader` to this program
fun attach_shader(shader: GLShader) `{ glAttachShader(recv, shader); `}
+ # Set the location for the attribute by `name`
fun bind_attrib_location(index: Int, name: String) import String.to_cstring `{
GLchar *c_name = String_to_cstring(name);
glBindAttribLocation(recv, index, c_name);
`}
+ # Get the location of the attribute by `name`
+ #
+ # Returns `-1` if there is no active attribute named `name`.
fun attrib_location(name: String): Int import String.to_cstring `{
GLchar *c_name = String_to_cstring(name);
return glGetAttribLocation(recv, c_name);
`}
+ # Get the location of the uniform by `name`
+ #
+ # Returns `-1` if there is no active uniform named `name`.
+ fun uniform_location(name: String): Int import String.to_cstring `{
+ GLchar *c_name = String_to_cstring(name);
+ return glGetUniformLocation(recv, c_name);
+ `}
+
+ # Query information on this program
fun query(pname: Int): Int `{
int val;
glGetProgramiv(recv, pname, &val);
return val;
`}
+ # Try to link this program
+ #
+ # Check result using `in_linked` and `info_log`.
fun link `{ glLinkProgram(recv); `}
- fun is_linked: Bool do return query("8B82".to_hex) != 0
+ # Is this program linked?
+ fun is_linked: Bool do return query(0x8B82) != 0
+
+ # Use this program for the following operations
fun use `{ glUseProgram(recv); `}
+ # Delete this program
fun delete `{ glDeleteProgram(recv); `}
- fun is_deleted: Bool do return query("8B80".to_hex) != 0
+ # Has this program been deleted?
+ fun is_deleted: Bool do return query(0x8B80) != 0
+
+ # Validate whether this program can be executed in the current OpenGL state
+ #
+ # Check results using `is_validated` and `info_log`.
fun validate `{ glValidateProgram(recv); `}
- fun is_validated: Bool do return query("8B83".to_hex) != 0
+ # Boolean result of `validate`, must be called after `validate`
+ fun is_validated: Bool do return query(0x8B83) != 0
+
+ # Retrieve the information log of this program
+ #
+ # Useful with `link` and `validate`
fun info_log: String import NativeString.to_s `{
int size;
glGetProgramiv(recv, GL_INFO_LOG_LENGTH, &size);
glGetProgramInfoLog(recv, size, NULL, msg);
return NativeString_to_s(msg);
`}
+
+ # Number of active uniform in this program
+ #
+ # This should be the number of uniforms declared in all shader, except
+ # unused uniforms which may have been optimized out.
+ fun n_active_uniforms: Int do return query(0x8B86)
+
+ # Length of the longest uniform name in this program, including `\n`
+ fun active_uniform_max_length: Int do return query(0x8B87)
+
+ # Number of active attributes in this program
+ #
+ # This should be the number of uniforms declared in all shader, except
+ # unused uniforms which may have been optimized out.
+ fun n_active_attributes: Int do return query(0x8B89)
+
+ # Length of the longest uniform name in this program, including `\n`
+ fun active_attribute_max_length: Int do return query(0x8B8A)
+
+ # Number of shaders attached to this program
+ fun n_attached_shaders: Int do return query(0x8B85)
+
+ # Name of the active attribute at `index`
+ fun active_attrib_name(index: Int): String
+ do
+ var max_size = active_attribute_max_length
+ return active_attrib_name_native(index, max_size).to_s
+ end
+ private fun active_attrib_name_native(index, max_size: Int): NativeString `{
+ char *name = malloc(max_size);
+ glGetActiveAttrib(recv, index, max_size, NULL, NULL, NULL, name);
+ return name;
+ `}
+
+ # Size of the active attribute at `index`
+ fun active_attrib_size(index: Int): Int `{
+ int size;
+ glGetActiveAttrib(recv, index, 0, NULL, NULL, &size, NULL);
+ return size;
+ `}
+
+ # Type of the active attribute at `index`
+ #
+ # May only be float related data types (single float, vectors and matrix).
+ fun active_attrib_type(index: Int): GLFloatDataType `{
+ GLenum type;
+ glGetActiveAttrib(recv, index, 0, NULL, &type, NULL, NULL);
+ return type;
+ `}
+
+ # Name of the active uniform at `index`
+ fun active_uniform_name(index: Int): String
+ do
+ var max_size = active_attribute_max_length
+ return active_uniform_name_native(index, max_size).to_s
+ end
+ private fun active_uniform_name_native(index, max_size: Int): NativeString `{
+ char *name = malloc(max_size);
+ glGetActiveUniform(recv, index, max_size, NULL, NULL, NULL, name);
+ return name;
+ `}
+
+ # Size of the active uniform at `index`
+ fun active_uniform_size(index: Int): Int `{
+ int size;
+ glGetActiveUniform(recv, index, 0, NULL, NULL, &size, NULL);
+ return size;
+ `}
+
+ # Type of the active uniform at `index`
+ #
+ # May be any data type supported by OpenGL ES 2.0 shaders.
+ fun active_uniform_type(index: Int): GLDataType `{
+ GLenum type;
+ glGetActiveUniform(recv, index, 0, NULL, &type, NULL, NULL);
+ return type;
+ `}
end
# Abstract OpenGL ES shader object, implemented by `GLFragmentShader` and `GLVertexShader`
extern class GLShader `{GLuint`}
+ # Set the source of the shader
fun source=(code: String) import String.to_cstring, String.length `{
GLchar *c_code = String_to_cstring(code);
glShaderSource(recv, 1, (const GLchar * const*)&c_code, NULL);
`}
- fun source: nullable String import NativeString.to_s `{
- int size;
- glGetShaderiv(recv, GL_SHADER_SOURCE_LENGTH, &size);
- if (size == 0) return NULL;
+
+ # Source of the shader, if available
+ #
+ # Returns `null` if the source is not available, usually when the shader
+ # was created from a binary file.
+ fun source: nullable String
+ do
+ var size = query(0x8B88)
+ if size == 0 then return null
+ return source_native(size).to_s
+ end
+
+ private fun source_native(size: Int): NativeString `{
GLchar *code = malloc(size);
glGetShaderSource(recv, size, NULL, code);
- return NativeString_to_s(code);
+ return code;
`}
+ # Query information on this shader
protected fun query(pname: Int): Int `{
int val;
glGetShaderiv(recv, pname, &val);
return val;
`}
+ # Try to compile `source` into a binary GPU program
+ #
+ # Check the result using `is_compiled` and `info_log`
fun compile `{ glCompileShader(recv); `}
- fun is_compiled: Bool do return query("8B81".to_hex) != 0
+ # Has this shader been compiled?
+ fun is_compiled: Bool do return query(0x8B81) != 0
+
+ # Delete this shader
fun delete `{ glDeleteShader(recv); `}
- fun is_deleted: Bool do return query("8B80".to_hex) != 0
+ # Has this shader been deleted?
+ fun is_deleted: Bool do return query(0x8B80) != 0
+
+ # Is this a valid shader?
fun is_ok: Bool `{ return glIsShader(recv); `}
+ # Retrieve the information log of this shader
+ #
+ # Useful with `link` and `validate`
fun info_log: String import NativeString.to_s `{
int size;
glGetShaderiv(recv, GL_INFO_LOG_LENGTH, &size);
glGetShaderInfoLog(recv, size, NULL, msg);
return NativeString_to_s(msg);
`}
-
end
+# An OpenGL ES 2.0 fragment shader
extern class GLFragmentShader
super GLShader
+ # Create a new fragment shader
+ #
+ # The newly created instance should be checked using `is_ok`.
new `{ return glCreateShader(GL_FRAGMENT_SHADER); `}
end
+# An OpenGL ES 2.0 vertex shader
extern class GLVertexShader
super GLShader
+ # Create a new fragment shader
+ #
+ # The newly created instance should be checked using `is_ok`.
new `{ return glCreateShader(GL_VERTEX_SHADER); `}
end
# An array of `Float` associated to a program variable
class VertexArray
var index: Int
+
+ # Number of data per vertex
var count: Int
+
protected var glfloat_array: GLfloatArray
init(index, count: Int, array: Array[Float])
`}
end
+# An OpenGL ES 2.0 error code
extern class GLError `{ GLenum `}
fun is_ok: Bool do return is_no_error
fun is_no_error: Bool `{ return recv == GL_NO_ERROR; `}
end
end
+# Clear the color buffer with `r`, `g`, `b`, `a`
protected fun gl_clear_color(r, g, b, a: Float) `{ glClearColor(r, g, b, a); `}
+
+# Set the viewport
protected fun gl_viewport(x, y, width, height: Int) `{ glViewport(x, y, width, height); `}
-protected fun gl_vertex_attrib_pointer_int(index, length: Int, normalize: Bool, stride: Int, vertex: Array[Int]) import Array[Int].length, Array[Int].intern_items `{
- int* c_vertex = Array_of_Int_intern_items(vertex);
- glVertexAttribPointer(index, length, GL_INT, normalize, stride, c_vertex);
-`}
-protected fun gl_vertex_attrib_pointer_float(index, length: Int, normalize: Bool, stride: Int, vertex: Array[Float]) import Array[Float].length, Array[Float].intern_items `{
- int* c_vertex = Array_of_Float_intern_items(vertex);
- glVertexAttribPointer(index, length, GL_FLOAT, normalize, stride, c_vertex);
-`}
# Direct call to `glClear`, call with a combinaison of `gl_clear_color_buffer`,
# `gl_stencil_buffer_bit` and `gl_color_buffer_bit`.
private fun gl_clear(flag: Int) `{ glClear(flag); `}
-protected fun gl_depth_buffer_bit: Int do return once "0100".to_hex
-protected fun gl_stencil_buffer_bit: Int do return once "0400".to_hex
-protected fun gl_color_buffer_bit: Int do return once "4000".to_hex
+protected fun gl_depth_buffer_bit: Int do return 0x0100
+protected fun gl_stencil_buffer_bit: Int do return 0x0400
+protected fun gl_color_buffer_bit: Int do return 0x4000
protected fun gl_clear_color_buffer do gl_clear(gl_color_buffer_bit)
protected fun gl_clear_depth_buffer do gl_clear(gl_depth_buffer_bit)
end
end
+# Query the boolean value at `key`
private fun gl_get_bool(key: Int): Bool `{
GLboolean val;
- glGetBooleanv(GL_SHADER_COMPILER, &val);
+ glGetBooleanv(key, &val);
return val == GL_TRUE;
`}
+
+# Query the floating point value at `key`
private fun gl_get_float(key: Int): Float `{
GLfloat val;
glGetFloatv(key, &val);
return val;
`}
+
+# Query the integer value at `key`
private fun gl_get_int(key: Int): Int `{
GLint val;
glGetIntegerv(key, &val);
return val;
`}
-fun gl_shader_compiler: Bool do return gl_get_bool("8DFA".to_hex)
+# Does this driver support shader compilation?
+#
+# Should always return `true` in OpenGL ES 2.0 and 3.0.
+fun gl_shader_compiler: Bool do return gl_get_bool(0x8DFA)
+
+# Float related data types of OpenGL ES 2.0 shaders
+#
+# Only data types supported by shader attributes, as seen with
+# `GLProgram::active_attrib_type`.
+extern class GLFloatDataType `{ GLenum `}
+ fun is_float: Bool `{ return recv == GL_FLOAT; `}
+ fun is_float_vec2: Bool `{ return recv == GL_FLOAT_VEC2; `}
+ fun is_float_vec3: Bool `{ return recv == GL_FLOAT_VEC3; `}
+ fun is_float_vec4: Bool `{ return recv == GL_FLOAT_VEC4; `}
+ fun is_float_mat2: Bool `{ return recv == GL_FLOAT_MAT2; `}
+ fun is_float_mat3: Bool `{ return recv == GL_FLOAT_MAT3; `}
+ fun is_float_mat4: Bool `{ return recv == GL_FLOAT_MAT4; `}
+end
+
+# All data types of OpenGL ES 2.0 shaders
+#
+# These types can be used by shader uniforms, as seen with
+# `GLProgram::active_uniform_type`.
+extern class GLDataType
+ super GLFloatDataType
+
+ fun is_int: Bool `{ return recv == GL_INT; `}
+ fun is_int_vec2: Bool `{ return recv == GL_INT_VEC2; `}
+ fun is_int_vec3: Bool `{ return recv == GL_INT_VEC3; `}
+ fun is_int_vec4: Bool `{ return recv == GL_INT_VEC4; `}
+ fun is_bool: Bool `{ return recv == GL_BOOL; `}
+ fun is_bool_vec2: Bool `{ return recv == GL_BOOL_VEC2; `}
+ fun is_bool_vec3: Bool `{ return recv == GL_BOOL_VEC3; `}
+ fun is_bool_vec4: Bool `{ return recv == GL_BOOL_VEC4; `}
+ fun is_sampler_2d: Bool `{ return recv == GL_SAMPLER_2D; `}
+ fun is_sampler_cube: Bool `{ return recv == GL_SAMPLER_CUBE; `}
+end
# GPIO related functionnalities
module gpio
+# A physical binary pin
interface Pin
+ # Set the output of this pin
fun write(high: Bool) is abstract
end
# Count and update length of collisions for `node_at_idx`
# Note for dynamic call-graph analysis: callers of this functions are
# responsible of collisions.
- private fun gt_collide(i: Int, k: K)
+ fun gt_collide(i: Int, k: K)
do
var c = _array[i]
sys.gt_coll += 1
# Count and update length of collisions for `store`
# Note for dynamic call-graph analysis: callers of this functions are
# responsible of collisions.
- private fun st_collide(i: Int, n: N)
+ fun st_collide(i: Int, n: N)
do
var c = _array[i]
sys.st_coll += 1
# Set a 'value' for 'key'
# var img = new HTMLTag("img")
# img.attr("src", "./image.png").attr("alt", "image")
- # assert img.write_to_string == """<img src="./image.png" alt="image"/>"""
+ # assert img.write_to_string == """<img src="./image.png" alt="image"/>"""
fun attr(key: String, value: String): HTMLTag do
attrs[key] = value
return self
extern class NativeFile in "Java" `{ java.io.File `}
super JavaObject
- redef type SELF: NativeFile
fun can_execute: Bool in "Java" `{ return recv.canExecute(); `}
fun can_read: Bool in "Java" `{ return recv.canRead(); `}
extern class NativeFileInputStream in "Java" `{ java.io.FileInputStream `}
super JavaObject
- redef type SELF: NativeFileInputStream
fun available: Int in "Java" `{
try {
extern class NativeFileOutputStream in "Java" `{ java.io.FileOutputStream `}
super JavaObject
- redef type SELF: NativeFileOutputStream
fun close in "Java" `{
try {
extern class NativeFileDescriptor in "Java" `{ java.io.FileDescriptor `}
super JavaObject
- redef type SELF: NativeFileDescriptor
+
fun sync in "Java" `{
try{
recv.sync();
extern class NativeInputStream in "Java" `{ java.io.InputStream `}
super JavaObject
- redef type SELF: NativeInputStream
fun available: Int in "Java" `{
try {
extern class JavaString in "Java" `{ java.lang.String `}
super JavaObject
- redef type SELF: JavaString
-
# Get the string from Java and copy it to Nit memory
fun to_cstring: NativeString import sys, Sys.jni_env `{
Sys sys = JavaString_sys(recv);
end
redef extern class JavaObject
- type SELF: JavaObject
# Returns a global reference to the Java object behind this reference
#
# See the License for the specific language governing permissions and
# limitations under the License.
-# Dynamic interface to read Json strings.
+# Dynamic interface to read JSON strings.
#
# `String::to_json_value` returns a `JsonValue` which can be queried
-# to get the underlying Json data. It can also be used as any Json types.
+# to get the underlying JSON data.
module dynamic
import error
private import static
+# Wraps a JSON value.
+#
+# Offer methods to query the type, to dynamicaly cast the underlying value and
+# to query elements (in case of a JSON object or a JSON array).
+#
+# Use `String::to_json_value` to get a `JsonValue` from a string.
class JsonValue
+
+ # The wrapped JSON value.
var value: nullable Object
# Is this value null?
#
# require: `self.is_numeric`
#
- # assert "1.234".to_json_value.to_numeric = 1.234
- # assert "1234".to_json_value.to_numeric = 1234
+ # assert "1.234".to_json_value.to_numeric == 1.234
+ # assert "1234".to_json_value.to_numeric == 1234
fun to_numeric: Numeric
do
if is_int then return to_i
# Redef parser
redef class Nvalue
- fun to_nit_object: nullable Jsonable is abstract
+ # The represented value.
+ private fun to_nit_object: nullable Jsonable is abstract
end
redef class Nvalue_number
end
redef class Nstring
- fun to_nit_string: String do
+ # The represented string.
+ private fun to_nit_string: String do
var res = new FlatBuffer
var i = 1
while i < text.length - 1 do
end
redef class Nmembers
- fun pairs: Array[Npair] is abstract
+ # All the key-value pairs.
+ private fun pairs: Array[Npair] is abstract
end
redef class Nmembers_tail
end
redef class Npair
- fun name: String do return n_string.to_nit_string
- fun value: nullable Jsonable do return n_value.to_nit_object
+ # The represented key.
+ private fun name: String do return n_string.to_nit_string
+
+ # The represented value.
+ private fun value: nullable Jsonable do return n_value.to_nit_object
end
redef class Nvalue_array
end
redef class Nelements
- fun items: Array[Nvalue] is abstract
+ # All the items.
+ private fun items: Array[Nvalue] is abstract
end
redef class Nelements_tail
# See the License for the specific language governing permissions and
# limitations under the License.
+# Handles serialization and deserialization of objects to/from Json.
module json_serialization
import serialization
import json::static
+# Serializer of Nit objects to Json string.
class JsonSerializer
super Serializer
# Target writing stream
var stream: OStream
- init(stream: OStream) do self.stream = stream
-
redef fun serialize(object)
do
if object == null then
end
end
- # Map of references to already serialized objects
+ # Map of references to already serialized objects.
var refs_map = new HashMap[Serializable,Int]
+ # Get the internal serialized reference for this `object`.
private fun ref_id_for(object: Serializable): Int
do
if refs_map.keys.has(object) then
end
end
-# Deserializer from a Json string
+# Deserializer from a Json string.
class JsonDeserializer
super Deserializer
- var root: nullable Jsonable
+ # Json text to deserialize from.
+ private var text: Text
+
+ # Root json object parsed from input text.
+ var root: nullable Jsonable is noinit
+
+ # Depth-first path in the serialized object tree.
var path = new Array[JsonObject]
+
+ # Map of refenrences to already deserialized objects.
var id_to_object = new HashMap[Int, Object]
+ # Last encountered object reference id.
+ #
+ # See `id_to_object`.
var just_opened_id: nullable Int = null
- init(text: Text)
- do
+ init do
var root = text.parse_json
if root isa JsonObject then path.add(root)
self.root = root
end
end
+ # Instanciate a new `Array` from its serialized representation.
init from_deserializer(v: Deserializer)
do
if v isa JsonDeserializer then
# Utility to select options to create the VM using `create_jvm`
#
# Usage example:
-# ~~~~
+#
+# ~~~~nitish
# var builder = new JavaVMBuilder
# builder.options.add "-Djava.class.path=."
# var jvm = builder.create_jvm
# Create a new event_base to use with the rest of Libevent
new `{ return event_base_new(); `}
+
+ # Has `self` been correctly initialized?
fun is_valid: Bool do return not address_is_null
- #fun creation_ok
# Event dispatching loop
#
# Write a string to the connection
fun write(str: String)
do
- var res = native_buffer_event.write(str.to_cstring, str.length)
+ native_buffer_event.write(str.to_cstring, str.length)
end
# Write a file to the connection
# A buffer event structure, strongly associated to a connection, an input buffer and an output_buffer
extern class NativeBufferEvent `{ struct bufferevent * `}
+ # Write `length` bytes of `line`
fun write(line: NativeString, length: Int): Int `{
return bufferevent_write(recv, line, length);
`}
fun length: Int `{ return evbuffer_get_length(recv); `}
end
+# An input buffer
extern class InputNativeEvBuffer
super NativeEvBuffer
fun drain(length: Int) `{ evbuffer_drain(recv, length); `}
end
+# An output buffer
extern class OutputNativeEvBuffer
super NativeEvBuffer
# Factory to listen on sockets and create new `Connection`
class ConnectionFactory
+ # The `NativeEventBase` for the dispatch loop of this factory
var event_base: NativeEventBase
# On new connection, create the handler `Connection` object
# `MarkdownEmitter` used for ouput.
var emitter: MarkdownEmitter is noinit
+ # Work in extended mode (default).
+ #
+ # Behavior changes when using extended mode:
+ #
+ # * Lists and code blocks end a paragraph
+ #
+ # In normal markdown the following:
+ #
+ # This is a paragraph
+ # * and this is not a list
+ #
+ # Will produce:
+ #
+ # <p>This is a paragraph
+ # * and this is not a list</p>
+ #
+ # When using extended mode this changes to:
+ #
+ # <p>This is a paragraph</p>
+ # <ul>
+ # <li>and this is not a list</li>
+ # </ul>
+ #
+ # * Fences code blocks
+ #
+ # If you don't want to indent your all your code with 4 spaces,
+ # you can wrap your code in ``` ``` ``` or `~~~`.
+ #
+ # Here's an example:
+ #
+ # ```
+ # fun test do
+ # print "Hello World!"
+ # end
+ # ```
+ #
+ # * Code blocks meta
+ #
+ # If you want to use syntax highlighting tools, most of them need to know what kind
+ # of language they are highlighting.
+ # You can add an optional language identifier after the fence declaration to output
+ # it in the HTML render.
+ #
+ # ```nit
+ # import markdown
+ #
+ # print "# Hello World!".md_to_html
+ # ```
+ #
+ # Becomes
+ #
+ # <pre class="nit"><code>import markdown
+ #
+ # print "Hello World!".md_to_html
+ # </code></pre>
+ #
+ # * Underscores (Emphasis)
+ #
+ # Underscores in the middle of a word like:
+ #
+ # Con_cat_this
+ #
+ # normally produces this:
+ #
+ # <p>Con<em>cat</em>this</p>
+ #
+ # With extended mode they don't result in emphasis.
+ #
+ # <p>Con_cat_this</p>
+ #
+ # * Strikethrough
+ #
+ # Like in [GFM](https://help.github.com/articles/github-flavored-markdown),
+ # strikethrought span is marked with `~~`.
+ #
+ # ~~Mistaken text.~~
+ #
+ # becomes
+ #
+ # <del>Mistaken text.</del>
+ var ext_mode = true
+
init do self.emitter = new MarkdownEmitter(self)
# Process the mardown `input` string and return the processed output.
if value[leading] == '#' then return new LineHeadline
if value[leading] == '>' then return new LineBlockquote
- if value.length - leading - trailing > 2 then
- if value[leading] == '`' and md.count_chars_start('`') >= 3 then
- return new LineFence
- end
- if value[leading] == '~' and md.count_chars_start('~') >= 3 then
- return new LineFence
+ if ext_mode then
+ if value.length - leading - trailing > 2 then
+ if value[leading] == '`' and md.count_chars_start('`') >= 3 then
+ return new LineFence
+ end
+ if value[leading] == '~' and md.count_chars_start('~') >= 3 then
+ return new LineFence
+ end
end
end
return new TokenEmUnderscore(pos, c)
end
end
+ if ext_mode then
+ if (c0.is_letter or c0.is_digit) and c0 != '_' and
+ (c1.is_letter or c1.is_digit) then
+ return new TokenNone(pos, c)
+ else
+ return new TokenEmUnderscore(pos, c)
+ end
+ end
if c0 != ' ' or c1 != ' ' then
return new TokenEmUnderscore(pos, c)
else
return new TokenHTML(pos, c)
else if c == '&' then
return new TokenEntity(pos, c)
- else if c == '^' then
- if c0 == '^' or c1 == '^' then
- return new TokenNone(pos, c)
- else
- return new TokenSuper(pos, c)
- end
else
+ if ext_mode then
+ if c == '~' and c1 == '~' then
+ return new TokenStrike(pos, c)
+ end
+ end
return new TokenNone(pos, c)
end
end
# A Link Reference.
# Links that are specified somewhere in the mardown document to be reused as shortcuts.
#
-# Example:
-#
-# [1]: http://example.com/ "Optional title"
+# ~~~raw
+# [1]: http://example.com/ "Optional title"
+# ~~~
class LinkRef
# Link href
# Render a strong text.
fun add_strong(v: MarkdownEmitter, text: Text) is abstract
- # Render a super text.
- fun add_super(v: MarkdownEmitter, text: Text) is abstract
+ # Render a strike text.
+ #
+ # Extended mode only (see `MarkdownProcessor::ext_mode`)
+ fun add_strike(v: MarkdownEmitter, text: Text) is abstract
# Render a link.
fun add_link(v: MarkdownEmitter, link: Text, name: Text, comment: nullable Text) is abstract
end
redef fun add_code(v, block) do
- v.add "<pre><code>"
+ if block isa BlockFence and block.meta != null then
+ v.add "<pre class=\"{block.meta.to_s}\"><code>"
+ else
+ v.add "<pre><code>"
+ end
v.emit_in block
v.add "</code></pre>\n"
end
v.add "</strong>"
end
- redef fun add_super(v, text) do
- v.add "<sup>"
+ redef fun add_strike(v, text) do
+ v.add "<del>"
v.add text
- v.add "</sup>"
+ v.add "</del>"
end
redef fun add_image(v, link, name, comment) do
class BlockFence
super BlockCode
+ # Any string found after fence token.
+ var meta: nullable Text
+
# Fence code lines start at 0 spaces.
redef var line_start = 0
end
var was_empty = line.prev_empty
while line != null and not line.is_empty do
var t = v.line_kind(line)
- if v.in_list and t isa LineList then
+ if (v.in_list or v.ext_mode) and t isa LineList then
break
end
- if t isa LineCode or t isa LineFence then
+ if v.ext_mode and (t isa LineCode or t isa LineFence) then
break
end
if t isa LineHeadline or t isa LineHeadline1 or t isa LineHeadline2 or
else
block = v.current_block.split(v.current_block.last_line.as(not null))
end
- block.kind = new BlockFence(block)
+ var meta = block.first_line.value.meta_from_fence
+ block.kind = new BlockFence(block, meta)
block.first_line.clear
var last = block.last_line
if last != null and v.line_kind(last) isa LineFence then
end
end
-# A markdown super token.
-class TokenSuper
+# A markdown strike token.
+#
+# Extended mode only (see `MarkdownProcessor::ext_mode`)
+class TokenStrike
super Token
redef fun emit(v) do
var tmp = v.push_buffer
- var b = v.emit_text_until(v.current_text.as(not null), pos + 1, self)
+ var b = v.emit_text_until(v.current_text.as(not null), pos + 2, self)
v.pop_buffer
if b > 0 then
- v.decorator.add_super(v, tmp)
- v.current_pos = b
+ v.decorator.add_strike(v, tmp)
+ v.current_pos = b + 1
else
v.addc char
end
return pos
end
+ # Extract string found at end of fence opening.
+ private fun meta_from_fence: nullable Text do
+ for i in [0..chars.length[ do
+ var c = chars[i]
+ print c
+ if c != ' ' and c != '`' and c != '~' then
+ return substring_from(i).trim
+ end
+ end
+ return null
+ end
+
# Is `self` an unsafe HTML element?
private fun is_html_unsafe: Bool do return html_unsafe_tags.has(self.write_to_string)
assert res == exp
end
+ fun test_process_list11 do
+ var test = """
+This is a paragraph
+* and this is not a list
+"""
+ var exp = """
+<p>This is a paragraph
+* and this is not a list</p>
+"""
+ var proc = new MarkdownProcessor
+ proc.ext_mode = false
+ var res = proc.process(test).write_to_string
+ assert res == exp
+ end
+
+ fun test_process_list_ext do
+ var test = """
+This is a paragraph
+* and this is not a list
+"""
+ var exp = """
+<p>This is a paragraph</p>
+<ul>
+<li>and this is not a list</li>
+</ul>
+"""
+ var res = test.md_to_html.write_to_string
+ assert res == exp
+ end
+
fun test_process_code1 do
var test = """
This is a normal paragraph:
assert res == exp
end
- fun test_process_code3 do
+ fun test_process_code_ext1 do
var test = """
Here is an example of AppleScript:
~~~
assert res == exp
end
- fun test_process_code4 do
+ fun test_process_code_ext2 do
var test = """
Here is an example of AppleScript:
```
assert res == exp
end
+ fun test_process_code_ext3 do
+ var proc = new MarkdownProcessor
+ proc.ext_mode = false
+
+ var test = """
+Here is an example of AppleScript:
+ beep
+"""
+ var exp = """
+<p>Here is an example of AppleScript:
+beep</p>
+"""
+ var res = proc.process(test).write_to_string
+ assert res == exp
+ end
+
+ fun test_process_code_ext4 do
+ var test = """
+Here is an example of AppleScript:
+ beep
+"""
+ var exp = """
+<p>Here is an example of AppleScript:</p>
+<pre><code>beep
+</code></pre>
+"""
+ var res = test.md_to_html.write_to_string
+ assert res == exp
+ end
+
+ fun test_process_code_ext5 do
+ var test = """
+```nit
+print "Hello World!"
+```
+"""
+ var exp = """
+<pre class="nit"><code>print "Hello World!"
+</code></pre>
+"""
+ var res = test.md_to_html.write_to_string
+ assert res == exp
+ end
fun test_process_nesting1 do
var test = """
assert res == exp
end
+ fun test_process_emph3 do
+ var proc = new MarkdownProcessor
+ proc.ext_mode = false
+ var test = "Con_cat_this"
+ var exp = "<p>Con<em>cat</em>this</p>\n"
+ var res = proc.process(test).write_to_string
+ assert res == exp
+ end
+
+ fun test_process_emph_ext do
+ var test = "Con_cat_this"
+ var exp = "<p>Con_cat_this</p>\n"
+ var res = test.md_to_html.write_to_string
+ assert res == exp
+ end
+
fun test_process_xml1 do
var test = """
This is a regular paragraph.
assert res == exp
end
+ fun test_process_strike do
+ var proc = new MarkdownProcessor
+ proc.ext_mode = false
+ var test = "This is how you ~~strike text~~"
+ var exp = "<p>This is how you ~~strike text~~</p>\n"
+ var res = proc.process(test).write_to_string
+ assert exp == res
+ end
+
+ fun test_process_strike_ext do
+ var test = "This is how you ~~strike text~~"
+ var exp = "<p>This is how you <del>strike text</del></p>\n"
+ var res = test.md_to_html.write_to_string
+ assert exp == res
+ end
+
+
fun test_daring_encoding do
var test = """
AT&T has an ampersand in their name.
end
fun test_daring_pars do
+ var proc = new MarkdownProcessor
+ proc.ext_mode = false
+
var test = """
In Markdown 1.0.0 and earlier. Version
8. This line turns into a list item.
<p>Here's one with a bullet.
* criminey.</p>
"""
- var res = test.md_to_html.write_to_string
+ var res = proc.process(test).write_to_string
assert res == exp
end
assert v.line_kind(subject) isa LineHeadline
subject = new MDLine(" code")
assert v.line_kind(subject) isa LineCode
- subject = new MDLine(" ~~~")
- assert v.line_kind(subject) isa LineFence
- subject = new MDLine(" ```")
- assert v.line_kind(subject) isa LineFence
subject = new MDLine(" Title ")
subject.next = new MDLine("== ")
assert v.line_kind(subject) isa LineHeadline1
assert v.line_kind(subject) isa LineOList
end
+ fun test_line_type_ext do
+ var v = new MarkdownProcessor
+ subject = new MDLine(" ~~~")
+ assert v.line_kind(subject) isa LineFence
+ subject = new MDLine(" ```")
+ assert v.line_kind(subject) isa LineFence
+ end
+
fun test_count_chars do
subject = new MDLine("")
assert subject.count_chars('*') == 0
#
# The input event file is made of event descriptions, one event by line.
#
-# ~~~
+# ~~~raw
# 10 click 10.0 20.0
# 20 quit
# ~~~
# limitations under the License.
# Impements the services of `mnit:app` using the API from the Android ndk
-module android_app
+module android_app is
+ android_manifest_activity """
+ android:theme="@android:style/Theme.NoTitleBar.Fullscreen"
+ android:configChanges="orientation|keyboardHidden"
+ android:screenOrientation="portrait""""
+end
import mnit
import android
# Draw image by specifying the positon of each image corners
# Corners are in counter-clockwise order stating top left
# a is top left, b is bottom left, c is bottom right and d is top right
- # ~~~
+ # ~~~raw
# a-d
# | |
# b-c
self[key] = res
return res
end
-
- init do end
end
# Simple way to store an `HashMap[K1, HashMap[K2, V]]`
+#
+# ~~~~
+# var hm2 = new HashMap2[Int, String, Float]
+# hm2[1, "one"] = 1.0
+# hm2[2, "two"] = 2.0
+# assert hm2[1, "one"] == 1.0
+# assert hm2[2, "not-two"] == null
+# ~~~~
class HashMap2[K1: Object, K2: Object, V]
- private var level1: HashMap[K1, HashMap[K2, V]] = new HashMap[K1, HashMap[K2, V]]
+ private var level1 = new HashMap[K1, HashMap[K2, V]]
# Return the value associated to the keys `k1` and `k2`.
# Return `null` if no such a value.
end
# Simple way to store an `HashMap[K1, HashMap[K2, HashMap[K3, V]]]`
+#
+# ~~~~
+# var hm3 = new HashMap3[Int, String, Int, Float]
+# hm3[1, "one", 11] = 1.0
+# hm3[2, "two", 22] = 2.0
+# assert hm3[1, "one", 11] == 1.0
+# assert hm3[2, "not-two", 22] == null
+# ~~~~
class HashMap3[K1: Object, K2: Object, K3: Object, V]
- private var level1: HashMap[K1, HashMap2[K2, K3, V]] = new HashMap[K1, HashMap2[K2, K3, V]]
+ private var level1 = new HashMap[K1, HashMap2[K2, K3, V]]
# Return the value associated to the keys `k1`, `k2`, and `k3`.
# Return `null` if no such a value.
end
# A map with a default value.
+#
+# ~~~~
+# var dm = new DefaultMap[String, Int](10)
+# assert dm["a"] == 10
+# ~~~~
+#
+# The default value is used when the key is not present.
+# And getting a default value does not register the key.
+#
+# ~~~~
+# assert dm["a"] == 10
+# assert dm.length == 0
+# assert dm.has_key("a") == false
+# ~~~~
+#
+# It also means that removed key retrieve the default value.
+#
+# ~~~~
+# dm["a"] = 2
+# assert dm["a"] == 2
+# dm.keys.remove("a")
+# assert dm["a"] == 10
+# ~~~~
+#
+# Warning: the default value is used as is, so using mutable object might
+# cause side-effects.
+#
+# ~~~~
+# var dma = new DefaultMap[String, Array[Int]](new Array[Int])
+#
+# dma["a"].add(65)
+# assert dma["a"] == [65]
+# assert dma.default == [65]
+# assert dma["c"] == [65]
+#
+# dma["b"] += [66]
+# assert dma["b"] == [65, 66]
+# assert dma.default == [65]
+# ~~~~
class DefaultMap[K: Object, V]
super HashMap[K, V]
# Connection to a MPD server
class MPDConnection
+
+ # Socket connection to server.
var socket: nullable Socket = null
+ # Server hostname.
var host: String
+
+ # Server port.
var port: Int
+
+ # Server password.
var password: nullable String
+ # Last occured error.
var error: nullable String = null
# Connect to the MPD server
error = "Cannot get volume"
end
+ # Set MPD server volume.
fun volume=(vol: Int) do write_and_check("setvol {vol}\n")
# Pause music playing on the MPD server
end
end
+ # Load playlist named `name`.
fun load_playlist(name: String)
do
write_and_check "load \"{name}\""
# MPD song info
class SongInfo
+ # Song album.
var album: String
+
+ # Song artist.
var artist: String
+
+ # Song title.
var title: String
+
+ # Song total duration.
var time: Int
end
# MPD server status
class ServerStatus
+
+ # MPD server volume.
var volume: nullable Int
+ # Playback state (play/stop/pause).
var state: String
+
+ # Is MPD server playing?
fun playing: Bool do return state == "play"
+
+ # Is MPD server stopped?
fun stopped: Bool do return state == "stop"
+ # Time elapsed within the current song.
var elapsed: nullable Int
+
+ # TODO comment
var time_at: nullable Int
+
+ # Total time of the current song.
var time_total: nullable Int
+
+ # Get the cursor position on the song duration.
fun time_ratio: nullable Float do
if time_at == null or time_total == null then return null
return time_at.to_f / time_total.to_f
# Deserialize message
var deserializer = new JsonDeserializer(buffer)
var deserialized = deserializer.deserialize
-
+
if deserialized == null then print "|{buffer}|{buffer.chars.join("-")}| {buffer.length}"
return deserialized
end
+ # Send an empty buffer, only for the `tag`
fun send_empty(dest: Rank, tag: Tag, comm: Comm): SuccessOrError
`{
return MPI_Send(NULL, 0, MPI_CHAR, dest, tag, comm);
`}
+ # Receive an empty buffer, only for the `tag`
fun recv_empty(dest: Rank, tag: Tag, comm: Comm): SuccessOrError
`{
return MPI_Recv(NULL, 0, MPI_CHAR, dest, tag, comm, MPI_STATUS_IGNORE);
`}
- fun native_send(data: NativeCArray, count: Int, data_type: DataType, dest: Rank, tag: Tag, comm: Comm): SuccessOrError
+ # Send a `NativeCArray` `buffer` with a given `count` of `data_type`
+ fun native_send(buffer: NativeCArray, count: Int, data_type: DataType, dest: Rank, tag: Tag, comm: Comm): SuccessOrError
`{
- return MPI_Send(data, count, data_type, dest, tag, comm);
+ return MPI_Send(buffer, count, data_type, dest, tag, comm);
`}
- fun native_recv(data: NativeCArray, count: Int, data_type: DataType, dest: Rank, tag: Tag, comm: Comm, status: Status): SuccessOrError
+ # Receive into a `NativeCArray` `buffer` with a given `count` of `data_type`
+ fun native_recv(buffer: NativeCArray, count: Int, data_type: DataType, dest: Rank, tag: Tag, comm: Comm, status: Status): SuccessOrError
`{
- return MPI_Recv(data, count, data_type, dest, tag, comm, status);
+ return MPI_Recv(buffer, count, data_type, dest, tag, comm, status);
`}
+ # Probe for the next data to receive, store the result in `status`
+ #
+ # Note: If you encounter an error where the next receive does not correspond
+ # to the last `probe`, call this method twice to ensure a correct result.
fun probe(source: Rank, tag: Tag, comm: Comm, status: Status): SuccessOrError
`{
return MPI_Probe(source, tag, comm, status);
# An MPI communicator
extern class Comm `{ MPI_Comm `}
+ # The _null_ communicator, targeting no processors
new null_ `{ return MPI_COMM_NULL; `}
+
+ # The _world_ communicator, targeting all processors
new world `{ return MPI_COMM_WORLD; `}
+
+ # The _self_ communicator, targeting this processor only
new self_ `{ return MPI_COMM_SELF; `}
# Number of processors in this communicator
# An MPI data type
extern class DataType `{ MPI_Datatype `}
+ # Get a MPI char.
new char `{ return MPI_CHAR; `}
+
+ # Get a MPI short.
new short `{ return MPI_SHORT; `}
+
+ # Get a MPI int.
new int `{ return MPI_INT; `}
+
+ # Get a MPI long.
new long `{ return MPI_LONG; `}
+
+ # Get a MPI long long.
new long_long `{ return MPI_LONG_LONG; `}
+
+ # Get a MPI unsigned char.
new unsigned_char `{ return MPI_UNSIGNED_CHAR; `}
+
+ # Get a MPI unsigned short.
new unsigned_short `{ return MPI_UNSIGNED_SHORT; `}
+
+ # Get a MPI unsigned int.
new unsigned `{ return MPI_UNSIGNED; `}
+
+ # Get a MPI unsigned long.
new unsigned_long `{ return MPI_UNSIGNED_LONG; `}
+
+ # Get a MPI unsigned long long.
new unsigned_long_long `{ return MPI_UNSIGNED_LONG_LONG; `}
+
+ # Get a MPI float.
new float `{ return MPI_FLOAT; `}
+
+ # Get a MPI double.
new double `{ return MPI_DOUBLE; `}
+
+ # Get a MPI long double.
new long_double `{ return MPI_LONG_DOUBLE; `}
+
+ # Get a MPI byte.
new byte `{ return MPI_BYTE; `}
end
# An MPI operation
#
-# Used with the `reduce` method
+# Used with the `reduce` method.
+#
+# See <http://www.mpi-forum.org/docs/mpi-1.1/mpi-11-html/node78.html>
extern class Op `{ MPI_Op `}
+ # Get a MPI null operation.
new op_null `{ return MPI_OP_NULL; `}
+
+ # Get a MPI maximum operation.
new max `{ return MPI_MAX; `}
+
+ # Get a MPI minimum operation.
new min `{ return MPI_MIN; `}
+
+ # Get a MPI sum operation.
new sum `{ return MPI_SUM; `}
+
+ # Get a MPI product operation.
new prod `{ return MPI_PROD; `}
+
+ # Get a MPI logical and operation.
new land `{ return MPI_LAND; `}
+
+ # Get a MPI bit-wise and operation.
new band `{ return MPI_BAND; `}
+
+ # Get a MPI logical or operation.
new lor `{ return MPI_LOR; `}
+
+ # Get a MPI bit-wise or operation.
new bor `{ return MPI_BOR; `}
+
+ # Get a MPI logical xor operation.
new lxor `{ return MPI_LXOR; `}
+
+ # Get a MPI bit-wise xor operation.
new bxor `{ return MPI_BXOR; `}
+
+ # Get a MPI minloc operation.
+ #
+ # Used to compute a global minimum and also an index attached
+ # to the minimum value.
+ #
+ # See <http://www.mpi-forum.org/docs/mpi-1.1/mpi-11-html/node79.html#Node79>
new minloc `{ return MPI_MINLOC; `}
+
+ # Get a MPI maxloc operation.
+ #
+ # Used to compute a global maximum and also an index attached
+ # to the maximum value.
+ #
+ # See <http://www.mpi-forum.org/docs/mpi-1.1/mpi-11-html/node79.html#Node79>
new maxloc `{ return MPI_MAXLOC; `}
+
+ # Get a MPI replace operation.
new replace `{ return MPI_REPLACE; `}
end
# An MPI rank within a communcator
extern class Rank `{ int `}
+ # Special rank accepting any processor
new any `{ return MPI_ANY_SOURCE; `}
# This Rank as an `Int`
# An MPI tag, can be defined using `Int::tag`
extern class Tag `{ int `}
+ # Special tag accepting any tag
new any `{ return MPI_ANY_TAG; `}
# This tag as an `Int`
--- /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.
+
+# Introduce base classes and services for JSON handling.
+module jsonable
+
+import standard
+private import json::json_parser
+private import json::json_lexer
+
+# Something that can be translated to JSON
+interface Jsonable
+ # Get the JSON representation of `self`
+ fun to_json: String is abstract
+end
+
+redef class String
+ super Jsonable
+
+ redef fun to_json do
+ var res = new FlatBuffer
+ res.add '\"'
+ for i in [0..self.length[ do
+ var char = self[i]
+ if char == '\\' then
+ res.append("\\\\")
+ continue
+ else if char == '\"' then
+ res.append("\\\"")
+ continue
+ else if char == '\/' then
+ res.append("\\/")
+ continue
+ else if char == '\n' then
+ res.append("\\n")
+ continue
+ else if char == '\r' then
+ res.append("\\r")
+ continue
+ else if char == '\t' then
+ res.append("\\t")
+ continue
+ end
+ res.add char
+ end
+ res.add '\"'
+ return res.write_to_string
+ end
+end
+
+redef class Int
+ super Jsonable
+
+ redef fun to_json do return self.to_s
+end
+
+redef class Float
+ super Jsonable
+
+ redef fun to_json do return self.to_s
+end
+
+redef class Bool
+ super Jsonable
+
+ redef fun to_json do return self.to_s
+end
+
+# A JSON Object representation that behaves like a `Map`
+class JsonObject
+ super Jsonable
+ super Map[String, nullable Jsonable]
+
+ private var map = new HashMap[String, nullable Jsonable]
+
+ # Create an empty `JsonObject`
+ #
+ # var obj = new JsonObject
+ # assert obj.is_empty
+ init do end
+
+ # Init the JSON Object from a Nit `Map`
+ #
+ # var map = new HashMap[String, String]
+ # map["foo"] = "bar"
+ # map["goo"] = "baz"
+ # var obj = new JsonObject.from(map)
+ # assert obj.length == 2
+ # assert obj["foo"] == "bar"
+ # assert obj["goo"] == "baz"
+ init from(items: Map[String, nullable Jsonable]) do
+ for k, v in items do map[k] = v
+ end
+
+ redef fun [](key) do return map[key]
+ redef fun []=(key, value) do map[key] = value
+ redef fun clear do map.clear
+ redef fun has_key(key) do return map.has_key(key)
+ redef fun is_empty do return map.is_empty
+ redef fun iterator do return map.iterator
+ redef fun keys do return map.keys
+ redef fun values do return map.values
+ redef fun length do return map.length
+
+ # Advanced query to get a value within `self` or its children.
+ #
+ # A query is composed of the keys to each object seperated by '.'.
+ #
+ # REQUIRE `self.has_key(query)`
+ #
+ # var obj1 = new JsonObject
+ # obj1["baz"] = "foobarbaz"
+ # var obj2 = new JsonObject
+ # obj2["bar"] = obj1
+ # var obj3 = new JsonObject
+ # obj3["foo"] = obj2
+ # assert obj3.get("foo.bar.baz") == "foobarbaz"
+ fun get(query: String): nullable Jsonable do
+ var keys = query.split(".").reversed
+ var key = keys.pop
+
+ assert has_key(key)
+ var node = self[key]
+
+ while not keys.is_empty do
+ key = keys.pop
+ assert node isa JsonObject and node.has_key(key)
+ node = node[key]
+ end
+ return node
+ end
+
+ # Create an empty `JsonObject`
+ #
+ # var obj = new JsonObject
+ # obj["foo"] = "bar"
+ # assert obj.to_json == "\{\"foo\": \"bar\"\}"
+ redef fun to_json do
+ var tpl = new Array[String]
+ tpl.add "\{"
+ var vals = new Array[String]
+ for k, v in self do
+ if v == null then
+ vals.add "{k.to_json}: null"
+ else
+ vals.add "{k.to_json}: {v.to_json}"
+ end
+ end
+ tpl.add vals.join(",")
+ tpl.add "\}"
+ return tpl.join("")
+ end
+
+ redef fun to_s do return to_json
+end
+
+# A JSON Array representation that behaves like a `Sequence`
+class JsonArray
+ super Jsonable
+ super Sequence[nullable Jsonable]
+
+ private var array = new Array[nullable Jsonable]
+
+ init do end
+
+ # init the JSON Array from a Nit `Collection`
+ init from(items: Collection[nullable Jsonable]) do
+ array.add_all(items)
+ end
+
+ redef fun [](key) do return array[key]
+ redef fun []=(key, value) do array[key] = value
+ redef fun clear do array.clear
+ redef fun insert(item, index) do array.insert(item, index)
+ redef fun is_empty do return array.is_empty
+ redef fun iterator do return array.iterator
+ redef fun length do return array.length
+ redef fun pop do return array.pop
+ redef fun push(value) do array.push(value)
+ redef fun remove_at(index) do array.remove_at(index)
+ redef fun shift do return array.shift
+ redef fun unshift(e) do array.unshift(e)
+
+ redef fun to_json do
+ var tpl = new Array[String]
+ tpl.add "["
+ var vals = new Array[String]
+ for v in self do
+ if v == null then
+ vals.add "null"
+ else
+ vals.add v.to_json
+ end
+ end
+ tpl.add vals.join(",")
+ tpl.add "]"
+ return tpl.join("")
+ end
+
+ redef fun to_s do return to_json
+end
+
+# An error in JSON format that can be returned by tools using JSON like parsers.
+#
+# var error = new JsonError("ErrorCode", "ErrorMessage")
+# assert error.to_s == "ErrorCode: ErrorMessage"
+# assert error.to_json == "\{\"error\": \"ErrorCode\", \"message\": \"ErrorMessage\"\}"
+class JsonError
+ super Jsonable
+
+ # The error code
+ var error: String
+
+ # The error message
+ var message: String
+
+ redef fun to_json do
+ var tpl = new Array[String]
+ tpl.add "\{"
+ tpl.add "\"error\": {error.to_json}, "
+ tpl.add "\"message\": {message.to_json}"
+ tpl.add "\}"
+ return tpl.join("")
+ end
+
+ redef fun to_s do return "{error}: {message}"
+end
+
+# Redef parser
+
+redef class Nvalue
+ private fun to_nit_object: nullable Jsonable is abstract
+end
+
+redef class Nvalue_number
+ redef fun to_nit_object
+ do
+ var text = n_number.text
+ if text.chars.has('.') or text.chars.has('e') or text.chars.has('E') then return text.to_f
+ return text.to_i
+ end
+end
+
+redef class Nvalue_string
+ redef fun to_nit_object do return n_string.to_nit_string
+end
+
+redef class Nvalue_true
+ redef fun to_nit_object do return true
+end
+
+redef class Nvalue_false
+ redef fun to_nit_object do return false
+end
+
+redef class Nvalue_null
+ redef fun to_nit_object do return null
+end
+
+redef class Nstring
+ # FIXME support \n, etc.
+ fun to_nit_string: String do
+ var res = new FlatBuffer
+ var skip = false
+ for i in [1..text.length-2] do
+ if skip then
+ skip = false
+ continue
+ end
+ var char = text[i]
+ if char == '\\' and i < text.length - 2 then
+ if text[i + 1] == '\\' then
+ res.add('\\')
+ skip = true
+ continue
+ end
+ if text[i + 1] == '\"' then
+ res.add('\"')
+ skip = true
+ continue
+ end
+ if text[i + 1] == '/' then
+ res.add('\/')
+ skip = true
+ continue
+ end
+ if text[i + 1] == 'n' then
+ res.add('\n')
+ skip = true
+ continue
+ end
+ if text[i + 1] == 'r' then
+ res.add('\r')
+ skip = true
+ continue
+ end
+ if text[i + 1] == 't' then
+ res.add('\t')
+ skip = true
+ continue
+ end
+ end
+ res.add char
+ end
+ return res.write_to_string
+ end
+end
+
+redef class Nvalue_object
+ redef fun to_nit_object
+ do
+ var obj = new JsonObject
+ var members = n_members
+ if members != null then
+ var pairs = members.pairs
+ for pair in pairs do obj[pair.name] = pair.value
+ end
+ return obj
+ end
+end
+
+redef class Nmembers
+ fun pairs: Array[Npair] is abstract
+end
+
+redef class Nmembers_tail
+ redef fun pairs
+ do
+ var arr = n_members.pairs
+ arr.add n_pair
+ return arr
+ end
+end
+
+redef class Nmembers_head
+ redef fun pairs do return [n_pair]
+end
+
+redef class Npair
+ fun name: String do return n_string.to_nit_string
+ fun value: nullable Jsonable do return n_value.to_nit_object
+end
+
+redef class Nvalue_array
+ redef fun to_nit_object
+ do
+ var arr = new JsonArray
+ var elements = n_elements
+ if elements != null then
+ var items = elements.items
+ for item in items do arr.add(item.to_nit_object)
+ end
+ return arr
+ end
+end
+
+redef class Nelements
+ fun items: Array[Nvalue] is abstract
+end
+
+redef class Nelements_tail
+ redef fun items
+ do
+ var items = n_elements.items
+ items.add(n_value)
+ return items
+ end
+end
+
+redef class Nelements_head
+ redef fun items do return [n_value]
+end
+
+redef class Text
+ # Parse a JSON String as Jsonable entities
+ #
+ # Example with `JsonObject`"
+ #
+ # var obj = "\{\"foo\": \{\"bar\": true, \"goo\": [1, 2, 3]\}\}".to_jsonable
+ # assert obj isa JsonObject
+ # assert obj["foo"] isa JsonObject
+ # assert obj["foo"].as(JsonObject)["bar"] == true
+ #
+ # Example with `JsonArray`
+ #
+ # var arr = "[1, 2, 3]".to_jsonable
+ # assert arr isa JsonArray
+ # assert arr.length == 3
+ # assert arr.first == 1
+ # assert arr.last == 3
+ #
+ # Example with `String`
+ #
+ # var str = "\"foo, bar, baz\"".to_jsonable
+ # assert str isa String
+ # assert str == "foo, bar, baz"
+ #
+ # Malformed JSON input returns a `JsonError` object
+ #
+ # var bad = "\{foo: \"bar\"\}".to_jsonable
+ # assert bad isa JsonError
+ # assert bad.error == "JsonLexerError"
+ fun to_jsonable: nullable Jsonable
+ do
+ var lexer = new Lexer_json(to_s)
+ var parser = new Parser_json
+ var tokens = lexer.lex
+ parser.tokens.add_all(tokens)
+ var root_node = parser.parse
+ if root_node isa NStart then
+ return root_node.n_0.to_nit_object
+ else if root_node isa NLexerError then
+ var pos = root_node.position
+ var msg = "{root_node.message} at {pos or else "<unknown>"} for {root_node}"
+ return new JsonError("JsonLexerError", msg)
+ else if root_node isa NParserError then
+ var pos = root_node.position
+ var msg = "{root_node.message} at {pos or else "<unknown>"} for {root_node}"
+ return new JsonError("JsonParsingError", msg)
+ else abort
+ end
+end
+
self.cypher_url = root["cypher"].to_s
end
- fun service_root: Jsonable do return get("{base_url}/db/data")
+ fun service_root: Jsonable do return get(base_url / "db/data")
# Is the connection with the Neo4j server ok?
fun is_ok: Bool do return service_root isa JsonObject
# assert nodes.has(andres)
# assert nodes.has(kate)
fun nodes_with_label(lbl: String): Array[NeoNode] do
- var res = get("{base_url}/db/data/label/{lbl}/nodes")
+ var res = get(base_url / "db/data/label/{lbl.to_percent_encoding}/nodes")
var nodes = new Array[NeoNode]
for json in res.as(JsonArray) do
var obj = json.as(JsonObject)
# assert not nodes.has(kate)
fun nodes_with_labels(labels: Array[String]): Array[NeoNode] do
assert not labels.is_empty
- var res = cypher(new CypherQuery.from_string("MATCH (n:{labels.join(":")}) RETURN n"))
+
+ # Build the query.
+ var buffer = new RopeBuffer
+ buffer.append "match n where \{label_0\} in labels(n)"
+ for i in [1..labels.length[ do
+ buffer.append " and \{label_{i}\} in labels(n)"
+ end
+ buffer.append " return n"
+ var query = new CypherQuery.from_string(buffer.write_to_string)
+ for i in [0..labels.length[ do
+ query.params["label_{i}"] = labels[i]
+ end
+
+ # Retrieve the answer.
+ var res = cypher(query)
var nodes = new Array[NeoNode]
for json in res.as(JsonObject)["data"].as(JsonArray) do
var obj = json.as(JsonArray).first.as(JsonObject)
private var internal_properties: nullable JsonObject = null
private fun load_properties: JsonObject do
- var obj = neo.get("{url.to_s}/properties").as(JsonObject)
+ var obj = neo.get(url.to_s / "properties").as(JsonObject)
internal_properties = obj
return obj
end
private fun load_labels: Array[String] do
var labels = new Array[String]
- var res = neo.get("{url.to_s}/labels")
+ var res = neo.get(url.to_s / "labels")
if res isa JsonArray then
for val in res do labels.add val.to_s
end
private fun load_in_edges: List[NeoEdge] do
var edges = new List[NeoEdge]
- var res = neo.get("{url.to_s}/relationships/in").as(JsonArray)
+ var res = neo.get(url.to_s / "relationships/in").as(JsonArray)
for obj in res do
edges.add(new NeoEdge.from_json(neo, obj.as(JsonObject)))
end
private fun load_out_edges: List[NeoEdge] do
var edges = new List[NeoEdge]
- var res = neo.get("{url.to_s}/relationships/out")
+ var res = neo.get(url.to_s / "relationships/out")
for obj in res.as(JsonArray) do
edges.add(new NeoEdge.from_json(neo, obj.as(JsonObject)))
end
fun get_errors: Array[String]
do
- var errors: Array[String] = new Array[String]
+ var errors = new Array[String]
errors.add_all(errors)
for o in options do
for e in o.errors do
#
# Ordered tree are tree where the elements of a same parent are in a specific order
#
-# The class can be used as it to work with generic tree.
-# The class can also be specialized to provide more specific behavior.
+# Elements of the trees are added with the `add` method that takes a parent and
+# a sub-element.
+# If the parent is `null`, then the element is considered a root.
+#
+# ~~~~
+# var t = new OrderedTree[String]
+# t.add(null, "root")
+# t.add("root", "child1")
+# t.add("root", "child2")
+# t.add("child1", "grand-child")
+# assert t.length == 4
+# ~~~~
+#
+# By default, the elements with a same parent
+# are visited in the order they are added.
+#
+# ~~~
+# assert t.to_a == ["root", "child1", "grand-child", "child2"]
+# assert t.write_to_string == """
+# root
+# |--child1
+# | `--grand-child
+# `--child2
+# """
+# ~~~
+#
+# The `sort_with` method can be used reorder elements
+#
+# ~~~
+# t.add("root", "aaa")
+# assert t.to_a == ["root", "child1", "grand-child", "child2", "aaa"]
+# t.sort_with(alpha_comparator)
+# assert t.to_a == ["root", "aaa", "child1", "grand-child", "child2"]
+# ~~~
+#
+# This class can be used as it to work with generic trees but can also be specialized to provide more specific
+# behavior or display. It is why the internal attributes are mutable.
class OrderedTree[E: Object]
super Streamable
super Collection[E]
- # Sequence
+ # The roots of the tree (in sequence)
var roots = new Array[E]
+
+ # The branches of the trees.
+ # For each element, the ordered array of its direct sub-elements.
var sub = new HashMap[E, Array[E]]
- # Add a new element `e` in the tree
+ # Add a new element `e` in the tree.
# `p` is the parent of `e`.
# if `p` is null, then `e` is a root element.
- #
- # By defauld, the elements with a same parent
- # are displayed in the order they are added.
- #
- # The `sort_with` method can be used reorder elements
fun add(p: nullable E, e: E)
do
if p == null then
# Write a ASCII-style tree and use the `display` method to label elements
redef fun write_to(stream: OStream)
do
- var last = roots.last
for r in roots do
stream.write display(r)
stream.write "\n"
# Pipelined filters and operations on iterators.
#
-# This module enhance `Iterator`s with some methods that enable a
-# pipeline-like programing that offers the manupulation of
-# collections trough connected filters with reasonable memory constraints.
+# This module enhances `Iterator` with some methods that enable a pipeline-like programing.
+# The processing of elements in a pipeline is done trough connected filters that are implemented with reasonable memory constraints.
module pipeline
redef interface Iterator[E]
# Filter: sort with a given `comparator`.
# Important: require O(n) memory.
+ #
+ # assert ["a", "c", "b"].iterator.sort_with(alpha_comparator).to_a == ["a", "b", "c"]
fun sort_with(comparator: Comparator): Iterator[E]
do
var a = self.to_a
# 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.
-#
-# Targets the PNaCl platform
+
+# Provides PNaCl support for Nit.
#
# To use this module and compile for PNaCl, you must install the
# NaCl SDK (This file is based on Pepper 33).
# If NACL_SDK_ROOT is not set in your PATH, you have to work in
# 'nacl_sdk/pepper_your_pepper_version/getting_started/your_project_folder'.
-#
-# Provides PNaCl support for Nit.
module pnacl is platform
import standard
# Pre order sets and partial order set (ie hierarchies)
module poset
-# Preorder set graph.
-# This class modelize an incremental preorder graph where new node and edges can be added (but no removal)
-# Preorder graph has two caracteristics:
+# Pre-order set graph.
+# This class models an incremental pre-order graph where new nodes and edges can be added (but not removed).
+# Pre-order graph has two characteristics:
# * reflexivity: an element is in relation with itself (ie `self.has(e) implies self.has_edge(e,e)`)
# * transitivity: `(self.has_edge(e,f) and self.has_edge(f,g)) implies self.has_edge(e,g)`
+#
+# Nodes and edges are added to the POSet.
+#
+# ~~~
+# var pos = new POSet[String]
+# pos.add_edge("A", "B") # add A->B
+# pos.add_edge("B", "C") # add B->C
+# pos.add_node("D") # add unconnected node "D"
+#
+# # A -> B -> C D
+#
+# assert pos.has_edge("A", "B") == true # direct
+# ~~~
+#
+# Since a poset is transitive, direct and indirect edges are considered by default.
+# Direct edges (transitive-reduction) can also be considered independently.
+#
+# ~~~
+# assert pos.has_edge("A", "C") == true # indirect
+# assert pos.has_edge("A", "D") == false # no edge
+# assert pos.has_edge("B", "A") == false # edges are directed
+#
+# assert pos.has_direct_edge("A", "B") == true # direct
+# assert pos.has_direct_edge("A", "C") == false # indirect
+# ~~~
+#
+# POSet are dynamic.
+# It means that the transitivity is updated while new nodes and edges are added.
+# The transitive-reduction (*direct edges*)) is also updated,
+# so adding new edges can make some direct edge to disappear.
+#
+# ~~~
+# pos.add_edge("A","D")
+# pos.add_edge("D","B")
+# pos.add_edge("A","E")
+# pos.add_edge("E","C")
+#
+# # A -> D -> B
+# # | |
+# # v v
+# # E ------> C
+#
+# assert pos.has_edge("D", "C") == true # new indirect edge
+# assert pos.has_edge("A", "B") == true # still an edge
+# assert pos.has_direct_edge("A", "B") == false # but no-more a direct one
+# ~~~
+#
+# Thanks to the `[]` method, elements can be considered relatively to the poset.
+# SEE `POSetElement`
class POSet[E: Object]
super Collection[E]
super Comparator
redef fun iterator do return elements.keys.iterator
# All the nodes
- private var elements: HashMap[E, POSetElement[E]] = new HashMap[E, POSetElement[E]]
+ private var elements = new HashMap[E, POSetElement[E]]
redef fun has(e) do return self.elements.keys.has(e)
end
# Return a view of `e` in the poset.
- # This allows to asks manipulate elements in thier relation with others elements.
+ # This allows to view the elements in their relation with others elements.
#
- # var poset: POSet[Something] # ...
- # for x in poset do
- # for y in poset[x].direct_greaters do
- # print "{x} -> {y}"
- # end
- # end
+ # var poset = new POSet[String]
+ # poset.add_chain(["A", "B", "D"])
+ # poset.add_chain(["A", "C", "D"])
+ # var a = poset["A"]
+ # assert a.direct_greaters.has_exactly(["B", "C"])
+ # assert a.greaters.has_exactly(["A", "B", "C", "D"])
+ # assert a.direct_smallers.is_empty
#
# REQUIRE: has(e)
fun [](e: E): POSetElement[E]
# Add an edge from `f` to `t`.
# Because a POSet is transitive, all transitive edges are also added to the graph.
# If the edge already exists, the this function does nothing.
+ #
+ # ~~~
+ # var pos = new POSet[String]
+ # pos.add_edge("A", "B") # add A->B
+ # assert pos.has_edge("A", "C") == false
+ # pos.add_edge("B", "C") # add B->C
+ # assert pos.has_edge("A", "C") == true
+ # ~~~
+ #
# If a reverse edge (from `t` to `f`) already exists, a loop is created.
#
- # FIXME: Do somethind clever to manage loops.
+ # FIXME: Do something clever to manage loops.
fun add_edge(f, t: E)
do
var fe = add_node(f)
te.dfroms.add f
end
+ # Add an edge between all elements of `es` in order.
+ #
+ # ~~~~
+ # var pos = new POSet[String]
+ # pos.add_chain(["A", "B", "C", "D"])
+ # assert pos.has_direct_edge("A", "B")
+ # assert pos.has_direct_edge("B", "C")
+ # assert pos.has_direct_edge("C", "D")
+ # ~~~~
+ fun add_chain(es: SequenceRead[E])
+ do
+ if es.is_empty then return
+ var i = es.iterator
+ var e = i.item
+ i.next
+ for f in i do
+ add_edge(e, f)
+ e = f
+ end
+ end
+
# Is there an edge (transitive or not) from `f` to `t`?
+ #
+ # SEE: `add_edge`
+ #
# Since the POSet is reflexive, true is returned if `f == t`.
+ #
+ # ~~~
+ # var pos = new POSet[String]
+ # pos.add_node("A")
+ # assert pos.has_edge("A", "A") == true
+ # ~~~
fun has_edge(f,t: E): Bool
do
if not elements.keys.has(f) then return false
end
# Is there a direct edge from `f` to `t`?
+ #
+ # ~~~
+ # var pos = new POSet[String]
+ # pos.add_chain(["A", "B", "C"]) # add A->B->C
+ # assert pos.has_direct_edge("A", "B") == true
+ # assert pos.has_direct_edge("A", "C") == false
+ # assert pos.has_edge("A", "C") == true
+ # ~~~
+ #
# Note that because of loops, the result may not be the expected one.
fun has_direct_edge(f,t: E): Bool
do
# Write the POSet as a graphviz digraph.
#
- # Nodes are identified with their `to_s`.
+ # Nodes are labeled with their `to_s` so homonymous nodes may appear.
# Edges are unlabeled.
fun write_dot(f: OStream)
do
f.write "digraph \{\n"
+ var ids = new HashMap[E, Int]
+ for x in elements.keys do
+ ids[x] = ids.length
+ end
for x in elements.keys do
var xstr = x.to_s.escape_to_dot
- f.write "\"{xstr}\";\n"
+ var nx = "n{ids[x]}"
+ f.write "{nx}[label=\"{xstr}\"];\n"
var xe = self.elements[x]
for y in xe.dtos do
- var ystr = y.to_s.escape_to_dot
+ var ny = "n{ids[y]}"
if self.has_edge(y,x) then
- f.write "\"{xstr}\" -> \"{ystr}\"[dir=both];\n"
+ f.write "{nx} -> {ny}[dir=both];\n"
else
- f.write "\"{xstr}\" -> \"{ystr}\";\n"
+ f.write "{nx} -> {ny};\n"
end
end
end
fun show_dot
do
var f = new OProcess("dot", "-Txlib")
- f.write "\}\n"
write_dot(f)
f.close
f.wait
end
# Compare two elements in an arbitrary total order.
- # Tis function is mainly used to sort elements of the set in an arbitrary linear extension.
- # if a<b then return -1
- # if a>b then return 1
+ #
+ # This function is mainly used to sort elements of the set in an coherent way.
+ #
+ # ~~~~
+ # var pos = new POSet[String]
+ # pos.add_chain(["A", "B", "C", "D", "E"])
+ # pos.add_chain(["A", "X", "C", "Y", "E"])
+ # var a = ["X", "C", "E", "A", "D"]
+ # pos.sort(a)
+ # assert a == ["E", "D", "C", "X", "A"]
+ # ~~~~
+ #
+ # POSet are not necessarily total orders because some distinct elements may be incomparable (neither greater or smaller).
+ # Therefore this method relies on arbitrary linear extension.
+ # This linear extension is a lawful total order (transitive, anti-symmetric, reflexive, and total), so can be used to compare the elements.
+ #
+ # The abstract behavior of the method is thus the following:
+ #
+ # ~~~~nitish
# if a == b then return 0
- # else return -1 or 1
- # The total order is stable unless a new node or a new edge is added
+ # if has_edge(b, a) then return -1
+ # if has_edge(a, b) then return 1
+ # return -1 or 1 # according to the linear extension.
+ # ~~~~
+ #
+ # Note that the linear extension is stable, unless a new node or a new edge is added.
redef fun compare(a, b: E): Int
do
var ae = self.elements[a]
return res
end
+ # Filter elements to return only the greatest ones
+ #
# ~~~
# var s = new POSet[String]
# s.add_edge("B", "A")
# assert s.select_greatest(["A", "B", "C"]) == ["A"]
# assert s.select_greatest(["B", "C", "D"]) == ["B", "C"]
# ~~~
- # Filter elements to return only the greatest ones
fun select_greatest(elements: Collection[E]): Array[E]
do
var res = new Array[E]
end
# Sort a sorted array of poset elements using linearization order
+ # ~~~~
+ # var pos = new POSet[String]
+ # pos.add_chain(["A", "B", "C", "D", "E"])
+ # pos.add_chain(["A", "X", "C", "Y", "E"])
+ # var a = pos.linearize(["X", "C", "E", "A", "D"])
+ # assert a == ["E", "D", "C", "X", "A"]
+ # ~~~~
fun linearize(elements: Collection[E]): Array[E] do
var lin = elements.to_a
sort(lin)
#
# For instance, one common usage is to add a specific attribute for each poset a class belong.
#
-# class Thing
-# var in_some_relation: POSetElement[Thing]
-# var in_other_relation: POSetElement[Thing]
-# end
-# var t: Thing # ...
-# t.in_some_relation.greaters
-#
+# ~~~nitish
+# class Thing
+# var in_some_relation: POSetElement[Thing]
+# var in_other_relation: POSetElement[Thing]
+# end
+# var t: Thing
+# # ...
+# t.in_some_relation.greaters
+# ~~~
class POSetElement[E: Object]
# The poset self belong to
var poset: POSet[E]
# Return the set of all elements `t` that have an edge from `element` to `t`.
# Since the POSet is reflexive, element is included in the set.
+ #
+ # ~~~~
+ # var pos = new POSet[String]
+ # pos.add_chain(["A", "B", "C", "D"])
+ # assert pos["B"].greaters.has_exactly(["B", "C", "D"])
+ # ~~~~
fun greaters: Collection[E]
do
return self.tos
end
# Return the set of all elements `t` that have a direct edge from `element` to `t`.
+ #
+ # ~~~~
+ # var pos = new POSet[String]
+ # pos.add_chain(["A", "B", "C", "D"])
+ # assert pos["B"].direct_greaters.has_exactly(["C"])
+ # ~~~~
fun direct_greaters: Collection[E]
do
return self.dtos
# Return the set of all elements `f` that have an edge from `f` to `element`.
# Since the POSet is reflexive, element is included in the set.
+ #
+ # ~~~~
+ # var pos = new POSet[String]
+ # pos.add_chain(["A", "B", "C", "D"])
+ # assert pos["C"].smallers.has_exactly(["A", "B", "C"])
+ # ~~~~
fun smallers: Collection[E]
do
return self.froms
end
# Return the set of all elements `f` that have an edge from `f` to `element`.
+ #
+ # ~~~~
+ # var pos = new POSet[String]
+ # pos.add_chain(["A", "B", "C", "D"])
+ # assert pos["C"].direct_smallers.has_exactly(["B"])
+ # ~~~~
fun direct_smallers: Collection[E]
do
return self.dfroms
end
# Is there an edge from `element` to `t`?
+ #
+ # ~~~~
+ # var pos = new POSet[String]
+ # pos.add_chain(["A", "B", "C", "D"])
+ # assert pos["B"] <= "D"
+ # assert pos["B"] <= "C"
+ # assert pos["B"] <= "B"
+ # assert not pos["B"] <= "A"
+ # ~~~~
fun <=(t: E): Bool
do
return self.tos.has(t)
end
# Is `t != element` and is there an edge from `element` to `t`?
+ #
+ # ~~~~
+ # var pos = new POSet[String]
+ # pos.add_chain(["A", "B", "C", "D"])
+ # assert pos["B"] < "D"
+ # assert pos["B"] < "C"
+ # assert not pos["B"] < "B"
+ # assert not pos["B"] < "A"
+ # ~~~~
fun <(t: E): Bool
do
return t != self.element and self.tos.has(t)
end
# The length of the shortest path to the root of the poset hierarchy
+ #
+ # ~~~~
+ # var pos = new POSet[String]
+ # pos.add_chain(["A", "B", "C", "D"])
+ # assert pos["A"].depth == 3
+ # assert pos["D"].depth == 0
+ # ~~~~
fun depth: Int do
if direct_greaters.is_empty then
return 0
redef type VALUE: nullable UserGroup
- init for_dropping_privileges do init("Drop privileges to user:group or simply user", "-u", "--usergroup")
- init(help: String, names: String...) do super(help, null, names)
+ # Create an `OptionUserAndGroup` for dropping privileges
+ init for_dropping_privileges
+ do
+ init("Drop privileges to user:group or simply user", null, ["-u", "--usergroup"])
+ end
redef fun convert(str)
do
return new UserGroup(words[0], words[1])
else
errors.add("Option {names.join(", ")} expected parameter in the format \"user:group\" or simply \"user\".\n")
- abort # FIXME only for nitc, remove and replace with next line when FFI is working in nitg
- #return null
+ return null
end
end
end
--- /dev/null
+# This file is part of NIT (http://www.nitlanguage.org).
+#
+# Copyright 2014 Alexis Laferrière <alexis.laf@xymus.net>
+#
+# 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.
+
+# Offers some POSIX threads services that are not available on all platforms
+module extra is
+ c_compiler_option("-pthread")
+ c_linker_option("-pthread")
+end
+
+intrude import pthreads
+
+in "C" `{
+ // TODO protect with: #ifdef WITH_LIBGC
+ #ifndef ANDROID
+ #define GC_THREADS
+ #include <gc.h>
+ #endif
+`}
+
+redef extern class NativePthread
+ fun cancel: Bool `{
+ return pthread_cancel(*recv);
+ `}
+end
+
+redef class Thread
+ # Cancel the execution of the thread
+ fun cancel
+ do
+ if native == null then return
+ native.cancel
+ native = null
+ end
+end
+
+# Does not return if the running thread is to be cancelled
+fun test_cancel `{ pthread_testcancel(); `}
+
+private extern class NativePthreadBarrier in "C" `{ pthread_barrier_t * `}
+ new(count: Int) `{
+ pthread_barrier_t *barrier = malloc(sizeof(pthread_barrier_t));
+ int res = pthread_barrier_init(barrier, NULL, count);
+ return barrier;
+ `}
+
+ fun destroy `{ pthread_barrier_destroy(recv); `}
+
+ fun wait `{ pthread_barrier_wait(recv); `}
+end
module pthreads is
c_compiler_option("-pthread")
c_linker_option("-pthread")
+ pkgconfig "bdw-gc"
end
#
// TODO protect with: #ifdef WITH_LIBGC
// We might have to add the next line to gc_chooser.c too, especially
// if we get an error like "thread not registered with GC".
+ #ifndef ANDROID
#define GC_THREADS
#include <gc.h>
- //#endif
+ #endif
`}
redef class Sys
return (nullable_Object)thread_return;
`}
- fun cancel: Bool `{
- return pthread_cancel(*recv);
- `}
-
- fun attr: NativePthreadAttr `{
- pthread_attr_t *pattr = malloc(sizeof(pthread_attr_t));
- pthread_getattr_np(*recv, pattr);
- return pattr;
- `}
-
- fun equal(other: NativePthread): Bool `{ pthread_equal(*recv, *other); `}
+ fun equal(other: NativePthread): Bool `{ return pthread_equal(*recv, *other); `}
fun kill(signal: Int) `{ pthread_kill(*recv, signal); `}
end
# pthread_mutexattr_setrobust_np
end
-private extern class NativePthreadBarrier in "C" `{ pthread_barrier_t * `}
- new(count: Int) `{
- pthread_barrier_t *barrier = malloc(sizeof(pthread_barrier_t));
- int res = pthread_barrier_init(barrier, NULL, count);
- return barrier;
- `}
-
- fun destroy `{ pthread_barrier_destroy(recv); `}
-
- fun wait `{ pthread_barrier_wait(recv); `}
-end
-
private extern class NativePthreadKey in "C" `{ pthread_key_t * `}
new `{
pthread_key_t *key = malloc(sizeof(pthread_key_t));
`}
end
+private extern class NativePthreadCond in "C" `{ pthread_cond_t * `}
+ new `{
+ pthread_cond_t cond;
+ int r = pthread_cond_init(&cond, NULL);
+ if (r == 0) {
+ pthread_cond_t *pcond = malloc(sizeof(pthread_cond_t));
+ memmove(pcond, &cond, sizeof(pthread_cond_t));
+ return pcond;
+ }
+ return NULL;
+ `}
+
+ fun destroy `{ pthread_cond_destroy(recv); `}
+
+ fun signal `{ pthread_cond_signal(recv); `}
+
+ fun broadcast `{ pthread_cond_broadcast(recv); `}
+
+ fun wait(mutex: NativePthreadMutex) `{ pthread_cond_wait(recv, mutex); `}
+end
+
#
## Nity part
#
return r
end
- # Cancel the execution of the thread
- fun cancel
- do
- if native == null then return
- native.cancel
- native = null
- end
-
redef fun finalize
do
if native == null then return
# Exit current thread and return `value` to caller of `Thread::join`
fun exit_thread(value: nullable Object) `{ pthread_exit(value); `}
-# Does not return if the running thread is to be cancelled
-fun test_cancel `{ pthread_testcancel(); `}
-
# Returns the handle to the running `Thread`
fun thread: Thread
do
class Barrier
super Finalizable
+ private var mutex = new Mutex
+ private var cond: nullable NativePthreadCond = new NativePthreadCond
+
# Number of threads that must be waiting for `wait` to unblock
var count: Int
- private var native: nullable NativePthreadBarrier is noinit
-
- init do native = new NativePthreadBarrier(count)
+ private var threads_waiting = 0
# Wait at this barrier and block until there are a `count` threads waiting
- fun wait do native.wait
+ fun wait
+ do
+ mutex.lock
+ threads_waiting += 1
+ if threads_waiting == count then
+ threads_waiting = 0
+ cond.broadcast
+ else
+ cond.wait(mutex.native.as(not null))
+ end
+ mutex.unlock
+ end
redef fun finalize
do
- var native = self.native
- if native != null then
- native.destroy
- native.free
+ var cond = self.cond
+ if cond != null then
+ cond.destroy
+ cond.free
end
- self.native = null
+ self.cond = null
end
end
class AttributesImpl
super Attributes
- private var data: Array[String] = new Array[String]
+ private var data = new Array[String]
redef var length: Int = 0
redef fun uri(index: Int): nullable String do
# to the `xmlns` prefix.
var nsdecl = "http://www.w3.org/xmlns/2000/"
- private var contexts: Array[Context] = new Array[Context].with_capacity(32)
- private var current_context: Context = new Context
+ private var contexts = new Array[Context].with_capacity(32)
+ private var current_context = new Context
private var context_position: Int = 0
init do
# from [SAX 2.0](http://www.saxproject.org).
private class Context
- private var empty: Collection[String] = new Array[String].with_capacity(0)
+ var empty: Collection[String] = new Array[String].with_capacity(0)
# `prefix` -> `uri`
- private var prefix_table: nullable Map[String, String] = null
+ var prefix_table: nullable Map[String, String] = null
# Cache of `process_name` for elements.
#
# `qname -> [uri, local_name, qname]`
- private var element_name_table: nullable Map[String, Array[String]] = null
+ var element_name_table: nullable Map[String, Array[String]] = null
# Cache of `process_name` for attributes.
#
# `qname -> [uri, local_name, qname]`
- private var attribute_name_table: nullable Map[String, Array[String]] = null
+ var attribute_name_table: nullable Map[String, Array[String]] = null
# Namespace in absence of prefix.
- private var default_ns: nullable String = null
+ var default_ns: nullable String = null
# Can we currently declare prefixes in this context?
var decls_ok: Bool = true is writable
# All prefixes declared in this context.
- private var declarations: nullable Array[String] = null
+ var declarations: nullable Array[String] = null
# Was `copy_tables` called since the last call to `parent=`?
- private var decl_seen: Bool = false
+ var decl_seen: Bool = false
# Parent context.
- private var p_parent: nullable Context = null
-
- init do
- end
+ var p_parent: nullable Context = null
# (Re)set the parent of this Namespace context.
#
#
# This class is optimized for the normal case where most
# elements do not contain Namespace declarations.
- private fun copy_tables do
+ fun copy_tables do
if prefix_table != null then
var old_prefix_table = prefix_table.as(not null)
prefix_table = new HashMap[String, String]
# can use it to make a persistent snapshot of a locator at any
# point during a document parse:
#
-# module example
-# #
-# import sax::helpers::SAXLocatorImpl
-# import sax::ContentHandler
-# #
+# import sax::helpers::sax_locator_impl
+# import sax::content_handler
+#
# class Example super ContentHandler
-# private var _locator: nullable SAXLocator = null
+# private var locator: SAXLocator
# private var start_loc: nullable SAXLocator = null
-# #
-# fun locator=(Locator locator) do
-# # note the locator
-# _locator = locator
-# end
-# #
-# fun start_document do
+#
+# redef fun start_document do
# # save the location of the start of the document
# # for future use.
-# start_loc = new SAXLocatorImpl.from(locator)
+# start_loc = new SAXLocatorImpl.with(locator)
# end
# end
#
end
fun test_prefixes do
- var subject = sample
var res = sample.prefixes
assert 3 == res.length else
end
fun test_declared_prefixes do
- var subject = sample
var res = sample.declared_prefixes
assert 2 == res.length else
# from [SAX 2.0](http://www.saxproject.org).
class InputSource
- init do end
-
# Create a new input source with the specified system identifier.
#
# Applications may use `public_id=` to include a public identifier as well,
# document from a system identifier. It is the exact
# equivalent of the following:
#
- # var source = new InputSouce
- # source.system_id = system_id
- # parse(source)
+ # ~~~nitish
+ # var source = new InputSouce
+ # source.system_id = system_id
+ # parse(source)
+ # ~~~
#
# If the system identifier is a URL, it must be fully resolved
# by the application before it is passed to the parser.
--- /dev/null
+/lexer.nit diff
# They both foward the cursor to the next byte on success, but only `expect`
# functions fire a fatal error on mismatch.
class XophonLexer
+
+ # The model.
var reader_model: XophonReaderModel
+
+ # The input to read from.
var input: IStream is writable
+
+ # Alias to `reader_model.locator`.
private var locator: SAXLocatorImpl is noinit
init do
# “Namespaces in XML”.
private var qname_re: Regex = "^[^:]+(:[^:]+)?$".to_re
+ # The locator that is used to indicate the current location.
var locator: nullable SAXLocatorImpl = null is writable
end
redef fun parse(input: InputSource) do
- var stream: IStream
var system_id: nullable MaybeError[String, Error] = null
model.locator = new SAXLocatorImpl
# Expect a `document` production.
private fun expect_document: Bool do
- var success = true
var got_doctype = false
var got_element = false
expected.end_document
assert_equals
end
+
+ fun test_mixed do
+ var atts = new AttributesImpl
+
+ # TODO For the moment, ignorable white space is not detected.
+ before_test
+ parse_string("<foo> \r\n\n<bar> baz </bar></foo>")
+ expected.document_locator = new SAXLocatorImpl
+ expected.start_document
+ expected.start_element("", "foo", "foo", atts)
+ expected.characters(" \n\n")
+ expected.start_element("", "bar", "bar", atts)
+ expected.characters(" baz ")
+ expected.end_element("", "bar", "bar")
+ expected.end_element("", "foo", "foo")
+ expected.end_document
+ assert_equals
+ end
end
private var del_em: String is noinit
- private var a: SAXEventLogger = new SAXEventLogger
- private var b: SAXEventLogger = new SAXEventLogger
+ private var a = new SAXEventLogger
+ private var b = new SAXEventLogger
private var init_done: Bool = false
# order they fired (the oldest first). Two event loggers have equivalent
# logs if and only if they received the same events in the same order and
# with equivalent arguments.
- private var log: Array[Array[String]] = new Array[Array[String]]
+ private var log = new Array[Array[String]]
# http://xml.org/sax/properties/declaration-handler
private var decl_handler: nullable DeclHandler = null
# in the specified entry.
private fun diff_append_deletion(buf: Buffer, log: Array[Array[String]],
entry_index: Int, sorted_mismatches: Collection[Int]) do
- var sub_buf = new FlatBuffer
-
buf.append(term_deletion)
buf.append("< {entry_index}|")
diff_append_mismatch_entry(buf, log[entry_index], sorted_mismatches,
super TestSuite
# Logger of the expected event sequence.
- var expected: SAXEventLogger = new SAXEventLogger
+ var expected = new SAXEventLogger
# Logger of the actual event sequence.
- var actual: SAXEventLogger = new SAXEventLogger
+ var actual = new SAXEventLogger
# The tested SAX reader.
var reader: XMLReader is noinit
# This method must be implemented for each specific view.
# A traditional way of implementation is to use a double-dispatch mechanism
#
- # Exemple:
# class MyView
+ # super View
# redef fun draw_sprite(s) do s.draw_on_myview(self)
# end
# redef class Sprite
SDL_FillRect(recv, NULL, SDL_MapRGB(recv->format,ri,gi,bi));
`}
+ # SDL events since the last call to this method
fun events: Sequence[SDLInputEvent]
do
- var new_event: nullable Object = null
- var events = new List[SDLInputEvent]
+ var events = new Array[SDLInputEvent]
loop
- new_event = poll_event
- if new_event != null then # new_event isa Event then #
- events.add(new_event)
- else
- break
- end
+ var new_event = poll_event
+ if new_event == null then break
+ events.add new_event
end
return events
end
redef type I: SDLImage
redef fun blit(img, x, y) do native_blit(img, x.to_i, y.to_i)
- fun native_blit(img: I, x, y: Int) `{
+ private fun native_blit(img: I, x, y: Int) `{
SDL_Rect dst;
dst.x = x;
dst.y = y;
redef var pressed: Bool
redef fun depressed: Bool do return not pressed
+ # Is this event raised by the left button?
+ fun is_left_button: Bool do return button == 1
+
+ # Is this event raised by the right button?
+ fun is_right_button: Bool do return button == 2
+
+ # Is this event raised by the middle button?
+ fun is_middle_button: Bool do return button == 3
+
+ # Is this event raised by the wheel going down?
+ fun is_down_wheel: Bool do return button == 4
+
+ # Is this event raised by the wheel going up?
+ fun is_up_wheel: Bool do return button == 5
+
+ # Is this event raised by the wheel?
+ fun is_wheel: Bool do return is_down_wheel or is_up_wheel
+
init (x, y: Float, button: Int, pressed: Bool)
do
super(x, y)
--- /dev/null
+This is a low-level wrapper of the SDL 2.0 library (as `sdl2`) and SDL_image 2.0 (as `sdl2::image`).
+
+The main entry point of this project, `sdl2`, exposes some features of the base
+library: video, events, syswm, etc. The alternative entry point `sdl2::image` offers
+mainly `SDLSurface::load` to load images from PNG, JPG or TIF files.
+
+You can also import `sdl2::all` to get `sdl2` and all its sister libraries, which is only
+`sdl2::image` at this point.
+
+# Examples
+
+See the `minimal` example within this project at `examples/minimal` for a simple example
+of how to use this project.
--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Copyright 2014 Alexis Laferrière <alexis.laf@xymus.net>
+#
+# 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.
+
+# Unites the main `sdl2` module and its sister library `sdl2::image`
+module all
+
+import sdl2
+import image
--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Copyright 2014 Alexis Laferrière <alexis.laf@xymus.net>
+#
+# 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.
+
+# SDL 2 events and related services
+module events is pkgconfig "sdl2"
+
+import sdl2_base
+
+in "C Header" `{
+ #include <SDL2/SDL_events.h>
+`}
+
+# A temporary buffer for a SDL 2 event
+#
+# An instance of this class should be used to call `poll_event` and `to_event`.
+extern class SDLEventBuffer `{SDL_Event *`}
+ # Allocate memory for a new `SDLEventBuffer`
+ new malloc `{ return malloc(sizeof(SDL_Event)); `}
+
+ # Poll and event into `self`
+ #
+ # Returns `true` if an event was available.
+ fun poll_event: Bool `{ return SDL_PollEvent(recv); `}
+
+ # Get a reference to the data at `self` as a precise `SDLEvent`
+ #
+ # Returns `null` if the event is unknown.
+ #
+ # Note: The returned `SDLEvent` is just a different Nit instance pointing to the same data.
+ # A call to `poll_event` will invalidate any instances returned previously by `to_event`.
+ #
+ # TODO remove `nullable` from the return type once all cases are correctly handled.
+ fun to_event: nullable SDLEvent
+ do
+ if is_quit then return to_quit
+ if is_mouse_motion then return to_mouse_motion
+ if is_mouse_button_down then return to_mouse_button_down
+ if is_mouse_button_up then return to_mouse_button_up
+ return null
+ end
+
+ # Is this a quit event?
+ fun is_quit: Bool `{ return recv->type == SDL_QUIT; `}
+
+ # Get a reference to data at `self` as a `SDLQuitEvent`
+ fun to_quit: SDLQuitEvent `{ return recv; `}
+
+ # Is this a mouse motion event?
+ fun is_mouse_motion: Bool `{ return recv->type == SDL_MOUSEMOTION; `}
+
+ # Get a reference to data at `self` as a `SDLMouseMotionEvent`
+ fun to_mouse_motion: SDLMouseMotionEvent `{ return recv; `}
+
+ # Is this a mouse button down event?
+ fun is_mouse_button_down: Bool `{ return recv->type == SDL_MOUSEBUTTONDOWN; `}
+
+ # Get a reference to data at `self` as a `SDLMouseButtonDownEvent`
+ fun to_mouse_button_down: SDLMouseButtonDownEvent `{ return recv; `}
+
+ # Is this a mouse button up event?
+ fun is_mouse_button_up: Bool `{ return recv->type == SDL_MOUSEBUTTONUP; `}
+
+ # Get a reference to data at `self` as a `SDLMouseButtonUpEvent`
+ fun to_mouse_button_up: SDLMouseButtonUpEvent `{ return recv; `}
+
+ # TODO other SDL events:
+ #
+ # SDL_CommonEvent common
+ # SDL_WindowEvent window
+ # SDL_KeyboardEvent key
+ # SDL_TextEditingEvent edit
+ # SDL_TextInputEvent text
+ # SDL_MouseWheelEvent wheel
+ # SDL_JoyAxisEvent jaxis
+ # SDL_JoyBallEvent jball
+ # SDL_JoyHatEvent jhat;
+ # SDL_JoyButtonEvent jbutton
+ # SDL_JoyDeviceEvent jdevice
+ # SDL_ControllerAxisEvent caxis
+ # SDL_ControllerButtonEvent cbutton
+ # SDL_ControllerDeviceEvent cdevice
+ # SDL_QuitEvent quit
+ # SDL_UserEvent user
+ # SDL_SysWMEvent syswm
+ # SDL_TouchFingerEvent tfinger
+ # SDL_MultiGestureEvent mgesture
+ # SDL_DollarGestureEvent dgesture
+ # SDL_DropEvent drop
+end
+
+# An event from SDL 2
+extern class SDLEvent `{SDL_Event *`}
+end
+
+# A quit event, usually from the close window button
+extern class SDLQuitEvent
+ super SDLEvent
+end
+
+# A mouse event
+extern class SDLMouseEvent
+ super SDLEvent
+
+ # Implementation note
+ #
+ # Even if the structures are different between the mouse events, the first
+ # four fields of each events are common to all of them.
+
+ # Which mouse, pointer or finger raised this event
+ fun which: Int `{ return recv->motion.which; `}
+end
+
+# A mouse motion event
+extern class SDLMouseMotionEvent
+ super SDLMouseEvent
+
+ # X coordinate on screen of this event
+ fun x: Int `{ return recv->motion.x; `}
+
+ # Y coordinate on screen of this event
+ fun y: Int `{ return recv->motion.y; `}
+
+ # Difference on the X axis between this event and the previous one
+ fun xrel: Int `{ return recv->motion.xrel; `}
+
+ # Difference on the Y axis between this event and the previous one
+ fun yrel: Int `{ return recv->motion.yrel; `}
+end
+
+# A mouse button event
+#
+# This could as well be an abstract class. All instances of `SDLMouseButtonEvent`
+# is either a `SDLMouseButtonUpEvent` or a `SDLMouseButtonDownEvent`.
+extern class SDLMouseButtonEvent
+ super SDLMouseEvent
+
+ # X coordinate on screen of this event
+ fun x: Int `{ return recv->button.x; `}
+
+ # Y coordinate on screen of this event
+ fun y: Int `{ return recv->button.y; `}
+end
+
+# A mouse button release event
+extern class SDLMouseButtonUpEvent
+ super SDLMouseButtonEvent
+end
+
+# A mouse button click event
+extern class SDLMouseButtonDownEvent
+ super SDLMouseButtonEvent
+end
--- /dev/null
+all:
+ mkdir -p bin/
+ ../../../../bin/nitg -o bin/minimal src/minimal.nit
--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Copyright 2014 Alexis Laferrière <alexis.laf@xymus.net>
+#
+# 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.
+
+# An example to test and demonstrate the `sdl2` lib with `image` and `events`
+module minimal
+
+import sdl2::all
+
+# Check for an error, then print and clear it
+#
+# Some errors are not fatal, so we ignore them at this level.
+fun check_error(loc: String)
+do
+ var error = sys.sdl.error.to_s
+ if not error.is_empty then
+ print "at {loc}: {error}"
+ sys.sdl.clear_error
+ end
+end
+
+# Init `sdl2`, including video and events
+sys.sdl.initialize((new SDLInitFlags).video)
+check_error "init"
+
+# Init `sdl2::image`
+sdl.img.initialize((new SDLImgInitFlags).png)
+check_error "img_init"
+
+# Create a window
+var window = new SDLWindow("Window title!".to_cstring, 800, 600, (new SDLWindowFlags).opengl)
+check_error "window"
+
+# Create a render, the suffested one
+var renderer = new SDLRenderer(window, -1, (new SDLRendererFlags).accelerated)
+check_error "renderer"
+
+# Load an image
+var surface = new SDLSurface.load("assets/fighter.png".to_cstring)
+check_error "surface"
+assert not surface.address_is_null
+
+# Alternative code to load a BMP image without `sdl2::image`
+#
+# var surface = new SDLSurface.load_bmp("assets/fighter.bmp".to_cstring)
+
+# Set the window icon
+window.icon = surface
+check_error "icon"
+
+# Get a texture out of that surface
+var texture = new SDLTexture.from_surface(renderer, surface)
+check_error "texture"
+
+# Allocate memory for reusable objects
+var event = new SDLEventBuffer.malloc
+var src = new SDLRect.nil
+var dst = new SDLRect(0, 0, 128, 128)
+
+# Set the colors we will be using
+var white = new SDLColor(255, 255, 255, 255)
+var green = new SDLColor( 0, 255, 0, 255)
+var spacy = new SDLColor( 25, 25, 50, 255)
+
+loop
+ # Loop over events until we get a quit event
+ while event.poll_event do
+ var higher_event = event.to_event
+ if higher_event isa SDLQuitEvent then
+ break label out
+ else if higher_event isa SDLMouseButtonDownEvent then
+ # Update `dst` to be centered on the latest click
+ dst.x = higher_event.x - dst.w/2
+ dst.y = higher_event.y - dst.h/2
+ end
+ end
+
+ # Clear the screen with a spacy color
+ renderer.draw_color = spacy
+ renderer.clear
+
+ # Draw the target box for the following `copy`
+ renderer.draw_color = green
+ renderer.draw_rect dst
+
+ # Copy a texture to the screen
+ renderer.draw_color = white
+ renderer.copy(texture, src, dst)
+
+ # Copy the back buffer to the screen
+ renderer.present
+
+ check_error "present"
+
+ 33.delay
+end label out
+
+# Free all resources
+event.free
+src.free
+dst.free
+
+texture.free
+surface.free
+
+window.destroy
+sdl.img.quit
+sys.sdl.quit
--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Copyright 2014 Alexis Laferrière <alexis.laf@xymus.net>
+#
+# 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.
+
+# Services of the SDL_image 2.0 library
+#
+# Offers `SDLSurface::load` which supports more image formats than `sdl2::sdl2`
+# alone: JPG, PNG, TIF, GIT, ICO and much more.
+module image is
+ pkgconfig "sdl2"
+ c_linker_option "-lSDL2_image"
+end
+
+import sdl2
+
+in "C" `{
+ #include <SDL2/SDL_image.h>
+`}
+
+redef class SDL
+ # Access to the global methods of `sdl2::image`
+ var img = new IMG is lazy
+end
+
+# Holds the global methods of `sdl2::image`
+class IMG
+ # Get the `IMG` singleton
+ new do return once new IMG.internal
+
+ # TODO make this private and only called through `sys.sdl.img`
+ init internal do end
+
+ # Initialize the image library
+ fun initialize(flags: SDLImgInitFlags): SDLImgInitFlags `{
+ return IMG_Init(flags);
+ `}
+
+ # Finalize and clean up the image library
+ fun quit `{ IMG_Quit(); `}
+
+ # Get the latest image library error
+ fun error: NativeString `{ return (char*)IMG_GetError(); `}
+end
+
+redef extern class SDLSurface
+ # Load the image at `path` inferring its type from the file extension
+ new load(path: NativeString) `{ return IMG_Load(path); `}
+end
+
+# Flags from `sys.sdl.img.initialize`
+extern class SDLImgInitFlags `{ int `}
+ # Get the default empty flag set
+ new `{ return 0; `}
+
+ # Add the JPG support to this flag set
+ fun jpg: SDLImgInitFlags `{ return recv | IMG_INIT_JPG; `}
+
+ # Add the PNG support to this flag set
+ fun png: SDLImgInitFlags `{ return recv | IMG_INIT_PNG; `}
+
+ # Add the TIF support to this flag set
+ fun tif: SDLImgInitFlags `{ return recv | IMG_INIT_TIF; `}
+
+ # Add the WEBP support to this flag set
+ fun webp: SDLImgInitFlags `{ return recv | IMG_INIT_WEBP; `}
+end
--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Copyright 2014 Alexis Laferrière <alexis.laf@xymus.net>
+#
+# 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.
+
+# Simple DirectMedia Layer (SDL) 2.0 services for easy window creation and 2D drawing
+module sdl2
+
+import sdl2_base
+import events
+import syswm
--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Copyright 2014 Alexis Laferrière <alexis.laf@xymus.net>
+#
+# 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.
+
+# Basic SDL 2 features
+module sdl2_base is pkgconfig "sdl2"
+
+in "C header" `{
+ #include <SDL2/SDL.h>
+`}
+
+redef class Sys
+ # Access to the global methods of `sdl2`
+ var sdl = new SDL is lazy
+end
+
+# Holds the global methods of `sdl2`
+class SDL
+ super Finalizable
+
+ # Get the `SDL` singleton
+ new do return once new SDL.internal
+
+ # TODO make this private and only called through `sys.sdl`
+ init internal do end
+
+ # Initialize the given SDL `subsystems`
+ fun initialize(subsystems: SDLInitFlags): Bool `{ return SDL_Init(subsystems); `}
+
+ # Returns the latest SDL error
+ #
+ # After calling this method, you should also call `clear_error`.
+ fun error: NativeString `{ return (char*)SDL_GetError(); `}
+
+ # Clear the SDL error
+ fun clear_error `{ SDL_ClearError(); `}
+
+ # Quit SDL
+ fun quit `{ SDL_Quit(); `}
+
+ # Was SDL initialized?
+ fun was_initialized: Bool do return not initialized_subsystems((new SDLInitFlags).everything).is_empty
+
+ # What SDL subsystems are initialized? You can use a mask of `subsystems` to restrict the query.
+ #
+ # Returns the flags of the initialized subsystems.
+ fun initialized_subsystems(subsystems: SDLInitFlags): SDLInitFlags `{ return SDL_WasInit(subsystems); `}
+
+ # The number of CPU on the system
+ fun cpu_count: Int `{ return SDL_GetCPUCount(); `}
+
+ # Amount of RAM configured on the system
+ fun system_ram: Int `{ return SDL_GetSystemRAM(); `}
+
+ # Show a simple message box
+ fun show_simple_message_box(level: SDLMessageBoxFlags, title, content: NativeString) `{
+ SDL_ShowSimpleMessageBox(level, title, content, NULL);
+ `}
+
+ redef fun finalize do if was_initialized then quit
+
+ # Function that should be called from the SDL main method
+ #
+ # This method should not normally be used, refer to the SDL source code
+ # before use.
+ fun set_main_ready `{ SDL_SetMainReady(); `}
+end
+
+# Flags for `sys.sdl.initialize` and related methods
+extern class SDLInitFlags `{ Uint32 `}
+ # Get the default empty flag set
+ new `{ return 0; `}
+
+ # Add the timer subsystem
+ fun timer: SDLInitFlags `{ return recv | SDL_INIT_TIMER; `}
+
+ # Add the audio subsystem
+ fun audio: SDLInitFlags `{ return recv | SDL_INIT_AUDIO; `}
+
+ # Add the video subsystem
+ fun video: SDLInitFlags `{ return recv | SDL_INIT_VIDEO; `}
+
+ # Add the joystick subsystem
+ #
+ # Implied by `gamecontroller`
+ fun joystick: SDLInitFlags `{ return recv | SDL_INIT_JOYSTICK; `}
+
+ # Add the haptic subsystem
+ fun haptic: SDLInitFlags `{ return recv | SDL_INIT_HAPTIC; `}
+
+ # Add the gamecontroller subsystem
+ fun gamecontroller: SDLInitFlags `{ return recv | SDL_INIT_GAMECONTROLLER; `}
+
+ # Add the events subsystem
+ #
+ # Implied by `video` and `joystick`
+ fun events: SDLInitFlags `{ return recv | SDL_INIT_EVENTS; `}
+
+ # Add all subsystems
+ fun everything: SDLInitFlags `{ return recv | SDL_INIT_EVERYTHING; `}
+
+ # Is this flag set empty?
+ fun is_empty: Bool `{ return recv == 0; `}
+
+ # TODO add all other is_
+end
+
+# A window created by SDL
+extern class SDLWindow `{ SDL_Window * `}
+ # Create a window with the given `title`, `width` and `height`, also apply the `flags`
+ new (title: NativeString, width, height: Int, flags: SDLWindowFlags) `{
+ return SDL_CreateWindow(title,
+ SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
+ width, height, flags);
+ `}
+
+ # Has this window been correctly initialized?
+ fun initialized: Bool do return not address_is_null
+
+ # Destroy this window
+ fun destroy `{ SDL_DestroyWindow(recv); `}
+
+ # Get the `SDLWindowFlags` describing the status of the window
+ fun flags: SDLWindowFlags `{ return SDL_GetWindowFlags(recv); `}
+
+ # Show a simple message box
+ #
+ # Similar to `sys.sdl.show_simple_message_box` but attached to this window
+ fun show_simple_message_box(level: SDLMessageBoxFlags, title, content: NativeString) `{
+ SDL_ShowSimpleMessageBox(level, title, content, recv);
+ `}
+
+ # Set the icon of this window
+ fun icon=(icon: SDLSurface) `{ SDL_SetWindowIcon(recv, icon); `}
+end
+
+# Flags for `SDLWindow::new` and returned by `SDLWindow::flags`
+extern class SDLWindowFlags `{ Uint32 `}
+ # Get the default empty flag set
+ new `{ return 0; `}
+
+ # Add the flag requesting a fullscreen window
+ fun fullscreen: SDLWindowFlags `{ return recv | SDL_WINDOW_FULLSCREEN; `}
+
+ # Add the flag requesting a fullscreen window for the current desktop
+ fun fullscreen_desktop: SDLWindowFlags `{ return recv | SDL_WINDOW_FULLSCREEN_DESKTOP; `}
+
+ # Add the flag requesting a window usable with an OpenGL context
+ fun opengl: SDLWindowFlags `{ return recv | SDL_WINDOW_OPENGL; `}
+
+ # Add the flag requesting a hidden window
+ fun hidden: SDLWindowFlags `{ return recv | SDL_WINDOW_HIDDEN; `}
+
+ # Add the flag requesting a borderless window
+ fun borderless: SDLWindowFlags `{ return recv | SDL_WINDOW_BORDERLESS; `}
+
+ # Add the flag requesting a resizable window
+ fun resizable: SDLWindowFlags `{ return recv | SDL_WINDOW_RESIZABLE; `}
+
+ # Add the flag requesting a minimized window
+ fun minimized: SDLWindowFlags `{ return recv | SDL_WINDOW_MINIMIZED; `}
+
+ # Add the flag requesting a maximimez window
+ fun maximized: SDLWindowFlags `{ return recv | SDL_WINDOW_MAXIMIZED; `}
+
+ # Add the flag to grab the input focus
+ fun input_grabbed: SDLWindowFlags `{ return recv | SDL_WINDOW_INPUT_GRABBED; `}
+
+ # Add the flag to request a window using the system High-DPI mode
+ fun allow_highdpi: SDLWindowFlags `{
+ #if SDL_VERSION_ATLEAST(2, 0, 2)
+ return recv | SDL_WINDOW_ALLOW_HIGHDPI;
+ #else
+ return recv;
+ #endif
+ `}
+
+ # Is the window shown?
+ #
+ # Can only be queried because it is ignored by `SDLWindow::new`
+ fun is_shown: Bool `{ return recv & SDL_WINDOW_SHOWN; `}
+
+ # Does the window has the input focus?
+ #
+ # Can only be queried because it is ignored by `SDLWindow::new`
+ fun has_input_focus: Bool `{ return recv & SDL_WINDOW_INPUT_FOCUS; `}
+
+ # Does the window has the mouse focus?
+ #
+ # Can only be queried because it is ignored by `SDLWindow::new`
+ fun has_mouse_focus: Bool `{ return recv & SDL_WINDOW_MOUSE_FOCUS; `}
+
+ # TODO add all other `is_` methods, as needed
+end
+
+redef universal Int
+ # Suspend execution for `recv` milliseconds
+ fun delay `{ SDL_Delay(recv); `}
+end
+
+# A renderer, maybe software or hardware
+extern class SDLRenderer `{ SDL_Renderer * `}
+ # Create a new `SDLRenderer` for the `window` using the `index`th renderer according to `flags`
+ #
+ # Use an `index` of `-1` to get the default renderer for the given flags.
+ new (window: SDLWindow, index: Int, flags: SDLRendererFlags) `{
+ return SDL_CreateRenderer(window, index, flags);
+ `}
+
+ # Create a new software `SDLRenderer`
+ new software(surface: SDLSurface) `{
+ return SDL_CreateSoftwareRenderer(surface);
+ `}
+
+ # Destroy this renderer
+ fun destroy `{ SDL_DestroyRenderer(recv); `}
+
+ # Clear the rendering target with the current `draw_color`
+ fun clear `{ SDL_RenderClear(recv); `}
+
+ # Copy the rectangle at `src` from `texture` to fill the `dst` at the rendering `target`
+ #
+ # If `dst` has a different size than `src`, the image will be stretched.
+ #
+ # If `src == null` the whole source texture will be drawn, and if
+ # `dst == null` then the texture will fill the rendering `target`.
+ fun copy(texture: SDLTexture, src, dst: nullable SDLRect)
+ do
+ if src == null then src = new SDLRect.nil
+ if dst == null then dst = new SDLRect.nil
+
+ native_copy(texture, src, dst)
+ end
+
+ private fun native_copy(texture: SDLTexture, src, dst: SDLRect) `{
+ SDL_RenderCopy(recv, texture, src, dst);
+ `}
+
+ # Update the screen with all rendering since the previous call
+ fun present `{ SDL_RenderPresent(recv); `}
+
+ # Get the `SDLRendererInfo` for this renderer
+ fun info_copy(out: SDLRendererInfo) `{ SDL_GetRendererInfo(recv, out); `}
+
+ # Set the drawing color
+ fun draw_color=(val: SDLColor) `{
+ SDL_SetRenderDrawColor(recv, val->r, val->g, val->b, val->a);
+ `}
+
+ # Get the drawing color of this renderer
+ #
+ # The returned `SDLColor` is malloced here and must be freed by the called.
+ # For a more efficient usage, it is recommended to use instead `draw_color_copy`.
+ fun draw_color: SDLColor
+ do
+ var color = new SDLColor.malloc
+ draw_color_copy color
+ return color
+ end
+
+ # Copy the drawing color of this renderer in `color`
+ fun draw_color_copy(color: SDLColor) `{
+ SDL_GetRenderDrawColor(recv, &color->r, &color->g, &color->b, &color->a);
+ `}
+
+ # Fill a rectangle with the current `draw_color`
+ #
+ # If `rect.address_is_null` then fills the entire screen.
+ fun fill_rect(rect: SDLRect) `{ SDL_RenderFillRect(recv, rect); `}
+
+ # Draw a rectangle with the current `draw_color`
+ fun draw_rect(rect: SDLRect) `{ SDL_RenderDrawRect(recv, rect); `}
+
+ # Draw a point with the current `draw_color`
+ fun draw_point(x, y: Int) `{ SDL_RenderDrawPoint(recv, x, y); `}
+
+ # Draw a line with the current `draw_color`
+ fun draw_line(x1, y1, x2, y2: Int) `{ SDL_RenderDrawLine(recv, x1, y1, x2, y2); `}
+
+ # Set the viewport of this renderer
+ fun viewport=(rect: SDLRect) `{ SDL_RenderSetViewport(recv, rect); `}
+
+ # Get the rendering target of this renderer
+ fun target: SDLTexture `{ return SDL_GetRenderTarget(recv); `}
+
+ # Set the rendering target of this renderer
+ fun target=(val: SDLTexture) `{ SDL_SetRenderTarget(recv, val); `}
+
+ # TODO add other renderer related methods:
+ #
+ # draw_rects
+ # draw_lines
+end
+
+# A color
+extern class SDLColor `{ SDL_Color *`}
+ # Allocate the memory for a new `SDLColor`, it must then be freed with `free`
+ new malloc `{ return malloc(sizeof(SDL_Color)); `}
+
+ # Allocate the memory for a new `SDLColor` and fill it with `r`, `g`, `b` and `a`
+ #
+ # As with `malloc`, the new instances must then be freed with `free`.
+ new (r, g, b, a: Int)
+ do
+ var color = new SDLColor.malloc
+ color.set(r, g, b, a)
+ return color
+ end
+
+ # Set this instance's `r`, `g`, `b` and `a`
+ fun set(r, g, b, a: Int)
+ do
+ self.r = r
+ self.g = g
+ self.b = b
+ self.a = a
+ end
+
+ # The red component of this color `[0..255]`
+ fun r: Int `{ return recv->r; `}
+
+ # Set the red component of this color `[0..255]`
+ fun r=(val: Int) `{ recv->r = val; `}
+
+ # The green component of this color `[0..255]`
+ fun g: Int `{ return recv->g; `}
+
+ # Set the green component of this color `[0..255]`
+ fun g=(val: Int) `{ recv->g = val; `}
+
+ # The blue component of this color `[0..255]`
+ fun b: Int `{ return recv->b; `}
+
+ # Set the blue component of this color `[0..255]`
+ fun b=(val: Int) `{ recv->b = val; `}
+
+ # The alpha component of this color `[0..255]`
+ fun a: Int `{ return recv->a; `}
+
+ # Set the ralpha component of this color `[0..255]`
+ fun a=(val: Int) `{ recv->a = val; `}
+
+ # TODO implement the related `SDL_Palette` and related methods
+end
+
+# Flags for `SDLRenderer::new`
+extern class SDLRendererFlags `{ Uint32 `}
+ # Get the default empty flag set
+ new `{ return 0; `}
+
+ # Add the flag to request a software renderer
+ fun software: SDLRendererFlags `{ return recv | SDL_RENDERER_SOFTWARE; `}
+
+ # Add the flag to request an accelerated renderer
+ #
+ # This is the default option.
+ fun accelerated: SDLRendererFlags `{ return recv | SDL_RENDERER_ACCELERATED; `}
+
+ # Add the flag to request a renderer where `SDLRenderer::present` is synchronized with the refresh rate
+ fun presentvsync: SDLRendererFlags `{ return recv | SDL_RENDERER_PRESENTVSYNC; `}
+
+ # Add the flag to request a renderer able to render to a texture
+ fun targettexture: SDLRendererFlags `{ return recv | SDL_RENDERER_TARGETTEXTURE; `}
+end
+
+# A bitmap surface
+extern class SDLSurface `{ SDL_Surface * `}
+
+ # Load the BMP file at `path`
+ new load_bmp(path: NativeString) `{ return SDL_LoadBMP(path); `}
+
+ redef fun free `{ SDL_FreeSurface(recv); `}
+
+ # Save this texture to a BMP file
+ fun save_bmp(path: NativeString) `{ SDL_SaveBMP(recv, path); `}
+end
+
+# A loaded bitmap texture
+extern class SDLTexture `{ SDL_Texture * `}
+ # Get a `SDLTexture` from a `surface`, for a given `renderer`
+ new from_surface(renderer: SDLRenderer, surface: SDLSurface) `{
+ return SDL_CreateTextureFromSurface(renderer, surface);
+ `}
+
+ # Destroy this texture
+ fun destroy `{ SDL_DestroyTexture(recv); `}
+
+ # Width of this texture
+ fun width: Int `{
+ int val;
+ SDL_QueryTexture(recv, NULL, NULL, &val, NULL);
+ return val;
+ `}
+
+ # Height of this texture
+ fun height: Int `{
+ int val;
+ SDL_QueryTexture(recv, NULL, NULL, NULL, &val);
+ return val;
+ `}
+
+ # TODO other queries: format and access
+end
+
+# A rectangle
+extern class SDLRect `{SDL_Rect *`}
+ # Get a null rectangle (on the C side), should be used only internally
+ new nil `{ return NULL; `}
+
+ # Allocate the memory for a new `SDLRect`, it must then be freed with `free`
+ new malloc`{ return malloc(sizeof(SDL_Rect)); `}
+
+ # Allocate the memory for a new `SDLRect` and fill it with `x`, `y`, `w` and `h`
+ #
+ # As with `malloc`, the new instances must then be freed with `free`.
+ new (x, y, w, h: Int)
+ do
+ var rect = new SDLRect.malloc
+ rect.set(x, y, w, h)
+ return rect
+ end
+
+ # Set this instance's `x`, `y`, `w` and `h`
+ fun set(x, y, w, h: Int)
+ do
+ self.x = x
+ self.y = y
+ self.w = w
+ self.h = h
+ end
+
+ # X coordinate of the top left corner
+ fun x: Int `{ return recv->x; `}
+
+ # Set the X coordinate of the top left corner
+ fun x=(val: Int) `{ recv->x = val; `}
+
+ # Y coordinate of the top left corner
+ fun y: Int `{ return recv->y; `}
+
+ # Set the Y coordinate of the top left corner
+ fun y=(val: Int) `{ recv->y = val; `}
+
+ # Width of this rectangle
+ fun w: Int `{ return recv->w; `}
+
+ # Set the width of this rectangle
+ fun w=(val: Int) `{ recv->w = val; `}
+
+ # Height of this rectangle
+ fun h: Int `{ return recv->h; `}
+
+ # Set the height of this rectangle
+ fun h=(val: Int) `{ recv->h = val; `}
+
+ # TODO implement other `SDLRect` related methods:
+ #
+ # SDL_EnclosePoints
+ # SDL_HasIntersection
+ # SDL_IntersectRect
+ # SDL_IntersectRectAndLine
+ # SDL_PointInRect
+ # SDL_RectEmpty
+ # SDL_RectEquals
+ # SDL_UnionRect
+end
+
+# A point with `x` and `y`
+extern class SDLPoint `{SDL_Point *`}
+ # Get a null rectangle (on the C side), should be used only internally
+ new nil `{ return NULL; `}
+
+ # Allocate the memory for a new `SDLPoint`, it must the be freed with `free`
+ new malloc`{ return malloc(sizeof(SDL_Point)); `}
+
+ # Allocate the memory for a new `SDLPoint` and fill it with `x` and `y`
+ #
+ # As with `malloc`, the new instances must the be freed with `free`.
+ new (x, y: Int) do
+ var point = new SDLPoint.malloc
+ point.x = x
+ point.y = y
+ return point
+ end
+
+ # X coordinate of this point
+ fun x: Int `{ return recv->x; `}
+
+ # Set the X coordinate of this point
+ fun x=(val: Int) `{ recv->x = val; `}
+
+ # Y coordinate of this point
+ fun y: Int `{ return recv->y; `}
+
+ # Set the Y coordinate of this point
+ fun y=(val: Int) `{ recv->y = val; `}
+end
+
+# Flag to set the icon in `sys.sdl.show_simple_message_box` and `SDLWindow::show_simple_message_box`
+extern class SDLMessageBoxFlags `{ Uint32 `}
+ # Request the error icon
+ new error `{ return SDL_MESSAGEBOX_ERROR; `}
+
+ # Request the warning icon
+ new warning `{ return SDL_MESSAGEBOX_WARNING; `}
+
+ # Request the information icon
+ new information `{ return SDL_MESSAGEBOX_INFORMATION; `}
+end
+
+# Information on a `SDLRenderer`
+extern class SDLRendererInfo `{ SDL_RendererInfo * `}
+ # Allocate the memory for a new `SDLRenderer`, it must then be freed with `free`
+ new malloc `{ return malloc(sizeof(SDL_RendererInfo)); `}
+
+ # Name of the renderer's driver
+ fun name: NativeString `{ return (char*)recv->name; `}
+
+ # Maximum texture width supported by the renderer
+ fun max_texture_width: Int `{ return recv->max_texture_width; `}
+
+ # Maximum texture height supported by the renderer
+ fun max_texture_height: Int `{ return recv->max_texture_height; `}
+end
--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Copyright 2014 Alexis Laferrière <alexis.laf@xymus.net>
+#
+# 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.
+
+# Window manager related SDL 2 services
+module syswm is pkgconfig "sdl2"
+
+import sdl2_base
+
+in "C Header" `{
+ #include <SDL2/SDL_syswm.h>
+`}
+
+redef extern class SDLWindow
+ # Get the `SDLSysVMInfo` for the system running this window
+ #
+ # The returned value must be freed.
+ fun wm_info: SDLSysWMInfo `{
+ SDL_SysWMinfo *val = malloc(sizeof(SDL_SysWMinfo));
+
+ SDL_VERSION(&val->version);
+
+ if(SDL_GetWindowWMInfo(recv, val) <= 0) {
+ free(val);
+ return NULL;
+ }
+
+ return val;
+ `}
+end
+
+# Information on the window manager
+#
+# Created using `SDLWindow::vm_info`
+extern class SDLSysWMInfo `{ SDL_SysWMinfo * `}
+ # Is this an unknown window manager?
+ fun is_unknown: Bool `{ return recv->subsystem == SDL_SYSWM_UNKNOWN; `}
+
+ # Is this a Windows system?
+ fun is_windows: Bool `{ return recv->subsystem == SDL_SYSWM_WINDOWS; `}
+
+ # Is this the X11 window manager?
+ fun is_x11: Bool `{ return recv->subsystem == SDL_SYSWM_X11; `}
+
+ # Is this a direct DirectFB?
+ fun is_direcfb: Bool `{ return recv->subsystem == SDL_SYSWM_DIRECTFB; `}
+
+ # Is this system an OS X?
+ fun is_cocoa: Bool `{ return recv->subsystem == SDL_SYSWM_COCOA; `}
+
+ # Is this system an iOS?
+ fun is_uikit: Bool `{ return recv->subsystem == SDL_SYSWM_UIKIT; `}
+
+ # It this window manager Wayland?
+ fun is_wayland: Bool `{
+ #if SDL_VERSION_ATLEAST(2, 0, 2)
+ return recv->subsystem == SDL_SYSWM_WAYLAND;
+ #else
+ return 0;
+ #endif
+ `}
+
+ # It this window manager Mir?
+ fun is_mir: Bool `{
+ #if SDL_VERSION_ATLEAST(2, 0, 3)
+ return recv->subsystem == SDL_SYSWM_MIR;
+ #else
+ return 0;
+ #endif
+ `}
+
+ # Is this system a Windows RT?
+ fun is_winrt: Bool `{
+ #if SDL_VERSION_ATLEAST(2, 0, 3)
+ return recv->subsystem == SDL_SYSWM_WINRT;
+ #else
+ return 0;
+ #endif
+ `}
+
+ # Is this system an Android?
+ fun is_android: Bool `{
+ #if SDL_VERSION_ATLEAST(2, 0, 4)
+ return recv->subsystem == SDL_SYSWM_ANDROID;
+ #else
+ return 0;
+ #endif
+ `}
+
+ # Returns the handle of this window on a X11 window system
+ #
+ # Require: `is_x11`
+ fun x11_window_handle: Pointer `{
+ return (void*)recv->info.x11.window;
+ `}
+end
# r.handle_signal(sigint, true)
# r.handle_signal(sigalarm, true)
#
-# Ask system to receive a `sigalarm` signal in 1 second
+# # Ask system to receive a `sigalarm` signal in 1 second
# set_alarm(1)
#
# loop
class Statement
private var native_statement: NativeStatement
- private init(ns: NativeStatement) do self.native_statement = ns
-
# Is this statement usable?
var is_open = true
end
end
+# A row from a `Statement`
class StatementRow
# Statement linked to `self`
var statement: Statement
- private init(s: Statement) do self.statement = s
-
# Number of entries in this row
#
# require: `self.statement.is_open`
private var index: Int
- private init(s: Statement, i: Int)
- do
- self.statement = s
- self.index = i
- end
-
# Name of the column
#
# require: `self.statement.is_open`
# Statement linked to `self`
var statement: Statement
- private init(s: Statement)
+ init
do
- self.statement = s
- self.item = new StatementRow(s)
-
+ self.item = new StatementRow(statement)
self.is_ok = statement.native_statement.step.is_row
end
- redef var item: StatementRow
+ redef var item: StatementRow is noinit
- redef var is_ok: Bool
+ redef var is_ok: Bool is noinit
# require: `self.statement.is_open`
redef fun next
class Blob
super Sqlite3Data
- private init(pointer: Pointer, length: Int)
- do
- self.pointer = pointer
- self.length = length
- end
-
+ # Pointer to the beginning of the blob
var pointer: Pointer
+
+ # Size of the blob
var length: Int
end
# Subclasses often provide a more efficient implementation.
#
# Because of the `iterator` method, Collections instances can use
-# the `for` control structure:
+# the `for` control structure.
#
-# var x: Collection[U]
-# # ...
-# for u in x do
-# # u is a U
-# # ...
-# end
+# ~~~nitish
+# var x: Collection[U]
+# # ...
+# for u in x do
+# # u is a U
+# # ...
+# end
+# ~~~
#
-# that is equivalent with
+# that is equivalent with the following:
#
-# var x: Collection[U]
-# # ...
-# var i = x.iterator
-# while i.is_ok do
-# var u = i.item # u is a U
-# # ...
-# i.next
-# end
+# ~~~nitish
+# var x: Collection[U]
+# # ...
+# var i = x.iterator
+# while i.is_ok do
+# var u = i.item # u is a U
+# # ...
+# i.next
+# end
+# ~~~
interface Collection[E]
# Get a new iterator on the collection.
fun iterator: Iterator[E] is abstract
return iterator.item
end
- # Is the collection contains all the elements of `other`?
+ # Does the collection contain at least each element of `other`?
#
- # assert [1,1,1].has_all([1]) == true
- # assert [1,1,1].has_all([1,2]) == false
# assert [1,3,4,2].has_all([1..2]) == true
# assert [1,3,4,2].has_all([1..5]) == false
+ #
+ # Repeated elements in the collections are not considered.
+ #
+ # assert [1,1,1].has_all([1]) == true
+ # assert [1..5].has_all([1,1,1]) == true
+ #
+ # Note that the default implementation is general and correct for any lawful Collections.
+ # It is memory-efficient but relies on `has` so may be CPU-inefficient for some kind of collections.
fun has_all(other: Collection[E]): Bool
do
for x in other do if not has(x) then return false
return true
end
+
+ # Does the collection contain exactly all the elements of `other`?
+ #
+ # The same elements must be present in both `self` and `other`,
+ # but the order of the elements in the collections are not considered.
+ #
+ # assert [1..3].has_exactly([3,1,2]) == true # the same elements
+ # assert [1..3].has_exactly([3,1]) == false # 2 is not in the array
+ # assert [1..2].has_exactly([3,1,2]) == false # 3 is not in the range
+ #
+ # Repeated elements must be present in both collections in the same amount.
+ # So basically it is a multi-set comparison.
+ #
+ # assert [1,2,3,2].has_exactly([1,2,2,3]) == true # the same elements
+ # assert [1,2,3,2].has_exactly([1,2,3]) == false # more 2 in the first array
+ # assert [1,2,3].has_exactly([1,2,2,3]) == false # more 2 in the second array
+ #
+ # Note that the default implementation is general and correct for any lawful Collections.
+ # It is memory-efficient but relies on `count` so may be CPU-inefficient for some kind of collections.
+ fun has_exactly(other: Collection[E]): Bool
+ do
+ if length != other.length then return false
+ for e in self do if self.count(e) != other.count(e) then return false
+ return true
+ end
end
# Instances of the Iterator class generates a series of elements, one at a time.
redef var is_ok: Bool = true
- private var container: Container[E]
+ var container: Container[E]
end
# Items can be removed from this collection
return nhs
end
+ # Returns a new instance of `Set`.
+ #
+ # Depends on the subclass, mainly used for copy services
+ # like `union` or `intersection`.
protected fun new_set: Set[E] is abstract
end
_iter.next
end
- private var iter: Iterator[Couple[K,V]]
+ var iter: Iterator[Couple[K,V]]
end
# Some tools ###################################################################
# var b = [10, 20, 30, 40, 50]
# a.copy_to(1, 2, b, 2)
# assert b == [10, 20, 2, 3, 50]
- protected fun copy_to(start: Int, len: Int, dest: AbstractArray[E], new_start: Int)
+ fun copy_to(start: Int, len: Int, dest: AbstractArray[E], new_start: Int)
do
# TODO native one
var i = len
redef var index = 0
- private var array: AbstractArrayRead[E]
+ var array: AbstractArrayRead[E]
end
private class ArrayReverseIterator[E]
redef fun item: E do return _iter.item
- private var iter: ArrayIterator[E]
+ var iter: ArrayIterator[E]
end
fun length: Int is intern
# Use `self` to initialize a standard Nit Array.
fun to_a: Array[E] do return new Array[E].with_native(self, length)
+
+ # Get item at `index`.
fun [](index: Int): E is intern
+
+ # Set `item` at `index`.
fun []=(index: Int, item: E) is intern
+
+ # Copy `length` items to `dest`.
fun copy_to(dest: NativeArray[E], length: Int) is intern
#fun =(o: NativeArray[E]): Bool is intern
#fun !=(o: NativeArray[E]): Bool is intern
import union_find
redef class Sequence[E]
+
+ # Copy the content of `self` between `start` and `len` to a new Array.
fun subarray(start, len: Int): Array[E]
do
var a = new Array[E].with_capacity(len)
private abstract class HashCollection[K: Object]
type N: HashNode[K]
- private var array: nullable NativeArray[nullable N] = null # Used to store items
- private var capacity: Int = 0 # Size of _array
- private var the_length: Int = 0 # Number of items in the map
+ var array: nullable NativeArray[nullable N] = null # Used to store items
+ var capacity: Int = 0 # Size of _array
+ var the_length: Int = 0 # Number of items in the map
- private var first_item: nullable N = null # First added item (used to visit items in nice order)
- private var last_item: nullable N = null # Last added item (same)
+ var first_item: nullable N = null # First added item (used to visit items in nice order)
+ var last_item: nullable N = null # Last added item (same)
# The last key accessed (used for cache)
- private var last_accessed_key: nullable K = null
+ var last_accessed_key: nullable K = null
# The last node accessed (used for cache)
- private var last_accessed_node: nullable N = null
+ var last_accessed_node: nullable N = null
# Return the index of the key k
fun index_at(k: K): Int
end
private abstract class HashNode[K: Object]
- private var key: K
+ var key: K
type N: HashNode[K]
- private var next_item: nullable N = null
- private var prev_item: nullable N = null
- private var prev_in_bucklet: nullable N = null
- private var next_in_bucklet: nullable N = null
+ var next_item: nullable N = null
+ var prev_item: nullable N = null
+ var prev_in_bucklet: nullable N = null
+ var next_in_bucklet: nullable N = null
end
# A map implemented with a hash table.
private class HashMapNode[K: Object, V]
super HashNode[K]
redef type N: HashMapNode[K, V]
- private var value: V
+ var value: V
end
+# A `MapIterator` over a `HashMap`.
class HashMapIterator[K: Object, V]
super MapIterator[K, V]
redef fun is_ok do return _node != null
end
# The set to iterate on
- private var set: HashSet[E]
+ var set: HashSet[E]
# The position in the internal map storage
- private var node: nullable HashSetNode[E] = null
+ var node: nullable HashSetNode[E] = null
init
do
super IndexedIterator[E]
redef fun item do return _node.item
+ # Set item `e` at self `index`.
fun item=(e: E) do _node.item = e
redef fun is_ok do return not _node == null
# Get the element after the last one.
var after: E
+ # assert [1..10].has(5)
+ # assert [1..10].has(10)
+ # assert not [1..10[.has(10)
redef fun has(item) do return item >= first and item <= last
+ # assert [1..1].has_only(1)
+ # assert not [1..10].has_only(1)
redef fun has_only(item) do return first == item and item == last or is_empty
+ # assert [1..10].count(1) == 1
+ # assert [1..10].count(0) == 0
redef fun count(item)
do
if has(item) then
redef fun iterator do return new IteratorRange[E](self)
+ # assert [1..10].length == 10
+ # assert [1..10[.length == 9
+ # assert [1..1].length == 1
+ # assert [1..-10].length == 0
redef fun length
do
+ if is_empty then return 0
var nb = first.distance(after)
if nb > 0 then
return nb
end
end
+ # assert not [1..10[.is_empty
+ # assert not [1..1].is_empty
+ # assert [1..-10].is_empty
redef fun is_empty do return first >= after
# Create a range [`from`, `to`].
- # The syntax `[from..to[` is equivalent.
- init(from: E, to: E)
- do
+ # The syntax `[from..to]` is equivalent.
+ #
+ # var a = [10..15]
+ # var b = new Range[Int] (10,15)
+ # assert a == b
+ # assert a.to_a == [10, 11, 12, 13, 14, 15]
+ init(from: E, to: E) is old_style_init do
first = from
last = to
after = to.successor(1)
# Create a range [`from`, `to`[.
# The syntax `[from..to[` is equivalent.
+ #
+ # var a = [10..15[
+ # var b = new Range[Int].without_last(10,15)
+ # assert a == b
+ # assert a.to_a == [10, 11, 12, 13, 14]
init without_last(from: E, to: E)
do
first = from
last = to.predecessor(1)
after = to
end
+
+ # Two ranges are equals if they have the same first and last elements.
+ #
+ # var a = new Range[Int](10, 15)
+ # var b = new Range[Int].without_last(10, 15)
+ # assert a == [10..15]
+ # assert a == [10..16[
+ # assert not a == [10..15[
+ # assert b == [10..15[
+ # assert b == [10..14]
+ # assert not b == [10..15]
+ redef fun ==(o) do
+ return o isa Range[E] and self.first == o.first and self.last == o.last
+ end
+
+ # var a = new Range[Int](10, 15)
+ # assert a.hash == 455
+ # var b = new Range[Int].without_last(10, 15)
+ # assert b.hash == 432
+ redef fun hash do
+ # 11 and 23 are magic numbers empirically determined to be not so bad.
+ return first.hash * 11 + last.hash * 23
+ end
end
private class IteratorRange[E: Discrete]
# Iterator on ranges.
super Iterator[E]
- private var range: Range[E]
+ var range: Range[E]
redef var item is noinit
redef fun is_ok do return _item < _range.after
var arguments: nullable Array[String]
# Launch a command with some arguments
- init(command: String, arguments: String...)
- do
+ init(command: String, arguments: String...) is old_style_init do
self.command = command
self.arguments = arguments
execute
class IProcess
super Process
super IStream
+
+ # File Descriptor used for the input.
var stream_in: IFStream is noinit
redef fun close do stream_in.close
class OProcess
super Process
super OStream
+
+ # File Descriptor used for the output.
var stream_out: OStream is noinit
redef fun close do stream_out.close
end
redef class NativeString
+ # Execute self as a shell command.
+ #
+ # See the posix function system(3).
fun system: Int is extern "string_NativeString_NativeString_system_0"
end
# The FILE *.
private var file: nullable NativeFile = null
+ # The status of a file. see POSIX stat(2).
fun file_stat: FileStat do return _file.file_stat
# File descriptor of this file
###############################################################################
+# Standard input stream.
class Stdin
super IFStream
redef fun poll_in: Bool is extern "file_stdin_poll_in"
end
+# Standard output stream.
class Stdout
super OFStream
init do
end
end
+# Standard error stream.
class Stderr
super OFStream
init do
end
# returns files contained within the directory represented by self
- fun files : Set[ String ] is extern import HashSet[String], HashSet[String].add, NativeString.to_s, String.to_cstring, HashSet[String].as(Set[String]) `{
+ fun files: Array[String] is extern import Array[String], Array[String].add, NativeString.to_s, String.to_cstring `{
char *dir_path;
DIR *dir;
}
else
{
- HashSet_of_String results;
+ Array_of_String results;
String file_name;
struct dirent *de;
- results = new_HashSet_of_String();
+ results = new_Array_of_String();
while ( ( de = readdir( dir ) ) != NULL )
if ( strcmp( de->d_name, ".." ) != 0 &&
strcmp( de->d_name, "." ) != 0 )
{
file_name = NativeString_to_s( strdup( de->d_name ) );
- HashSet_of_String_add( results, file_name );
+ Array_of_String_add( results, file_name );
}
closedir( dir );
- return HashSet_of_String_as_Set_of_String( results );
+ return results;
}
`}
end
#
# Currently, Object is also used to collect all top-level methods.
interface Object
+ # Type of this instance, automatically specialized in every class
+ #
+ # A common use case of the virtual type `SELF` is to type an attribute and
+ # store another instance of the same type as `self`. It can also be used as as
+ # return type to a method producing a copy of `self` or returning an instance
+ # expected to be the exact same type as self.
+ #
+ # This virtual type must be used with caution as it can hinder specialization.
+ # In fact, it imposes strict restrictions on all sub-classes and their usage.
+ # For example, using `SELF` as a return type of a method `foo`
+ # forces all subclasses to ensure that `foo` returns the correct and updated
+ # type.
+ # A dangerous usage take the form of a method typed by `SELF` which creates
+ # and returns a new instance.
+ # If not correctly specialized, this method would break when invoked on a
+ # sub-class.
+ #
+ # A general rule for safe usage of `SELF` is to ensure that inputs typed
+ # `SELF` are stored in attributes typed `SELF` and returned by methods typed
+ # `SELF`, pretty much the same things as you would do with parameter types.
+ type SELF: Object
+
# The unique object identifier in the class.
# Unless specific code, you should not use this method.
# The identifier is used internally to provide a hash value.
end
end
+ # Compare float numbers with a given precision.
+ #
+ # Because of the loss of precision in floating numbers,
+ # the `==` method is often not the best way to compare them.
+ #
+ # ~~~
+ # assert 0.01.is_approx(0.02, 0.1) == true
+ # assert 0.01.is_approx(0.02, 0.001) == false
+ # ~~~
+ fun is_approx(other, precision: Float): Bool
+ do
+ assert precision >= 0.0
+ return self <= other + precision and self >= other - precision
+ end
+
redef fun max(other)
do
if self < other then
redef fun -(i) is intern
redef fun *(i) is intern
redef fun /(i) is intern
+
+ # Modulo of `self` with `i`.
+ #
+ # Finds the remainder of division of `self` by `i`.
+ #
+ # assert 5 % 2 == 1
+ # assert 10 % 2 == 0
fun %(i: Int): Int is intern
redef fun zero do return 0
end
redef class Float
+
+ # Returns the non-negative square root of `self`.
+ #
+ # assert 9.0.sqrt == 3.0
+ # #assert 3.0.sqrt == 1.732
+ # assert 1.0.sqrt == 1.0
+ # assert 0.0.sqrt == 0.0
fun sqrt: Float is extern "kernel_Float_Float_sqrt_0"
+
+ # Computes the cosine of `self` (expressed in radians).
+ #
+ # #assert pi.cos == -1.0
fun cos: Float is extern "kernel_Float_Float_cos_0"
+
+ # Computes the sine of `self` (expressed in radians).
+ #
+ # #assert pi.sin == 0.0
fun sin: Float is extern "kernel_Float_Float_sin_0"
+
+ # Computes the cosine of x (expressed in radians).
+ #
+ # #assert 0.0.tan == 0.0
fun tan: Float is extern "kernel_Float_Float_tan_0"
+
+ # Computes the arc cosine of `self`.
+ #
+ # #assert 0.0.acos == pi / 2.0
fun acos: Float is extern "kernel_Float_Float_acos_0"
+
+ # Computes the arc sine of `self`.
+ #
+ # #assert 1.0.asin == pi / 2.0
fun asin: Float is extern "kernel_Float_Float_asin_0"
+
+ # Computes the arc tangent of `self`.
+ #
+ # #assert 0.0.tan == 0.0
fun atan: Float is extern "kernel_Float_Float_atan_0"
+
+ # Returns the absolute value of `self`.
+ #
+ # assert 12.0.abs == 12.0
+ # assert (-34.56).abs == 34.56
+ # assert -34.56.abs == -34.56
fun abs: Float `{ return fabs(recv); `}
+ # Returns `self` raised at `e` power.
+ #
+ # #assert 2.0.pow(0.0) == 1.0
+ # #assert 2.0.pow(3.0) == 8.0
+ # #assert 0.0.pow(9.0) == 0.0
fun pow(e: Float): Float is extern "kernel_Float_Float_pow_1"
+
+ # Returns the logarithm of `self`.
+ #
+ # assert 0.0.log.is_inf == -1
+ # #assert 1.0.log == 0.0
fun log: Float is extern "kernel_Float_Float_log_0"
+
+ # Returns **e** raised to `self`.
fun exp: Float is extern "kernel_Float_Float_exp_0"
# assert 1.1.ceil == 2.0
# assert 2.0.floor == 2.0
# assert (-1.5).floor == -2.0
fun floor: Float `{ return floor(recv); `}
+
+ # Rounds the value of a float to its nearest integer value
+ #
+ # assert 1.67.round == 2.0
+ # assert 1.34.round == 1.0
+ # assert -1.34.round == -1.0
+ # assert -1.67.round == -2.0
+ fun round: Float is extern "round"
# Returns a random `Float` in `[0.0 .. self[`.
fun rand: Float is extern "kernel_Float_Float_rand_0"
- fun hypot_with( b : Float ) : Float is extern "hypotf"
+ # Returns the euclidean distance from `b`.
+ fun hypot_with(b : Float): Float is extern "hypotf"
+
+ # Returns true is self is not a number.
fun is_nan: Bool is extern "isnan"
# Is the float an infinite value
end
end
+# Computes the arc tangent given `x` and `y`.
+#
+# assert atan2(-0.0, 1.0) == -0.0
+# assert atan2(0.0, 1.0) == 0.0
fun atan2(x: Float, y: Float): Float is extern "kernel_Any_Any_atan2_2"
+
+# Approximate value of **pi**.
fun pi: Float is extern "kernel_Any_Any_pi_0"
# Initialize the pseudo-random generator with the given seed.
return message;
`}
- # This field holds the number of parenthetical subexpressions in the regular expression that was compiled.
+ # Number of parenthetical subexpressions in this compiled regular expression
fun re_nsub: Int `{ return recv->re_nsub; `}
end
private var native: nullable NativeRegex = null
# Cache of a single `regmatch_t` to prevent many calls to `malloc`
- private var native_match = new NativeMatchArray.malloc(1) is lazy
+ private var native_match: NativeMatchArray is lazy do
+ native_match_is_init = true
+ return new NativeMatchArray.malloc(native.re_nsub+1)
+ end
+
+ private var native_match_is_init = false
# `cflags` of the last successful `compile`
private var cflags_cache = 0
native.regfree
native.free
self.native = null
- self.native_match.free
+
+ if native_match_is_init then
+ self.native_match.free
+ end
end
end
text = text.to_s
var cstr = text.substring_from(from).to_cstring
var eflags = gather_eflags
- var match = self.native_match
- var matches = new Array[Match]
+ var native_match = self.native_match
- var res = native.regexec(cstr, 1, match, eflags)
+ var nsub = native.re_nsub
+ var res = native.regexec(cstr, nsub+1, native_match, eflags)
# Found one?
- if res == 0 then return new Match(text, from + match.rm_so, match.rm_eo - match.rm_so)
+ if res == 0 then
+ var match = new Match(text,
+ from + native_match.rm_so,
+ native_match.rm_eo - native_match.rm_so)
+
+ # Add sub expressions
+ for i in [1..nsub] do
+ match.subs.add new Match( text,
+ native_match[i].rm_so,
+ native_match[i].rm_eo - native_match[i].rm_so)
+ end
+
+ return match
+ end
# No more match?
if res.is_nomatch then return null
var cstr = text.to_cstring
var eflags = gather_eflags
var eflags_or_notbol = eflags.bin_or(flag_notbol)
- var match = self.native_match
+ var native_match = self.native_match
var matches = new Array[Match]
- var res = native.regexec(cstr, 1, match, eflags)
+ var nsub = native.re_nsub
+ var res = native.regexec(cstr, nsub+1, native_match, eflags)
var d = 0
while res == 0 do
- matches.add new Match(text, d + match.rm_so, match.rm_eo - match.rm_so)
- if d == match.rm_eo then
+ var match = new Match(text,
+ d + native_match.rm_so,
+ native_match.rm_eo - native_match.rm_so)
+ matches.add match
+
+ # Add sub expressions
+ for i in [1..nsub] do
+ match.subs.add new Match( text,
+ d + native_match[i].rm_so,
+ native_match[i].rm_eo - native_match[i].rm_so)
+ end
+
+ if d == native_match.rm_eo then
d += 1
- else d = d + match.rm_eo
- cstr = cstr.substring_from(match.rm_eo)
- res = native.regexec(cstr, 1, match, eflags_or_notbol)
+ else d = d + native_match.rm_eo
+ cstr = cstr.substring_from(native_match.rm_eo)
+ res = native.regexec(cstr, nsub+1, native_match, eflags_or_notbol)
end
# No more match?
redef fun to_s do return "/{string}/"
end
+
+redef class Match
+ # Parenthesized subexpressions in this match
+ #
+ # ~~~
+ # var re = "c (d e+) f".to_re
+ # var match = "a b c d eee f g".search(re)
+ # assert match.subs.length == 1
+ # assert match.subs.first.to_s == "d eee"
+ # ~~~
+ var subs = new Array[Match] is lazy
+
+ # Get the `n`th expression in this match
+ #
+ # `n == 0` returns this match, and a greater `n` returns the corresponding
+ # subexpression.
+ #
+ # Require: `n >= 0 and n <= subs.length`
+ #
+ # ~~~
+ # var re = "c (d e+) f".to_re
+ # var match = "a b c d eee f g".search(re)
+ # assert match[0].to_s == "c d eee f"
+ # assert match[1].to_s == "d eee"
+ # ~~~
+ fun [](n: Int): Match do
+ if n == 0 then return self
+ assert n > 0 and n <= subs.length
+ return subs[n-1]
+ end
+end
# Right child of the node
var right: String
- init(l: String, r: String) do
+ init(l: String, r: String) is old_style_init do
left = l
right = r
length = l.length + r.length
redef fun +(o) do
var s = o.to_s
- var mlen = length
var slen = s.length
if s isa Concat then
return new Concat(self, s)
var nns = new NativeString(buf_size)
var blen = rpos - dumped
ns.copy_to(nns, blen, dumped, 0)
+ ns = nns
dumped = 0
rpos = blen
written = false
str = ""
length = 0
rpos = 0
+ dumped = 0
+ if written then
+ ns = new NativeString(buf_size)
+ written = false
+ end
end
redef fun substring(from, count) do
var slen = s.length
length += slen
var rp = rpos
- if s isa Rope then
- if rp > 0 and dumped != rp then
- str += new FlatString.with_infos(ns, rp - dumped, dumped, rp - 1)
- dumped = rp
- end
- str = str + s
- return
- end
- if slen > maxlen then
+ if s isa Rope or slen > maxlen then
if rp > 0 and dumped != rp then
str += new FlatString.with_infos(ns, rp - dumped, dumped, rp - 1)
dumped = rp
return
end
if slen <= remsp then
- sits.copy_to(ns, slen, begin, rp)
- if rp == buf_size then
- rpos = buf_size
+ if remsp <= 0 then
dump_buffer
rpos = 0
else
+ sits.copy_to(ns, slen, begin, rp)
rpos += slen
end
else
redef fun add(c) do
var rp = rpos
- length += 1
- ns[rp] = c
- rp += 1
- if rp == buf_size then
- rpos = rp
+ if rp >= buf_size then
dump_buffer
rp = 0
end
+ ns[rp] = c
+ rp += 1
+ length += 1
rpos = rp
end
end
redef fun reverse do
- str = str.reversed
- var nns = new NativeString(buf_size)
- var j = rpos
- var mits = ns
- for i in [0 .. rpos[ do
- nns[i] = mits[j]
- j -= 1
+ # Flush the buffer in order to only have to reverse `str`.
+ if rpos > 0 and dumped != rpos then
+ str += new FlatString.with_infos(ns, rpos - dumped, dumped, rpos - 1)
+ dumped = rpos
end
- ns = nns
+ str = str.reversed
end
redef fun upper do
# the Rope traversal.
var subs: IndexedIterator[String]
- init(root: RopeString) do
+ init(root: RopeString) is old_style_init do
pos = root.length - 1
subs = new ReverseRopeSubstrings(root)
ns = subs.item
# Position (char) in the Rope (0-indexed)
var pos: Int
- init(root: RopeString) do
+ init(root: RopeString) is old_style_init do
subs = new RopeSubstrings(root)
pns = 0
str = subs.item
# Current leaf
var str: String is noinit
- init(root: RopeString) do
+ init(root: RopeString) is old_style_init do
var r = new RopeIterPiece(root, false, true, null)
pos = root.length - 1
var lnod: String = root
redef fun next do
if pos < 0 then return
- var curr: nullable RopeIterPiece = iter.prev
+ var curr = iter.prev
var currit = curr.node
while curr != null do
currit = curr.node
# Did we attain the buffered part ?
var nsstr_done = false
- init(str: RopeBuffer) do
+ init(str: RopeBuffer) is old_style_init do
iter = str.str.substrings
nsstr = new FlatString.with_infos(str.ns, str.rpos - str.dumped, str.dumped, str.rpos - 1)
if str.length == 0 then nsstr_done = true
# Current leaf
var str: String is noinit
- init(root: RopeString) do
+ init(root: RopeString) is old_style_init do
var r = new RopeIterPiece(root, true, false, null)
pos = 0
max = root.length - 1
pos += str.length
if pos > max then return
var it = iter.prev
- var rnod: String = it.node
+ var rnod = it.node
loop
if not rnod isa Concat then
it.ldone = true
var tgt: RopeString
- init(s: RopeString) do tgt = s
+ init(s: RopeString) is old_style_init do tgt = s
redef fun [](i) do
return tgt[i]
end
+# An Iterator over a RopeBuffer.
class RopeBufferIter
super IndexedIterator[Char]
+ # Subiterator.
var sit: IndexedIterator[Char]
+ # Native string iterated over.
var ns: NativeString
+ # Current position in `ns`.
var pns: Int
+ # Maximum position iterable.
var maxpos: Int
redef var index: Int
- init(t: RopeBuffer) do
+ # Init the iterator from a RopeBuffer.
+ init(t: RopeBuffer) is old_style_init do
ns = t.ns
maxpos = t.rpos
sit = t.str.chars.iterator
index = 0
end
+ # Init the iterator from a RopeBuffer starting from `pos`.
init from(t: RopeBuffer, pos: Int) do
ns = t.ns
maxpos = t.length
end
end
+# Reverse iterator over a RopeBuffer.
class RopeBufferReviter
super IndexedIterator[Char]
+ # Subiterator.
var sit: IndexedIterator[Char]
+ # Native string iterated over.
var ns: NativeString
+ # Current position in `ns`.
var pns: Int
redef var index: Int
- init(tgt: RopeBuffer) do
+ # Init the iterator from a RopeBuffer.
+ init(tgt: RopeBuffer) is old_style_init do
sit = tgt.str.chars.reverse_iterator
pns = tgt.rpos - 1
index = tgt.length - 1
ns = tgt.ns
end
+ # Init the iterator from a RopeBuffer starting from `pos`.
init from(tgt: RopeBuffer, pos: Int) do
sit = tgt.str.chars.reverse_iterator_from(pos - tgt.rpos - tgt.dumped)
pns = pos - tgt.str.length
end
# Read a string until the end of the line.
+ #
+ # The line terminator '\n', if any, is preserved in each line.
+ # Use the method `Text::chomp` to safely remove it.
+ #
+ # ~~~
+ # var txt = "Hello\n\nWorld\n"
+ # var i = new StringIStream(txt)
+ # assert i.read_line == "Hello\n"
+ # assert i.read_line == "\n"
+ # assert i.read_line == "World\n"
+ # assert i.eof
+ # ~~~
+ #
+ # If `\n` is not present at the end of the result, it means that
+ # a non-eol terminated last line was returned.
+ #
+ # ~~~
+ # var i2 = new StringIStream("hello")
+ # assert not i2.eof
+ # assert i2.read_line == "hello"
+ # assert i2.eof
+ # ~~~
+ #
+ # NOTE: Only LINE FEED (`\n`) is considered to delimit the end of lines.
fun read_line: String
do
if last_error != null then return ""
return s.to_s
end
+ # Read all the lines until the eof.
+ #
+ # The line terminator '\n' is removed in each line,
+ #
+ # ~~~
+ # var txt = "Hello\n\nWorld\n"
+ # var i = new StringIStream(txt)
+ # assert i.read_lines == ["Hello", "", "World"]
+ # ~~~
+ #
+ # This method is more efficient that splitting
+ # the result of `read_all`.
+ #
+ # NOTE: Only LINE FEED (`\n`) is considered to delimit the end of lines.
+ fun read_lines: Array[String]
+ do
+ var res = new Array[String]
+ while not eof do
+ res.add read_line.chomp
+ end
+ return res
+ end
+
# Read all the stream until the eof.
fun read_all: String
do
end
# Read a string until the end of the line and append it to `s`.
+ #
+ # SEE: `read_line` for details.
fun append_line_to(s: Buffer)
do
if last_error != null then return
end
end
+# An Input/Output Stream
abstract class IOStream
super IStream
super OStream
content.add(str.to_s)
end
+ # Is the stream closed?
protected var closed = false
+
redef fun close do closed = true
end
# assert "\na\nb\tc\t".trim == "a\nb\tc"
fun trim: SELFTYPE do return (self.l_trim).r_trim
+ # Returns `self` removed from its last `\n` (if any).
+ #
+ # assert "Hello\n".chomp == "Hello"
+ # assert "Hello".chomp == "Hello"
+ # assert "\n\n\n".chomp == "\n\n"
+ #
+ # This method is mainly used to remove the LINE_FEED character from lines of text.
+ fun chomp: SELFTYPE
+ do
+ if self.chars.last != '\n' then return self
+ return substring(0, length-1)
+ end
+
# Justify a self in a space of `length`
#
# `left` is the space ratio on the left side.
return buf.to_s
end
- # Escape the four characters `<`, `>`, `&`, and `"` with their html counterpart
+ # Escape the characters `<`, `>`, `&`, `"`, `'` and `/` as HTML/XML entity references.
#
- # assert "a&b->\"x\"".html_escape == "a&b->"x""
+ # assert "a&b-<>\"x\"/'".html_escape == "a&b-<>"x"/'"
+ #
+ # SEE: <https://www.owasp.org/index.php/XSS_%28Cross_Site_Scripting%29_Prevention_Cheat_Sheet#RULE_.231_-_HTML_Escape_Before_Inserting_Untrusted_Data_into_HTML_Element_Content>
fun html_escape: SELFTYPE
do
var buf = new FlatBuffer
else if c == '>' then
buf.append ">"
else if c == '"' then
- buf.append """
+ buf.append """
+ else if c == '\'' then
+ buf.append "'"
+ else if c == '/' then
+ buf.append "/"
else buf.add c
end
redef var length: Int = 0
- init do end
-
redef fun output
do
var i = 0
type SELFTYPE: Text
- private var target: SELFTYPE
+ var target: SELFTYPE
redef fun is_empty do return target.is_empty
end
+# A `String` holds and manipulates an arbitrary sequence of characters.
+#
+# String objects may be created using literals.
+#
+# assert "Hello World!" isa String
abstract class String
super Text
# assert "abc" * 0 == ""
fun *(i: Int): SELFTYPE is abstract
+ # Insert `s` at `pos`.
+ #
+ # assert "helloworld".insert_at(" ", 5) == "hello world"
fun insert_at(s: String, pos: Int): SELFTYPE is abstract
redef fun substrings: Iterator[String] is abstract
end
+# A mutable sequence of characters.
abstract class Buffer
super Text
#
# SEE: `Char::is_letter` for the definition of a letter.
#
- # var b = new FlatBuffer.from("jAVAsCriPt")"
+ # var b = new FlatBuffer.from("jAVAsCriPt")
# b.capitalize
# assert b == "Javascript"
# b = new FlatBuffer.from("i am root")
if length == 0 then return
var c = self[0].to_upper
self[0] = c
- var prev: Char = c
+ var prev = c
for i in [1 .. length[ do
prev = c
c = self[i]
# Create a new empty string.
init do end
+ # Create a new string copied from `s`.
init from(s: Text)
do
capacity = s.length + 1
redef fun append(s)
do
- var my_items = target.items
var s_length = s.length
if target.capacity < s.length then enlarge(s_length + target.length)
end
extern class NativeString `{ char* `}
# Creates a new NativeString with a capacity of `length`
new(length: Int) is intern
+
+ # Get char at `index`.
fun [](index: Int): Char is intern
+
+ # Set char `item` at index.
fun []=(index: Int, item: Char) is intern
+
+ # Copy `self` to `dest`.
fun copy_to(dest: NativeString, length: Int, from: Int, to: Int) is intern
# Position of the first nul character.
while self[l] != '\0' do l += 1
return l
end
+
+ # Parse `self` as an Int.
fun atoi: Int is intern
+
+ # Parse `self` as a Float.
fun atof: Float is extern "atof"
redef fun to_s
return to_s_with_length(cstring_length)
end
+ # Returns `self` as a String of `length`.
fun to_s_with_length(length: Int): FlatString
do
assert length >= 0
return str
end
+ # Returns `self` as a new String.
fun to_s_with_copy: FlatString
do
var length = cstring_length
return res
end
+ # Is `self` in `s`?
protected fun is_in(s: Text): Bool do return search_index_in(s, 0) != -1
end
private fun compute_gs
do
- var x = _motif
var m = _length
var suff = suffixes
var i = 0
# Time since epoch
extern class TimeT `{time_t`}
+
+ # Returns Time since epoch from now.
new `{ return time(NULL); `}
+
+ # Returns Time since epoch from `i` (expressed in seconds).
new from_i(i: Int) `{ return i; `}
+ # Update current time.
fun update `{ time(&recv); `}
+ # Convert `self` to a human readable String.
fun ctime: String import NativeString.to_s_with_copy `{
return NativeString_to_s_with_copy( ctime(&recv) );
`}
fun difftime(start: TimeT): Float `{ return difftime(recv, start); `}
redef fun to_s do return ctime.replace("\n", "")
+
+ # Convert self to Int (expressed as seconds since epoch).
fun to_i: Int `{ return (int)recv; `}
end
# Time structure
extern class Tm `{struct tm *`}
+
+ # Create a new Time structure expressed in Coordinated Universal Time (UTC).
new gmtime `{
struct tm *tm;
time_t t = time(NULL);
tm = gmtime(&t);
return tm;
`}
+
+ # Create a new Time structure expressed in UTC from `t`.
new gmtime_from_timet(t: TimeT) `{
struct tm *tm;
tm = gmtime(&t);
return tm;
`}
+ # Create a new Time structure expressed in the local timezone.
new localtime `{
struct tm *tm;
time_t t = time(NULL);
tm = localtime(&t);
return tm;
`}
+
+ # Create a new Time structure expressed in the local timezone from `t`.
new localtime_from_timet(t: TimeT) `{
struct tm *tm;
tm = localtime(&t);
return tm;
`}
+ # Convert `self` as a TimeT.
fun to_timet: TimeT `{ return mktime(recv); `}
+ # Seconds after the minute.
fun sec: Int `{ return recv->tm_sec; `}
+
+ # Minutes after the hour.
fun min: Int `{ return recv->tm_min; `}
+
+ # hours since midnight.
fun hour: Int `{ return recv->tm_hour; `}
+
+ # Day of the month.
fun mday: Int `{ return recv->tm_mday; `}
+
+ # Months since January.
fun mon: Int `{ return recv->tm_mon; `}
+
+ # Years since 1900.
fun year: Int `{ return recv->tm_year; `}
+
+ # Days since Sunday.
fun wday: Int `{ return recv->tm_wday; `}
+
+ # Days since January 1st.
fun yday: Int `{ return recv->tm_yday; `}
+
+ # Is `self` in Daylight Saving Time.
fun is_dst: Bool `{ return recv->tm_isdst; `}
+ # Convert `self` to a human readable String.
fun asctime: String import NativeString.to_s_with_copy `{
return NativeString_to_s_with_copy( asctime(recv) );
`}
+
+ # Convert `self` to a human readable String corresponding to `format`.
+ # TODO document allowed format.
fun strftime(format: String): String import String.to_cstring, NativeString.to_s `{
char* buf, *c_format;
size_t res;
#
# As per the specification :
#
+ # ~~~raw
# Length | UTF-8 octet sequence
# | (binary)
# ---------+-------------------------------------------------
# 2 | 110xxxxx 10xxxxxx
# 3 | 1110xxxx 10xxxxxx 10xxxxxx
# 4 | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
+ # ~~~
private fun len: Int `{
char* ns = recv->ns;
int pos = recv->pos;
#
# As per the specification :
#
+ # ~~~raw
# Length | UTF-8 octet sequence
# | (binary)
# ---------+-------------------------------------------------
# 2 | 110xxxxx 10xxxxxx
# 3 | 1110xxxx 10xxxxxx 10xxxxxx
# 4 | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
+ # ~~~
fun len: Int `{
uint32_t s = *recv;
if(s <= 127) {return 1;}
#
# In external file `example.tpl`:
#
-# <!DOCTYPE html>
-# <html lang="en">
-# <head>
-# <title>%TITLE%</title>
-# </head>
-# <body>
-# <h1>%TITLE%</h1>
-# <p>%ARTICLE%</p>
-# </body>
-# </html>
+# ~~~html
+# <!DOCTYPE html>
+# <html lang="en">
+# <head>
+# <title>%TITLE%</title>
+# </head>
+# <body>
+# <h1>%TITLE%</h1>
+# <p>%ARTICLE%</p>
+# </body>
+# </html>
+# ~~~
#
# Loading the template file using `TemplateString`:
#
class TreeNode[K: Comparable, E]
# TreeNode type
- type SELF: TreeNode[K, E]
+ type N: TreeNode[K, E]
# `key` for this node
var key: K
var value: E
# Direct parent of this node (null if the node is root)
- var parent: nullable SELF = null is writable
+ var parent: nullable N = null is writable
redef fun to_s do return "\{{value or else ""}\}"
# Perform left rotation on `node`
#
+ # ~~~raw
# N Y
# / \ > / \
# a Y N c
# / \ < / \
# b c a b
+ # ~~~
#
protected fun rotate_left(node: N) do
var y = node.right
# Perform right rotation on `node`
#
+ # ~~~raw
# N Y
# / \ > / \
# a Y N c
# / \ < / \
# b c a b
+ # ~~~
#
protected fun rotate_right(node: N) do
var y = node.left
private var prev: nullable BinTreeNode[K, E]
private var next: nullable BinTreeNode[K, E]
- redef type SELF: BinTreeNode[K, E]
+ redef type N: BinTreeNode[K, E]
init(key: K, item: E) do
super(key, item)
end
- private var left_node: nullable SELF = null
+ private var left_node: nullable N = null
# `left` tree node child (null if node has no left child)
- fun left: nullable SELF do return left_node
+ fun left: nullable N do return left_node
# set `left` child for this node (or null if left no child)
# ENSURE: node.key < key (only if node != null)
- fun left=(node: nullable SELF) do
+ fun left=(node: nullable N) do
#assert node != null implies node.key < key
left_node = node
end
- private var right_node: nullable SELF = null
+ private var right_node: nullable N = null
# `right` tree node child (null if node has no right child)
- fun right: nullable SELF do return right_node
+ fun right: nullable N do return right_node
# set `right` child for this node (or null if right no child)
# ENSURE: node.key < key (only if node != null)
- fun right=(node: nullable SELF) do
+ fun right=(node: nullable N) do
#assert node != null implies node.key > key
right_node = node
end
# `parent` of the `parent` of this node (null if root)
- fun grandparent: nullable SELF do
+ fun grandparent: nullable N do
if parent == null then
return null
else
# Other child of the `grandparent`
# `left` or `right` depends on the position of the current node against its parent
- fun uncle: nullable SELF do
+ fun uncle: nullable N do
var g = grandparent
if g == null then
return null
# Other child of the parent
# `left` or `right` depends on the position of the current node against its parent
- fun sibling: nullable SELF do
+ fun sibling: nullable N do
if parent == null then
return null
else if self == parent.left then
# Red-Black Tree Map
# Properties of a Red-Black tree map:
-# * every node is either red or black
-# * root is black
-# * every leaf (null) is black
-# * if a node is red, then both its children are black
-# * for each node, all simple path from the node to descendant
-# leaves contain the same number of black nodes
+# * every node is either red or black
+# * root is black
+# * every leaf (null) is black
+# * if a node is red, then both its children are black
+# * for each node, all simple path from the node to descendant
+# leaves contain the same number of black nodes
#
# Operations:
-# * search average O(lg n) worst O(lg n)
-# * insert average O(lg n) worst O(lg n)
-# * delete average O(lg n) worst O(lg n)
+# * search average O(lg n) worst O(lg n)
+# * insert average O(lg n) worst O(lg n)
+# * delete average O(lg n) worst O(lg n)
class RBTreeMap[K: Comparable, E]
super BinTreeMap[K, E]
class RBTreeNode[K: Comparable, E]
super BinTreeNode[K, E]
- redef type SELF: RBTreeNode[K, E]
+ redef type N: RBTreeNode[K, E]
# Is the node red?
private var is_red = true
# Serices from the X11 library
module x11 is pkgconfig
+`{
+ #include <X11/Xlib.h>
+`}
+
# Open the current display from the environment variables
#
# See <http://www.x.org/releases/X11R7.7/doc/man/man3/XOpenDisplay.3.xhtml>
" FFI Python
syntax include @FFIPython syntax/python.vim
unlet b:current_syntax
-syn match NITFFILanguage '"Python"' nextgroup=NITFFIBlockPython skipwhite
+syn match NITFFILanguage /\c"Python"/ nextgroup=NITFFIBlockPython skipwhite
syn region NITFFIBlockPython matchgroup=NITFFI start='`{' matchgroup=NITFFI end='`}' keepend fold contains=@FFIPython
" FFI Java
syntax include @FFIJava syntax/java.vim
unlet b:current_syntax
-syn match NITFFILanguage '"Java"' nextgroup=NITFFIBlockJava skipwhite
+syn match NITFFILanguage /\c"Java\(\| inner\)"/ nextgroup=NITFFIBlockJava skipwhite
syn region NITFFIBlockJava matchgroup=NITFFI start='`{' matchgroup=NITFFI end='`}' keepend fold contains=@FFIJava
" FFI C++
syntax include @FFICpp syntax/cpp.vim
unlet b:current_syntax
-syn match NITFFILanguage '"C++"' nextgroup=NITFFIBlockCpp skipwhite
+syn match NITFFILanguage /\c"C++\(\| header\| body\)"/ nextgroup=NITFFIBlockCpp skipwhite
syn region NITFFIBlockCpp matchgroup=NITFFI start='`{' matchgroup=NITFFI end='`}' keepend fold contains=@FFICpp
+" FFI Objective-C
+syntax include @FFIObjC syntax/objc.vim
+unlet b:current_syntax
+syn match NITFFILanguage /\c"ObjC\(\| Header\| Body\)"/ nextgroup=NITFFIBlockObjC skipwhite
+syn region NITFFIBlockObjC matchgroup=NITFFI start='`{' matchgroup=NITFFI end='`}' keepend fold contains=@FFIObjC
+
" FFI C (the last one is the default)
syntax include @FFIC syntax/c.vim
unlet b:current_syntax
-syn match NITFFILanguage '"C\(\| header\| body\)"' nextgroup=NITFFIBlockC skipwhite
+syn match NITFFILanguage /\c"C\(\| header\| body\)"/ nextgroup=NITFFIBlockC skipwhite
syn region NITFFIBlockC matchgroup=NITFFI start='`{' matchgroup=NITFFI end='`}' keepend fold contains=@FFIC
hi def link NITFFILanguage Define
\ '%f:%l\,%c--%*[0-9]\,%*[0-9]:',
\ '%f:%l\,%c:' ]
let ef_type = [ ' %tarning: ',
+ \ ' %tocumentation warning: ',
\ '' ]
" generate errorformat from combinations
endfor
endfor
- return SyntasticMake({ 'makeprg': makeprg, 'errorformat':errorformat })
+ let loclist = SyntasticMake({ 'makeprg': makeprg, 'errorformat': errorformat, 'postprocess': ['guards'] })
+
+ for e in loclist
+ if e['type'] ==? 'd' " is a documentation warning
+ let e['type'] = 'w'
+ let e['subtype'] = 'Style'
+ endif
+ endfor
+
+ return loclist
endfunction
call g:SyntasticRegistry.CreateAndRegisterChecker({
# SYNOPSIS
-nitls [*options*] FILE...
+nitls [*options*] [*FILE*]...
# DESCRIPTION
It is basically a `ls` or a simple `find` specialized on `.nit` source files.
+By default `nitls` works with the current directory (`.`).
+
+Each file can then be:
+
+* A Nit module (file).
+ In this case, only this single module is considered
+* A Nit group (directory).
+ In this case, all the modules of the groups (and recursively the sub-groups) are considered
+* A normal directory.
+ In this case, all its entries are analysed.
+ Files that are Nit modules and directories that are Nit groups are considered.
+ Other files and directories are ignored.
+
# EXAMPLES
-Show the tree of modules from the current directory and subdirectories.
+Show the tree of modules from the current directory.
- $ nitls -t -r .
+ $ nitls -t
Show the list of projects imported by the modules of the current directory.
# OPTIONS
-## COLLECT
-
-`-r`, `--recursive`
-: Process directories recursively.
-
- All `.nit` files found in the specified directory and subdirectories are considered.
-
-`-d`, `--depends`
-: List dependencies of given modules
-
- All imported modules are also considered.
-
-`-k`, `--keep`
-: Ignore errors and files that are not a Nit source file.
-
- When a file that is not a valit Nit module is encoutered, it is ignored and the rest of the file are
- processed.
-
- Without this option, a error message is displayed and nitls terminates on such a case.
+Each combination of option
## PRESENTATION MODE
Each `.nit` file is presented indivitually.
+The three modes are exclusives.
+
+The default mode is `--project` unless one on the argument is a group, then it is `--group`.
+
+## COLLECT
+
+`-r`, `--recursive`
+: Process directories recursively.
+
+ All `.nit` files found in the specified directory and subdirectories are considered.
+
+`-d`, `--depends`
+: List dependencies of given modules
+
+ All imported modules are also considered.
+
+ In --tree and --source modes, the modules direclty imported are also displayed.
+
+`-k`, `--keep`
+: Ignore errors and files that are not a Nit source file.
+
+ When a file that is not a valid Nit module is encoutered, it is ignored and the rest of the files are
+ processed.
+
+ Without this option, an error message is displayed and nitls terminates on such a case.
+
## PRESENTATION OPTIONS
`-p`, `--path`
: List only path (instead of name + path).
+ Paths are displayed uncolored.
+
`-M`
: List dependencies suitable for a rule in a Makefile.
`--check`
: Check format of Nit source files
+# SPECIFICATION
+
+The specification of the pretty printing is described here.
+
+* Default indentation level is one `'\t'` character and is increased by one for
+ each indentation level.
+* Default line max-size is 80.
+
+### COMMENTS
+
+There is many categories of comments:
+
+`Licence comments` are attached to the top of the file no blank line before,
+one after.
+
+~~~nitish
+# This is a licence comment
+
+# Documentation for module `foo`
+module foo
+~~~
+
+`ADoc` are documentation comments attached to a `AModule`, `AClassdef`, `APropdef`.
+
+They are printed before the definition with a blank line before and no after
+at the same indentation level than the definition.
+
+~~~nitish
+# Documentation for module `foo`
+module foo
+
+# Documentation for class `Bar`
+class Bar
+ # Documentation for method `baz`
+ fun baz do end
+end
+~~~
+
+`Block comments` are comments composed of one or more line rattached to nothing.
+They are displayed with one blank line before and after at current indent level.
+
+~~~nitish
+<blank>
+# block
+# comment
+<blank>
+~~~
+
+`Attached comments` are comments attached to a production.
+They are printed as this.
+
+~~~nitish
+fun foo do # attached comment
+end
+~~~
+
+`nitpretty` automatically remove multiple blanks between comments:
+
+~~~nitish
+# Licence
+# ...
+<blank>
+# Block comment
+~~~
+
+### INLINING
+
+Productions are automatically inlined when possible.
+
+Conditions:
+
+* The production must be syntactically inlinable
+* The inlined production length is less than `PrettyPrinterVisitor::max-size`
+* The production do not contains any comments
+
+### MODULES
+
+* There is a blank between the module declaration and its imports
+* There is no blank between imports and only one after
+* There is a blank between each extern block definition
+* There is a blank between each class definition
+* There is no blank line at the end of the module
+
+~~~nitish
+# Documentation for module `foo`
+module foo
+
+import a
+import b
+import c
+
+# Documentation for class `Bar`
+class Bar end
+
+class Baz end # not a `ADoc` comment
+~~~
+
+### CLASSES
+
+* There is no blank between the class definition and its super-classes declarations
+* There is no blank between two inlined property definition
+* There is a blank between each block definition
+* There no blank line at the end of the class definition
+
+~~~nitish
+# Documentation for class `Bar`
+class Bar end
+
+class Baz
+ super Bar
+
+ fun a is abstract
+ private fun b do end
+
+ fun c do
+ # ...
+ end
+end
+~~~
+
+Generic types have no space after or before brackets and are separated by a comma and a space:
+
+~~~nitish
+class A[E: Type1, F: Type1] end
+~~~
+
+### BLOCKS
+
+* Inlined productions have no blank lines between them
+* Block productions have a blank before and after
+
+~~~nitish
+var a = 10
+var b = 0
+
+if a > b then
+ is positive
+ print "positive"
+end
+
+print "end"
+~~~
+
+### CALLS AND BINARY OPS
+
+Arguments are always printed separated with a comma and a space:
+
+~~~nitish
+foo(a, b, c)
+~~~
+
+Binary ops are always printed wrapped with spaces:
+
+~~~nitish
+var c = 1 + 2
+~~~
+
+Calls and binary ops can be splitted to fit the `max-size` constraint.
+Breaking priority is given to arguments declaration after the comma.
+
+~~~nitish
+return foo("aaaaaaaaaaaaaaaaaaaaaaaaaa", "bbbbbbbbbbbbbbbbbbbbbbbbbbb",
+ "cccccccccccccccccccccccccc")
+~~~
+
+Binary ops can also be broken to fit the `max-size` limit:
+
+~~~nitish
+return "aaaaaaaaaaaaaaaaaaaaaaaaaa" + "bbbbbbbbbbbbbbbbbbbbbbbbbbb" +
+ "cccccccccccccccccccccccccc"
+~~~
+
# SEE ALSO
The Nit language documentation and the source code of its tools and libraries may be downloaded from <http://nitlanguage.org>
## Working with `DocUnits`
-With DocUnits, executable code can be placed in comments of modules, classes and properties.
-The execution can be verified using `assert`
+DocUnits are blocks of executable code placed in comments of modules, classes and properties.
+The execution can be verified using `assert`.
Example with a class:
fun baz(a, b: Int) do return a + b
end
+In a single piece of documentation, each docunit is considered a part of a single module, thus regrouped when
+tested.
+Therefore, it is possible (and recommended) to split docunits in small parts if it make the explanation easier.
+
+~~~~
+# Some example of grouped docunits
+#
+# Declare and initialize a variable `a`.
+#
+# var a = 1
+#
+# So the value of `a` can be used
+#
+# assert a == 1
+#
+# even in complex operations
+#
+# assert a + 1 == 2
+fun foo do end
+~~~~
+
+Sometime, some blocks of code has to be included in documentation but not considered by `nitunit`.
+Those blocks are distinguished by their tagged fences (untagged fences or fences tagged `nit` are considered to be docunits).
+
+~~~~
+# Some ASCII drawing
+#
+# ~~~~raw
+# @<
+# <__)
+# ~~~~
+fun foo do end
+~~~~
+
+The special fence-tag `nitish` could also be used to indicate pseudo-nit that will be ignored by nitunit but highlighted by nitdoc.
+Such `nitish` piece of code can be used to enclose examples that cannot compile or that one do not want to be automatically executed.
+
+~~~~
+# Some pseudo-nit
+#
+# ~~~~nitish
+# var a: Int = someting
+# # ...
+# if a == 1 then something else something-else
+# ~~~~
+#
+# Some code to not try to execute automatically
+#
+# ~~~~nitish
+# system("rm -rf /")
+# ~~~~
+~~~~
+
The `nitunit` command is used to test Nit files:
$ nitunit foo.nit
},
_create: function() {
- this.element
- .attr(this.options.fieldAttrs)
- .keydown($.proxy(this._doKeyDown, this))
- .keyup($.proxy(this._doKeyUp, this))
-
+ // set widget options
+ this.element.attr(this.options.fieldAttrs);
+ // event dispatch
+ this._on(this.element, {
+ "keydown": this._doKeyDown,
+ "keyup": this._doKeyUp,
+ "input": this._doInput
+ });
+ // add result table element once
this._table = $("<table/>")
.attr("id", this.options.tableID)
.css(this.options.tableCSS)
.css("min-width", this.element.outerWidth());
$("body").append(this._table);
-
+ // make table disappear when a click occurs outside
$(document).click($.proxy(this.closeTable, this));
},
this.closeTable();
return true;
default: // Other keys
- utils.delayEvent($.proxy(this.search, this));
return true;
}
},
+ _doInput: function(event) {
+ utils.delayEvent($.proxy(this.search, this));
+ },
+
/* Result lookup */
_getResults: function(query) {
# To create the new node `n`, we need to attach the child to it.
# But, to put `n` where `c` was in `p`, the place has to be remembered.
#
- # var p: AExpr
- # var c = p.c
- # var h = c.detach_with_placeholder
- # var n = astbuilder.make_XXX(c)
- # h.replace_with(n)
+ # ~~~nitish
+ # var p: AExpr
+ # var c = p.c
+ # var h = c.detach_with_placeholder
+ # var n = astbuilder.make_XXX(c)
+ # h.replace_with(n)
+ # ~~~
fun detach_with_placeholder: AExpr
do
var h = new APlaceholderExpr.make
var cds = mtype.collect_mclassdefs(self.mainmodule).to_a
self.mainmodule.linearize_mclassdefs(cds)
for cd in cds do
- if not self.modelbuilder.mclassdef2nclassdef.has_key(cd) then continue
- var n = self.modelbuilder.mclassdef2nclassdef[cd]
- for npropdef in n.n_propdefs do
- if npropdef isa AAttrPropdef then
- npropdef.init_expr(v, recv)
- end
+ for npropdef in modelbuilder.collect_attr_propdef(cd) do
+ npropdef.init_expr(v, recv)
end
end
end
var cds = mtype.collect_mclassdefs(self.mainmodule).to_a
self.mainmodule.linearize_mclassdefs(cds)
for cd in cds do
- if not self.modelbuilder.mclassdef2nclassdef.has_key(cd) then continue
- var n = self.modelbuilder.mclassdef2nclassdef[cd]
- for npropdef in n.n_propdefs do
- if npropdef isa AAttrPropdef then
- npropdef.check_expr(v, recv)
- end
+ for npropdef in modelbuilder.collect_attr_propdef(cd) do
+ npropdef.check_expr(v, recv)
end
end
end
do
if is_abstract then return true
var modelbuilder = v.compiler.modelbuilder
- if modelbuilder.mpropdef2npropdef.has_key(self) then
- var npropdef = modelbuilder.mpropdef2npropdef[self]
- return npropdef.can_inline
- else if self.mproperty.is_root_init then
+ var node = modelbuilder.mpropdef2node(self)
+ if node isa APropdef then
+ return node.can_inline
+ else if node isa AClassdef then
# Automatic free init is always inlined since it is empty or contains only attribtes assigments
return true
else
do
var modelbuilder = v.compiler.modelbuilder
var val = constant_value
- if modelbuilder.mpropdef2npropdef.has_key(self) then
- var npropdef = modelbuilder.mpropdef2npropdef[self]
+ var node = modelbuilder.mpropdef2node(self)
+ if node isa APropdef then
var oldnode = v.current_node
- v.current_node = npropdef
+ v.current_node = node
self.compile_parameter_check(v, arguments)
- npropdef.compile_to_c(v, self, arguments)
+ node.compile_to_c(v, self, arguments)
v.current_node = oldnode
- else if self.mproperty.is_root_init then
- var nclassdef = modelbuilder.mclassdef2nclassdef[self.mclassdef]
+ else if node isa AClassdef then
var oldnode = v.current_node
- v.current_node = nclassdef
+ v.current_node = node
self.compile_parameter_check(v, arguments)
- nclassdef.compile_to_c(v, self, arguments)
+ node.compile_to_c(v, self, arguments)
v.current_node = oldnode
else if val != null then
v.ret(v.value_instance(val))
# Custom lines to add to the AndroidManifest.xml in the <application> node
var manifest_application_lines = new Array[String]
+ # Custom lines to add to AndroidManifest.xml as attributes inside the <activity> node
+ var manifest_activity_attributes = new Array[String]
+
# Minimum API level required for the application to run
var min_api: nullable Int = null
annots = collect_annotations_on_modules("android_manifest_application", mmodule)
for an in annots do project.manifest_application_lines.add an.arg_as_string(self) or else ""
+ annots = collect_annotations_on_modules("android_manifest_activity", mmodule)
+ for an in annots do project.manifest_activity_attributes.add an.arg_as_string(self) or else ""
+
# Get the date and time (down to the minute) as string
var local_time = new Tm.localtime
var local_time_s = local_time.strftime("%y%m%d%H%M")
# Also copy over the java files
dir = "{android_project_root}/src/"
- var extra_java_files = compiler.mainmodule.extra_java_files
- if extra_java_files != null then for file in extra_java_files do
- var path = file.filename
- path.file_copy_to("{dir}/{path.basename("")}")
+ for mmodule in compiler.mainmodule.in_importation.greaters do
+ var extra_java_files = mmodule.extra_java_files
+ if extra_java_files != null then for file in extra_java_files do
+ var path = file.filename
+ path.file_copy_to(dir/path.basename(""))
+ end
end
## Generate delagating makefile
This will take care of integrating with our NDK code. -->
<activity android:name="android.app.NativeActivity"
android:label="@string/app_name"
- android:theme="@android:style/Theme.NoTitleBar.Fullscreen"
- android:configChanges="orientation|keyboardHidden"
- android:screenOrientation="portrait"
+ {{{project.manifest_activity_attributes.join("\n")}}}
{{{icon_declaration}}}>
- <!-- Tell NativeActivity the name of or .so -->
- <meta-data android:name=\"{{{app_package}}}\"
- android:value=\"{{{app_name}}}\" />
+ <!-- Tell NativeActivity the name of our .so -->
+ <meta-data android:name=\"android.app.lib_name\"
+ android:value=\"main\" />
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
# Two elements from a POSet cannot have the same color if they share common subelements
#
# Example:
+#
+# ~~~raw
# A
# / | \
# / | \
# E F G
# |
# H
+# ~~~
+#
# Conflicts:
-# A: {B, C, D, E, F, G, H}
-# B: {A, C, E, H}
-# C: {A, E, H, F}
-# D: {A, G}
-# E: {A, B, C, H}
-# F: {A, C}
-# G: {A, D}
-# H: {A, B, C, E}
+#
+# * A: {B, C, D, E, F, G, H}
+# * B: {A, C, E, H}
+# * C: {A, E, H, F}
+# * D: {A, G}
+# * E: {A, B, C, H}
+# * F: {A, C}
+# * G: {A, D}
+# * H: {A, B, C, E}
+#
# Possible colors:
-# A:0, B:1, C: 2, D: 1, E: 3, F:3, G:2, H:4
#
-# see:
-# Ducournau, R. (2011).
-# Coloring, a versatile technique for implementing object-oriented languages.
-# Software: Practice and Experience, 41(6), 627–659.
+# * A:0, B:1, C: 2, D: 1, E: 3, F:3, G:2, H:4
+#
+# see: Ducournau, R. (2011).
+# Coloring, a versatile technique for implementing object-oriented languages.
+# Software: Practice and Experience, 41(6), 627–659.
class POSetColorer[E: Object]
# Is the poset already colored?
var live_cast_types = runtime_type_analysis.live_cast_types
var mtypes = new HashSet[MType]
mtypes.add_all(live_types)
- mtypes.add_all(live_cast_types)
for c in self.box_kinds.keys do
mtypes.add(c.mclass_type)
end
# Compute colors
- var poset = poset_from_mtypes(mtypes)
+ var poset = poset_from_mtypes(mtypes, live_cast_types)
var colorer = new POSetColorer[MType]
colorer.colorize(poset)
type_ids = colorer.ids
return poset
end
- private fun poset_from_mtypes(mtypes: Set[MType]): POSet[MType] do
+ private fun poset_from_mtypes(mtypes, cast_types: Set[MType]): POSet[MType] do
var poset = new POSet[MType]
for e in mtypes do
poset.add_node(e)
- for o in mtypes do
+ for o in cast_types do
if e == o then continue
+ poset.add_node(o)
if e.is_subtype(mainmodule, null, o) then
poset.add_edge(e, o)
end
module doc_model
import model_utils
-import markdown
+import docdown
import doc_templates
import ordered_tree
import model_ext
redef fun tpl_definition do
var tpl = new TplDefinition
+ var mdoc = mdoc_or_fallback
if mdoc != null then
tpl.comment = mdoc.tpl_comment
end
redef fun tpl_definition do
var tpl = new TplDefinition
+ var mdoc = mdoc_or_fallback
if mdoc != null then
tpl.comment = mdoc.tpl_comment
end
redef fun tpl_declaration do
var tpl = new Template
tpl.add "<span>module "
- tpl.add tpl_link
+ tpl.add tpl_namespace
tpl.add "</span>"
return tpl
end
end
end
+redef class MInnerClass
+ redef fun nitdoc_url do return inner.nitdoc_url
+ redef fun tpl_signature do return inner.tpl_signature
+end
+
+redef class MInnerClassDef
+ redef fun nitdoc_url do return inner.nitdoc_url
+
+ redef fun tpl_anchor do return inner.tpl_anchor
+ redef fun tpl_link do return inner.tpl_link
+ redef fun tpl_signature do return inner.tpl_signature
+
+ redef fun tpl_definition do
+ var tpl = new TplClassDefinition
+ tpl.namespace = mclassdef.tpl_namespace
+ if mdoc != null then
+ tpl.comment = mdoc.tpl_comment
+ end
+ return tpl
+ end
+end
+
redef class MType
fun tpl_signature: Template is abstract
end
private fun properties do
for mproperty in model.mproperties do
if mproperty.visibility <= ctx.min_visibility then continue
+ if mproperty isa MInnerClass then continue
+ if mproperty isa MAttribute then continue
var page = new NitdocProperty(ctx, model, mainmodule, mproperty)
page.render.write_to_file("{ctx.output_dir.to_s}/{page.page_url}")
end
# Graph
var mmodules = new HashSet[MModule]
- mmodules.add_all mmodule.in_nesting.direct_greaters
+ mmodules.add_all mmodule.nested_mmodules
mmodules.add_all imports
if clients.length < 10 then mmodules.add_all clients
mmodules.add mmodule
tpl_sidebar_list("Virtual types", kind_map["type"].to_a, summary)
tpl_sidebar_list("Constructors", kind_map["init"].to_a, summary)
tpl_sidebar_list("Methods", kind_map["fun"].to_a, summary)
+ if not kind_map["inner"].is_empty then
+ tpl_sidebar_list("Inner classes", kind_map["inner"].to_a, summary)
+ end
tpl_sidebar.boxes.add new TplSideBox.with_content("All properties", summary)
end
for article in tpl_mproperty_articles(kind_map, "fun") do
section.add_child article
end
+ # inner classes
+ for article in tpl_mproperty_articles(kind_map, "inner") do
+ section.add_child article
+ end
parent.add_child section
end
end
map["type"] = new HashSet[MProperty]
map["init"] = new HashSet[MProperty]
map["fun"] = new HashSet[MProperty]
+ map["inner"] = new HashSet[MProperty]
for mprop in mprops do
if mprop isa MVirtualTypeProp then
map["type"].add mprop
else
map["fun"].add mprop
end
+ else if mprop isa MInnerClass then
+ map["inner"].add mprop
end
end
return map
private fun tpl_properties(parent: TplSection) do
# intro title
- var section = new TplSection.with_title("intro", "Introduction")
+ var ns = mproperty.intro.mclassdef.mmodule.tpl_namespace
+ var section = new TplSection("intro")
+ var title = new Template
+ title.add "Introduction in "
+ title.add ns
+ section.title = title
section.summary_title = "Introduction"
section.add_child tpl_mpropdef_article(mproperty.intro)
parent.add_child section
parent.add_child new TplSection(mentity.nitdoc_id)
else if mentity isa MModule then
var ssection = new TplSection(mentity.nitdoc_id)
- var title = new Template
+ title = new Template
title.add "in "
title.add mentity.tpl_namespace
ssection.title = title
module doc_templates
import template
+import json::static
# A documentation page
class TplPage
# Render the html header
private fun render_head do
- add "<!DOCTYPE html>"
- add "<head>"
- add " <meta charset='utf-8'/>"
- add " <!--link rel='stylesheet' href='{shareurl}/css/Nitdoc.UI.css' type='text/css'/-->"
- add " <link rel='stylesheet' href='{shareurl}/vendors/bootstrap/css/bootstrap.min.css'/>"
- add " <link rel='stylesheet' href='{shareurl}/css/nitdoc.bootstrap.css'/>"
- add " <link rel='stylesheet' href='{shareurl}/css/nitdoc.css'/>"
- add " <link rel='stylesheet' href='{shareurl}/css/Nitdoc.QuickSearch.css'/>"
- add " <link rel='stylesheet' href='{shareurl}/css/Nitdoc.ModalBox.css'/>"
- add " <link rel='stylesheet' href='{shareurl}/css/Nitdoc.GitHub.css'/>"
- add " <title>{title}</title>"
- add "</head>"
+ var css = (self.shareurl / "css").html_escape
+ var vendors = (self.shareurl / "vendors").html_escape
+
+ addn "<!DOCTYPE html>"
+ addn "<head>"
+ addn " <meta charset='utf-8'/>"
+ addn " <!--link rel='stylesheet' href='{css}/Nitdoc.UI.css' type='text/css'/-->"
+ addn " <link rel='stylesheet' href='{vendors}/bootstrap/css/bootstrap.min.css'/>"
+ addn " <link rel='stylesheet' href='{css}/nitdoc.bootstrap.css'/>"
+ addn " <link rel='stylesheet' href='{css}/nitdoc.css'/>"
+ addn " <link rel='stylesheet' href='{css}/Nitdoc.QuickSearch.css'/>"
+ addn " <link rel='stylesheet' href='{css}/Nitdoc.ModalBox.css'/>"
+ addn " <link rel='stylesheet' href='{css}/Nitdoc.GitHub.css'/>"
+ addn " <title>{title}</title>"
+ addn "</head>"
add "<body"
for attr in body_attrs do add attr
- add ">"
+ addn ">"
end
# Render the topmenu template
private fun render_topmenu do
- add " <div class='row'>"
+ addn " <div class='row'>"
add topmenu
- add " </div>"
+ addn " </div>"
end
# Render the sidebar
private fun render_content do
for section in sections do add section
if footer != null then
- add "<div class='well footer'>"
+ addn "<div class='well footer'>"
add footer.as(not null)
- add "</div>"
+ addn "</div>"
end
end
# Render JS scripts
private fun render_footer do
- add "<script src='{shareurl}/vendors/jquery/jquery-1.11.1.min.js'></script>"
- add "<script src='{shareurl}/vendors/jquery/jquery-ui-1.10.4.custom.min.js'></script>"
- add "<script src='{shareurl}/vendors/bootstrap/js/bootstrap.min.js'></script>"
- add "<script data-main='{shareurl}/js/nitdoc' src='{shareurl}/js/lib/require.js'></script>"
+ var vendors = (self.shareurl / "vendors").html_escape
+ var js = (self.shareurl / "js").html_escape
+
+ addn "<script src='{vendors}/jquery/jquery-1.11.1.min.js'></script>"
+ addn "<script src='{vendors}/jquery/jquery-ui-1.10.4.custom.min.js'></script>"
+ addn "<script src='{vendors}/bootstrap/js/bootstrap.min.js'></script>"
+ addn "<script data-main='{js}/nitdoc' src='{js}/lib/require.js'></script>"
for script in scripts do add script
- add """<script>
+ addn """<script>
$(function () {
$("[data-toggle='tooltip']").tooltip();
$("[data-toggle='popover']").popover();
});
</script>"""
- add "</body>"
- add "</html>"
+ addn "</body>"
+ addn "</html>"
end
# Render the whole page
redef fun rendering do
render_head
- add "<div class='container-fluid'>"
+ addn "<div class='container-fluid'>"
render_topmenu
- add " <div class='row' id='content'>"
+ addn " <div class='row' id='content'>"
if sidebar != null then
- add "<div class='col col-xs-3 col-lg-2'>"
+ addn "<div class='col col-xs-3 col-lg-2'>"
render_sidebar
- add "</div>"
- add "<div class='col col-xs-9 col-lg-10' data-spy='scroll' data-target='.summary'>"
+ addn "</div>"
+ addn "<div class='col col-xs-9 col-lg-10' data-spy='scroll' data-target='.summary'>"
render_content
- add "</div>"
+ addn "</div>"
else
- add "<div class='col col-xs-12'>"
+ addn "<div class='col col-xs-12'>"
render_content
- add "</div>"
+ addn "</div>"
end
- add " </div>"
- add "</div>"
+ addn " </div>"
+ addn "</div>"
render_footer
end
end
end
tpl.add ">"
tpl.add content
- tpl.add "</li>"
+ tpl.addn "</li>"
add_raw(tpl)
end
redef fun rendering do
if brand == null and elts.is_empty then return
- add "<nav id='topmenu' class='navbar navbar-default navbar-fixed-top' role='navigation'>"
- add " <div class='container-fluid'>"
- add " <div class='navbar-header'>"
+ addn "<nav id='topmenu' class='navbar navbar-default navbar-fixed-top' role='navigation'>"
+ addn " <div class='container-fluid'>"
+ addn " <div class='navbar-header'>"
add " <button type='button' class='navbar-toggle' "
- add " data-toggle='collapse' data-target='#topmenu-collapse'>"
- add " <span class='sr-only'>Toggle menu</span>"
- add " <span class='icon-bar'></span>"
- add " <span class='icon-bar'></span>"
- add " <span class='icon-bar'></span>"
- add " </button>"
+ addn " data-toggle='collapse' data-target='#topmenu-collapse'>"
+ addn " <span class='sr-only'>Toggle menu</span>"
+ addn " <span class='icon-bar'></span>"
+ addn " <span class='icon-bar'></span>"
+ addn " <span class='icon-bar'></span>"
+ addn " </button>"
if brand != null then add brand.as(not null)
- add " </div>"
- add " <div class='collapse navbar-collapse' id='topmenu-collapse'>"
+ addn " </div>"
+ addn " <div class='collapse navbar-collapse' id='topmenu-collapse'>"
if not elts.is_empty then
- add "<ul class='nav navbar-nav'>"
+ addn "<ul class='nav navbar-nav'>"
for elt in elts do add elt
- add "</ul>"
+ addn "</ul>"
end
- add " </div>"
- add " </div>"
- add "</nav>"
+ addn " </div>"
+ addn " </div>"
+ addn "</nav>"
end
end
redef fun rendering do
if boxes.is_empty then return
order_boxes
- add "<div id='sidebar'>"
+ addn "<div id='sidebar'>"
for box in boxes do add box
- add "</div>"
+ addn "</div>"
end
end
if content == null then return
var open = ""
if is_open then open = "in"
- add "<div class='panel'>"
- add " <div class='panel-heading'>"
+ addn "<div class='panel'>"
+ addn " <div class='panel-heading'>"
add " <a data-toggle='collapse' data-parent='#sidebar' data-target='#box_{id}' href='#'>"
add title
- add " </a>"
- add " </div>"
- add " <div id='box_{id}' class='panel-body collapse {open}'>"
+ addn " </a>"
+ addn " </div>"
+ addn " <div id='box_{id}' class='panel-body collapse {open}'>"
add content.as(not null)
- add " </div>"
- add "</div>"
+ addn " </div>"
+ addn "</div>"
end
end
redef fun rendering do
if children.is_empty then return
- add "<div class='panel'>"
- add " <div class='panel-heading'>"
+ addn "<div class='panel'>"
+ addn " <div class='panel-heading'>"
add " <a data-toggle='collapse' data-parent='#sidebar' data-target='#box-sum' href='#'>"
add "Summary"
- add " </a>"
- add " </div>"
- add " <div id='box-sum' class='summary collapse in'>"
- add " <ul class='nav'>"
+ addn " </a>"
+ addn " </div>"
+ addn " <div id='box-sum' class='summary collapse in'>"
+ addn " <ul class='nav'>"
for entry in children do add entry
- add " </ul>"
- add " </div>"
- add "</div>"
+ addn " </ul>"
+ addn " </div>"
+ addn "</div>"
end
end
add "<li>"
add text
if not children.is_empty then
- add "<ul class='nav'>"
+ addn "\n<ul class='nav'>"
for entry in children do add entry
- add "</ul>"
+ addn "</ul>"
end
- add "</li>"
+ addn "</li>"
end
end
super TplSectionElt
redef fun rendering do
- add "<section id='{id}' class='{css_classes.join(" ")}'>"
+ addn "<section id='{id}' class='{css_classes.join(" ")}'>"
if title != null then
var lvl = hlvl
if lvl == 2 then title_classes.add "well well-sm"
- add "<h{lvl} class='{title_classes.join(" ")}'>"
- add title.as(not null)
- add "</h{lvl}>"
+ addn "<h{lvl} class='{title_classes.join(" ")}'>"
+ addn title.as(not null)
+ addn "</h{lvl}>"
end
if subtitle != null then
- add "<div class='info subtitle'>"
- add subtitle.as(not null)
- add "</div>"
+ addn "<div class='info subtitle'>"
+ addn subtitle.as(not null)
+ addn "</div>"
end
for child in children do
add child
end
- add "</section>"
+ addn "</section>"
end
end
redef fun rendering do
if is_empty then return
- add "<article id='{id}' class='{css_classes.join(" ")}'>"
+ addn "<article id='{id}' class='{css_classes.join(" ")}'>"
if source_link != null then
add "<div class='source-link'>"
add source_link.as(not null)
- add "</div>"
+ addn "</div>"
end
if title != null then
var lvl = hlvl
if lvl == 2 then title_classes.add "well well-sm"
add "<h{lvl} class='{title_classes.join(" ")}'>"
add title.as(not null)
- add "</h{lvl}>"
+ addn "</h{lvl}>"
end
if subtitle != null then
add "<div class='info subtitle'>"
add subtitle.as(not null)
- add "</div>"
+ addn "</div>"
end
if content != null then
add content.as(not null)
for child in children do
add child
end
- add """</article>"""
+ addn """</article>"""
end
redef fun is_empty: Bool do
var location: nullable Streamable = null is writable
private fun render_info do
- add "<div class='info text-right'>"
+ addn "<div class='info text-right'>"
if namespace != null then
if comment == null then
add "<span class=\"noComment\">no comment for </span>"
add " "
add location.as(not null)
end
- add "</div>"
+ addn "</div>"
end
private fun render_comment do
end
redef fun rendering do
- add "<div class='definition'>"
+ addn "<div class='definition'>"
render_comment
render_info
- add "</div>"
+ addn "</div>"
end
end
init do end
redef fun rendering do
- add "<div class='definition'>"
+ addn "<div class='definition'>"
render_comment
render_info
render_list("Introduces", intros)
render_list("Redefines", redefs)
- add "</div>"
+ addn "</div>"
end
private fun render_list(name: String, elts: Array[TplListElt]) do
if elts.is_empty then return
- add "<h5>{name}</h5>"
- add "<ul class='list-unstyled list-definition'>"
+ addn "<h5>{name.html_escape}</h5>"
+ addn "<ul class='list-unstyled list-definition'>"
for elt in elts do add elt
- add "</ul>"
+ addn "</ul>"
end
end
redef fun rendering do
var title = self.title
- if title != null then add "<h1>{title}</h1>"
- add "<div class='container-fluid'>"
- add " <div class='row'>"
+ if title != null then addn "<h1>{title.to_s.html_escape}</h1>"
+ addn "<div class='container-fluid'>"
+ addn " <div class='row'>"
if not modules.is_empty then
- add "<div class='col-xs-4'>"
- add "<h3>Modules</h3>"
- add "<ul>"
+ addn "<div class='col-xs-4'>"
+ addn "<h3>Modules</h3>"
+ addn "<ul>"
for m in modules do
add "<li>"
add m
- add "</li>"
+ addn "</li>"
end
- add "</ul>"
- add "</div>"
+ addn "</ul>"
+ addn "</div>"
end
if not classes.is_empty then
- add "<div class='col-xs-4'>"
- add "<h3>Classes</h3>"
- add "<ul>"
+ addn "<div class='col-xs-4'>"
+ addn "<h3>Classes</h3>"
+ addn "<ul>"
for c in classes do
add "<li>"
add c
- add "</li>"
+ addn "</li>"
end
- add "</ul>"
- add "</div>"
+ addn "</ul>"
+ addn "</div>"
end
if not props.is_empty then
- add "<div class='col-xs-4'>"
- add "<h3>Properties</h3>"
- add "<ul>"
+ addn "<div class='col-xs-4'>"
+ addn "<h3>Properties</h3>"
+ addn "<ul>"
for p in props do
add "<li>"
add p
- add "</li>"
+ addn "</li>"
end
- add "</ul>"
- add "</div>"
+ addn "</ul>"
+ addn "</div>"
end
- add " </div>"
- add "</div>"
+ addn " </div>"
+ addn "</div>"
end
end
redef fun rendering do
if elts.is_empty then return
- add "<ul class='{css_classes.join(" ")}'>"
+ addn "<ul class='{css_classes.join(" ")}'>"
for elt in elts do add elt
- add "</ul>"
+ addn "</ul>"
end
end
redef fun rendering do
add "<li class='{css_classes.join(" ")}'>"
add content
- add "</li>"
+ addn "</li>"
end
end
var css_classes = new Array[String]
redef fun rendering do
- add "<div class='tab-content'>"
+ addn "<div class='tab-content'>"
for panel in panels do add panel
- add "</div>"
+ addn "</div>"
end
end
redef fun rendering do
add "<div class='tab-pane {css_classes.join(" ")}"
if is_active then add "active"
- add "' id='{id}'>"
+ addn "' id='{id}'>"
if content != null then add content.as(not null)
- add "</div>"
+ addn "</div>"
end
end
# A HTML tag attribute
# `<tag attr="value">`
+#
+# ~~~nit
+# var attr: TagAttribute
+#
+# attr = new TagAttribute("foo", null)
+# assert attr.write_to_string == " foo=\"\""
+#
+# attr = new TagAttribute("foo", "bar<>")
+# assert attr.write_to_string == " foo=\"bar<>\""
+# ~~~
class TagAttribute
super Template
redef fun rendering do
var value = self.value
if value == null then
- add(" {name}")
+ # SEE: http://www.w3.org/TR/html5/infrastructure.html#boolean-attributes
+ add " {name.html_escape}=\"\""
else
- add(" {name}=\"{value}\"")
+ add " {name.html_escape}=\"{value.html_escape}\""
end
end
end
redef fun rendering do
add "<script"
for attr in attrs do add attr
- add ">"
+ addn ">"
render_content
- add "</script>"
+ addn "</script>"
end
end
var site_id: String
redef fun render_content do
- add "<!-- Piwik -->"
- add "var _paq = _paq || [];"
- add " _paq.push([\"trackPageView\"]);"
- add " _paq.push([\"enableLinkTracking\"]);"
- add "(function() \{"
- add " var u=((\"https:\" == document.location.protocol) ? \"https\" : \"http\") + \"://{tracker_url}\";"
- add " _paq.push([\"setTrackerUrl\", u+\"piwik.php\"]);"
- add " _paq.push([\"setSiteId\", \"{site_id}\"]);"
- add " var d=document, g=d.createElement(\"script\"), s=d.getElementsByTagName(\"script\")[0]; g.type=\"text/javascript\";"
- add " g.defer=true; g.async=true; g.src=u+\"piwik.js\"; s.parentNode.insertBefore(g,s);"
- add "\})();"
+ var site_id = self.site_id.to_json
+ var tracker_url = self.tracker_url.trim
+ if tracker_url.chars.last != '/' then tracker_url += "/"
+ tracker_url = "://{tracker_url}".to_json
+
+ addn "<!-- Piwik -->"
+ addn "var _paq = _paq || [];"
+ addn " _paq.push([\"trackPageView\"]);"
+ addn " _paq.push([\"enableLinkTracking\"]);"
+ addn "(function() \{"
+ addn " var u=((\"https:\" == document.location.protocol) ? \"https\" : \"http\") + {tracker_url};"
+ addn " _paq.push([\"setTrackerUrl\", u+\"piwik.php\"]);"
+ addn " _paq.push([\"setSiteId\", {site_id}]);"
+ addn " var d=document, g=d.createElement(\"script\"), s=d.getElementsByTagName(\"script\")[0]; g.type=\"text/javascript\";"
+ addn " g.defer=true; g.async=true; g.src=u+\"piwik.js\"; s.parentNode.insertBefore(g,s);"
+ addn "\})();"
end
end
end
end
+# An inner class.
+class MInnerClass
+ super MProperty
+
+ redef type MPROPDEF: MInnerClassDef
+
+ # The actual class.
+ var inner: MClass
+end
+
+# An inner class definition.
+class MInnerClassDef
+ super MPropDef
+
+ redef type MPROPDEF: MInnerClassDef
+ redef type MPROPERTY: MInnerClass
+
+ # The actual class definition.
+ var inner: MClassDef
+end
+
+
# The “package” visiblity.
#
# Any visibility roughly equivalent to the default visibility of Java, that is
# limitations under the License.
# Transform Nit verbatim documentation into HTML
-module markdown
+module docdown
private import parser
import html
# Count empty lines between code blocks
var empty_lines = 0
+ # Optional tag for a fence
+ var fence_tag = ""
+
fun work(mdoc: MDoc): HTMLTag
do
var root = new HTMLTag("div")
empty_lines = 0
# to allows 4 spaces including the one that follows the #
curblock.add(text)
+ fence_tag = ""
continue
end
var l = 3
while l < text.length and text.chars[l] == '~' do l += 1
in_fence = text.substring(0, l)
+ while l < text.length and (text.chars[l] == '.' or text.chars[l] == ' ') do l += 1
+ fence_tag = text.substring_from(l)
continue
end
# Code part
var n2 = new HTMLTag("code")
n.add(n2)
- process_code(n2, part)
+ process_code(n2, part, null)
end
is_text = not is_text
end
# add the node
var n = new HTMLTag("pre")
root.add(n)
- process_code(n, btext.to_s)
+ process_code(n, btext.to_s, fence_tag)
curblock.clear
end
end
- fun process_code(n: HTMLTag, text: String)
+ fun process_code(n: HTMLTag, text: String, tag: nullable String)
do
+ # Do not try to highlight non-nit code.
+ if tag != null and tag != "" and tag != "nit" and tag != "nitish" then
+ n.append text
+ n.add_class("rawcode")
+ return
+ end
+
# Try to parse it
var ast = toolcontext.parse_something(text)
end
redef class Location
- fun as_line_pragma: String do return "#line {line_start} \"{file.filename}\"\n"
+ fun as_line_pragma: String do return "#line {line_start-1} \"{file.filename}\"\n"
end
redef class MModule
end
var ftype = code_block.language.get_ftype(code_block, nclassdef)
- nclassdef.ftype_cache = ftype
- nclassdef.ftype_computed = true
+ nclassdef.mclassdef.ftype_cache = ftype
+ nclassdef.mclassdef.ftype_computed = true
end
end
-redef class AClassdef
+redef class MClassDef
private var ftype_cache: nullable ForeignType = null
private var ftype_computed = false
return ftype_cache
end
- var intro_nclassdef = v.toolcontext.modelbuilder.mclassdef2nclassdef[intro]
- var ftype = intro_nclassdef.ftype
+ var ftype = intro.ftype
if ftype == null then
var ftype_b: nullable ForeignType = null # FIXME hack to circumvent bug where ftype is typed null
import cpp
import java
import extra_java_files
+import objc
redef class MModule
# Does this module uses the FFI?
--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Copyright 2014 Alexis Laferrière <alexis.laf@xymus.net>
+#
+# 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.
+
+# FFI support for Objective-C
+#
+# Compiles all Objective-C code with clang. The user module must define
+# the framework used.
+#
+# This module is heavily based on the C++ FFI.
+module objc
+
+import extern_classes
+import c
+
+redef class FFILanguageAssignationPhase
+ # The Objective-C language visitor
+ var objc_language: FFILanguage = new ObjCLanguage(self)
+end
+
+redef class MModule
+ private var objc_file: nullable ObjCCompilationUnit = null
+end
+
+# The Objective-C langugage visitor
+class ObjCLanguage
+ super FFILanguage
+
+ redef fun identify_language(n) do return n.is_objc
+
+ redef fun compile_module_block(block, ecc, mmodule)
+ do
+ if mmodule.objc_file == null then mmodule.objc_file = new ObjCCompilationUnit
+
+ if block.is_objc_header then
+ mmodule.objc_file.header_custom.add block.location.as_line_pragma
+ mmodule.objc_file.header_custom.add block.code
+ else if block.is_objc_body then
+ mmodule.objc_file.body_custom.add block.location.as_line_pragma
+ mmodule.objc_file.body_custom.add block.code
+ end
+ end
+
+ redef fun compile_extern_method(block, m, ecc, mmodule)
+ do
+ if mmodule.objc_file == null then mmodule.objc_file = new ObjCCompilationUnit
+
+ var mpropdef = m.mpropdef
+ var recv_mtype = mpropdef.mclassdef.bound_mtype
+ var csignature = mpropdef.mproperty.build_csignature(
+ recv_mtype, mmodule, "___impl", long_signature, from_objc_call_context)
+
+ var fc = new CFunction(csignature)
+ fc.decls.add block.location.as_line_pragma
+ fc.exprs.add block.code
+ mmodule.objc_file.add_exported_function fc
+ end
+
+ redef fun compile_extern_class(block, m, ecc, mmodule) do end
+
+ redef fun get_ftype(block, m) do return new ForeignObjCType(block.code)
+
+ redef fun compile_to_files(mmodule, compdir)
+ do
+ var objc_file = mmodule.objc_file
+ assert objc_file != null
+
+ # write .m and _m.h file
+ mmodule.objc_file.header_c_types.add """
+ #include "{{{mmodule.cname}}}._ffi.h"
+"""
+
+ var file = objc_file.write_to_files(mmodule, compdir)
+
+ # add compilation to makefile
+ mmodule.ffi_files.add file
+ end
+
+ redef fun compile_callback(callback, mmodule, mainmodule, ecc)
+ do
+ callback.compile_callback_to_objc(mmodule, mainmodule)
+ end
+end
+
+redef class AExternCodeBlock
+ # Is this Objective-C code?
+ fun is_objc : Bool do return language_name != null and
+ (language_name_lowered == "objc" or language_name_lowered.has_prefix("objc "))
+
+ # Is this Objective-C code for the body file?
+ fun is_objc_body : Bool do return language_name != null and
+ (language_name_lowered == "objc" or language_name_lowered == "objc body")
+
+ # Is this Objective-C code for the header file?
+ fun is_objc_header : Bool do return language_name != null and
+ (language_name_lowered == "objc header")
+end
+
+private class ObjCCompilationUnit
+ super CCompilationUnit
+
+ # Write this compilation unit to Objective-C source files
+ fun write_to_files(mmodule: MModule, compdir: String): ExternObjCFile
+ do
+ var base_name = "{mmodule.cname}._ffi"
+
+ var h_file = "{base_name}_m.h"
+ var guard = "{mmodule.cname.to_s.to_upper}_NIT_OBJC_H"
+ write_header_to_file(mmodule, compdir/h_file, new Array[String], guard)
+
+ var c_file = "{base_name}.m"
+ write_body_to_file(mmodule, compdir/c_file, ["\"{h_file}\""])
+
+ files.add compdir/c_file
+
+ mmodule.c_linker_options = "{mmodule.c_linker_options} -lobjc"
+
+ return new ExternObjCFile(compdir/c_file, mmodule)
+ end
+end
+
+# A Objective-C file
+class ExternObjCFile
+ super ExternFile
+
+ # Associated `MModule`
+ var mmodule: MModule
+
+ redef fun makefile_rule_name do return "{filename.basename(".m")}_m.o"
+ redef fun makefile_rule_content do
+ return "clang $(CFLAGS) -c {filename.basename("")} -o {makefile_rule_name}"
+ end
+ redef fun compiles_to_o_file do return true
+end
+
+# An Objective-C type
+class ForeignObjCType
+ super ForeignType
+
+ # Type name
+ var objc_type: String
+end
+
+redef class NitniCallback
+ # Compile this callback to be callable from Objective-C
+ fun compile_callback_to_objc(mmodule: MModule, mainmodule: MModule) do end
+end
+
+redef class MExplicitCall
+ redef fun compile_callback_to_objc(mmodule, mainmodule)
+ do
+ var mproperty = mproperty
+ assert mproperty isa MMethod
+
+ var objc_signature = mproperty.build_csignature(recv_mtype, mainmodule, null, short_signature, from_objc_call_context)
+ var ccall = mproperty.build_ccall(recv_mtype, mainmodule, null, long_signature, from_objc_call_context, null)
+ var fc = new CFunction(objc_signature)
+ fc.exprs.add ccall
+ mmodule.objc_file.add_local_function fc
+ end
+end
+
+# Calls withing Objective-C code
+private fun objc_call_context: ObjCCallContext do return once new ObjCCallContext
+
+# Calls from C to Objective-C
+private fun to_objc_call_context: ToObjCCallContext do return once new ToObjCCallContext
+
+# Calls from Objective-C to C
+private fun from_objc_call_context: FromObjCCallContext do return once new FromObjCCallContext
+
+private class ObjCCallContext
+ super CallContext
+
+ redef fun name_mtype(mtype)
+ do
+ if mtype isa MClassType then
+ var ftype = mtype.mclass.ftype
+ if ftype isa ForeignObjCType then
+ return ftype.objc_type
+ end
+ end
+
+ return mtype.cname
+ end
+end
+
+private class ToObjCCallContext
+ super ObjCCallContext
+
+ redef fun cast_to(mtype, name)
+ do
+ if mtype isa MClassType and mtype.mclass.ftype isa ForeignObjCType then
+ return "(void*)({name})"
+ else return name
+ end
+end
+
+private class FromObjCCallContext
+ super ObjCCallContext
+
+ redef fun cast_from(mtype, name)
+ do
+ if mtype isa MClassType and mtype.mclass.ftype isa ForeignObjCType then
+ return "({name_mtype(mtype)})({name})"
+ else return name
+ end
+end
import cached
import serialization_phase
import check_annotation
+import glsl_validation
redef class ToolContext
# FIXME: there is conflict in linex in nitc, so use this trick to force invocation
--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Copyright 2014 Alexis Laferrière <alexis.laf@xymus.net>
+#
+# 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 shader code within Nit modules using the tool _glslangValidator_
+#
+# For this phase to work, _glslangValidator_ must be in PATH. It can be
+# downloaded from https://www.khronos.org/opengles/sdk/tools/Reference-Compiler/
+module glsl_validation
+
+import literal
+
+redef class ToolContext
+ # Shader code validation phase
+ var glsl_validation_phase: Phase = new GLSLValidationPhase(self, [literal_phase])
+end
+
+private class GLSLValidationPhase
+ super Phase
+
+ # Annotation names
+
+ fun annot_name_vertex: String do return "glsl_vertex_shader"
+ fun annot_name_fragment: String do return "glsl_fragment_shader"
+
+ # TODO support more shader types as needed
+
+ # Is the tool _glsllangValidator_ in path?
+ var tool_is_in_path: nullable Bool = null
+
+ redef fun process_annotated_node(nstring, nat)
+ do
+ var annot_name = nat.n_atid.n_id.text
+ var is_vertex = annot_name == annot_name_vertex
+ var is_fragment = annot_name == annot_name_fragment
+
+ # Skip if we are not interested
+ if not is_vertex and not is_fragment then return
+
+ # Only applicable on strings
+ if not nstring isa AStringFormExpr then
+ toolcontext.error(nstring.location,
+ "Syntax error: only a string literal can be annotated as \"{annot_name}\".")
+ return
+ end
+
+ # Do not double check if tool is in path
+ var in_path = tool_is_in_path
+ if in_path != null then
+ if not in_path then return
+ else
+ # Is _glslangValidator_ installed?
+ var proc_which = new IProcess("which", "glslangValidator")
+ proc_which.wait
+ proc_which.close
+ var status = proc_which.status
+ in_path = status == 0
+ tool_is_in_path = in_path
+ if not in_path then
+ toolcontext.warning(nat.location, "glslvalidator",
+ "Warning: program \"glslangValidator\" not in PATH, cannot validate this shader.")
+ return
+ end
+ end
+
+ # Get the shader source
+ var shader = nstring.value
+ assert shader != null
+
+ # Copy the shader to a file
+ # TODO make it more portable
+ var tmp = "/tmp/"
+ var ext
+ if is_vertex then
+ ext = "vert"
+ else ext = "frag"
+ var path = tmp / "nit_shader." + ext
+
+ shader.write_to_file path
+
+ # Execute the validator
+ var proc_validator = new IProcess("glslangValidator", path)
+ proc_validator.wait
+ var lines = proc_validator.read_all.split('\n')
+ proc_validator.close
+
+ # Parse errors
+ var regex = "[A-Z]+: ([0-9]+):([0-9]+): (.*)".to_re
+ for line in lines do
+ var match = line.search(regex)
+
+ # Does it match an error?
+ # If not, then it should be the summary
+ if match != null then
+ var shader_line_no = match.subs[1].to_s.to_i
+ var msg = match.subs[2].to_s
+
+ var line_start = nstring.location.line_start + shader_line_no
+ var char_start = 0
+ var char_end = 0
+ var loc = new Location(nat.location.file,
+ line_start, line_start,
+ char_start, char_end)
+
+ toolcontext.warning(loc, "glslvalidator",
+ "Shader error on {msg}")
+ end
+ end
+ end
+end
if mdoc == null then mdoc = mclass.intro.mdoc
if mdoc != null then mdoc.fill_infobox(res)
+ if in_hierarchy == null then return res
+
if in_hierarchy.greaters.length > 1 then
var c = res.new_dropdown("hier", "super-classes")
for x in in_hierarchy.greaters do
var res = new HInfoBox(v, to_s)
res.href = href
if self isa MMethodDef then
- res.new_field("fun").append(mproperty.name).add msignature.linkto
+ if msignature != null then res.new_field("fun").append(mproperty.name).add msignature.linkto
else if self isa MAttributeDef then
- res.new_field("fun").append(mproperty.name).add static_mtype.linkto
+ if static_mtype != null then res.new_field("fun").append(mproperty.name).add static_mtype.linkto
else if self isa MVirtualTypeDef then
- res.new_field("add").append(mproperty.name).add bound.linkto
+ if bound != null then res.new_field("add").append(mproperty.name).add bound.linkto
else
res.new_field("wat?").append(mproperty.name)
end
redef fun check_errors
do
if dbg == null then
- super
+ return super
else
if messages.length > 0 then
message_sorter.sort(messages)
messages.clear
end
+ return not had_error
end
# -d
assert args.length == mpropdef.msignature.arity + 1 else debug("Invalid arity for {mpropdef}. {args.length} arguments given.")
# Look for the AST node that implements the property
- var mproperty = mpropdef.mproperty
- if self.modelbuilder.mpropdef2npropdef.has_key(mpropdef) then
- var npropdef = self.modelbuilder.mpropdef2npropdef[mpropdef]
- self.parameter_check(npropdef, mpropdef, args)
- if npropdef isa AMethPropdef then
- return npropdef.rt_call(self, mpropdef, args)
- else
- print "Error, invalid propdef to call at runtime !"
- return null
- end
- else if mproperty.is_root_init then
- var nclassdef = self.modelbuilder.mclassdef2nclassdef[mpropdef.mclassdef]
- self.parameter_check(nclassdef, mpropdef, args)
- return nclassdef.call(self, mpropdef, args)
+ var node = modelbuilder.mpropdef2node(mpropdef)
+ if node isa AMethPropdef then
+ self.parameter_check(node, mpropdef, args)
+ return node.rt_call(self, mpropdef, args)
+ else if node isa AClassdef then
+ self.parameter_check(node, mpropdef, args)
+ return node.call(self, mpropdef, args)
else
fatal("Fatal Error: method {mpropdef} not found in the AST")
abort
init_instance_primitive(self.true_instance)
self.false_instance = new PrimitiveInstance[Bool](mainmodule.bool_type, false)
init_instance_primitive(self.false_instance)
- self.null_instance = new MutableInstance(mainmodule.model.null_type)
+ self.null_instance = new PrimitiveInstance[nullable Object](mainmodule.model.null_type, null)
end
# Starts the interpreter on the main module of a program
# Subtype test in the context of the mainmodule
fun is_subtype(sub, sup: MType): Bool
do
- return sub.is_subtype(self.mainmodule, self.frame.arguments.first.mtype.as(MClassType), sup)
+ return sub.is_subtype(self.mainmodule, current_receiver_class, sup)
end
+ # Get a primitive method in the context of the main module
fun force_get_primitive_method(name: String, recv: MType): MMethod
do
assert recv isa MClassType
- return self.modelbuilder.force_get_primitive_method(self.frame.current_node, name, recv.mclass, self.mainmodule)
+ return self.modelbuilder.force_get_primitive_method(current_node, name, recv.mclass, self.mainmodule)
end
# Is a return executed?
return res
end
+ # Return a instance associated to a primitive class
+ # Current primitive classes are `Int`, `Bool`, and `String`
fun value_instance(object: Object): Instance
do
if object isa Int then
return b.to_s
end
+ # The current node, used to print errors, debug and stack-traces
+ fun current_node: nullable ANode
+ do
+ if frames.is_empty then return null
+ return frames.first.current_node
+ end
+
+ # The dynamic type of the current `self`
+ fun current_receiver_class: MClassType
+ do
+ return frames.first.arguments.first.mtype.as(MClassType)
+ end
+
# Exit the program with a message
fun fatal(message: String)
do
- if frames.is_empty then
+ var node = current_node
+ if node == null then
print message
else
- self.frame.current_node.fatal(self, message)
+ node.fatal(self, message)
end
exit(1)
end
# Debug on the current node
fun debug(message: String)
do
- if frames.is_empty then
+ var node = current_node
+ if node == null then
print message
else
- self.frame.current_node.debug(message)
+ node.debug(message)
end
end
assert args.length == mpropdef.msignature.arity + 1 else debug("Invalid arity for {mpropdef}. {args.length} arguments given.")
# Look for the AST node that implements the property
- var mproperty = mpropdef.mproperty
var val = mpropdef.constant_value
- if self.modelbuilder.mpropdef2npropdef.has_key(mpropdef) then
- var npropdef = self.modelbuilder.mpropdef2npropdef[mpropdef]
- self.parameter_check(npropdef, mpropdef, args)
- return npropdef.call(self, mpropdef, args)
- else if mproperty.is_root_init then
- var nclassdef = self.modelbuilder.mclassdef2nclassdef[mpropdef.mclassdef]
- self.parameter_check(nclassdef, mpropdef, args)
- return nclassdef.call(self, mpropdef, args)
+
+ var node = modelbuilder.mpropdef2node(mpropdef)
+ if node isa APropdef then
+ self.parameter_check(node, mpropdef, args)
+ return node.call(self, mpropdef, args)
+ else if node isa AClassdef then
+ self.parameter_check(node, mpropdef, args)
+ return node.call(self, mpropdef, args)
+ else if node != null then
+ fatal("Fatal Error: method {mpropdef} associated to unexpected AST node {node.location}")
+ abort
else if val != null then
return value_instance(val)
else
end
end
- # Generate type checks in the C code to check covariant parameters
+ # Execute type checks of covariant parameters
fun parameter_check(node: ANode, mpropdef: MMethodDef, args: Array[Instance])
do
var msignature = mpropdef.msignature
var origmtype = mpropdef.mproperty.intro.msignature.mparameters[i].mtype
if not origmtype.need_anchor then continue
+ #print "{mpropdef}: {mpropdef.mproperty.intro.msignature.mparameters[i]}"
+
# get the parameter type
var mtype = msignature.mparameters[i].mtype
var anchor = args.first.mtype.as(MClassType)
self.send(p, args)
else if p isa MAttribute then
assert recv isa MutableInstance
- recv.attributes[p] = arguments[i]
+ write_attribute(p, recv, arguments[i])
i += 1
else abort
end
var cds = mtype.collect_mclassdefs(self.mainmodule).to_a
self.mainmodule.linearize_mclassdefs(cds)
for cd in cds do
- if not self.modelbuilder.mclassdef2nclassdef.has_key(cd) then continue
- var n = self.modelbuilder.mclassdef2nclassdef[cd]
- for npropdef in n.n_propdefs do
- if npropdef isa AAttrPropdef then
- res.add(npropdef)
- end
- end
+ res.add_all(modelbuilder.collect_attr_propdef(cd))
end
cache[mtype] = res
return mainmodule.get_primitive_class(name)
end
- # This function determine the correct type according the reciever of the current definition (self).
+ # This function determines the correct type according to the receiver of the current propdef (self).
fun unanchor_type(mtype: MType): MType
do
- return mtype.anchor_to(self.mainmodule, self.frame.arguments.first.mtype.as(MClassType))
+ return mtype.anchor_to(self.mainmodule, current_receiver_class)
end
# Placebo instance used to mark internal error result when `null` already have a meaning.
# The real value encapsulated if the instance is primitive.
# Else aborts.
- fun val: Object do abort
+ fun val: nullable Object do abort
end
# A instance with attribute (standards objects)
# Special instance to handle primitives values (int, bool, etc.)
# The trick it just to encapsulate the <<real>> value
-class PrimitiveInstance[E: Object]
+class PrimitiveInstance[E]
super Instance
# The real value encapsulated
redef fun ==(o)
do
- if not o isa PrimitiveInstance[Object] then return false
+ if not o isa PrimitiveInstance[nullable Object] then return false
return self.val == o.val
end
redef fun eq_is(o)
do
- if not o isa PrimitiveInstance[Object] then return false
+ if not o isa PrimitiveInstance[nullable Object] then return false
return self.val.is_same_instance(o.val)
end
- redef fun to_s do return "{mtype}#{val.object_id}({val})"
+ redef fun to_s do return "{mtype}#{val.object_id}({val or else "null"})"
redef fun to_i do return val.as(Int)
return v.bool_instance(args[0].to_f.is_nan)
else if pname == "is_inf_extern" then
return v.bool_instance(args[0].to_f.is_inf != 0)
+ else if pname == "round" then
+ return v.float_instance(args[0].to_f.round)
end
else if cname == "NativeString" then
if pname == "new" then
else if pname == "atof" then
return v.float_instance(recvval.to_f)
end
+ else if cname == "String" then
+ var cs = v.send(v.force_get_primitive_method("to_cstring", args.first.mtype), [args.first])
+ var str = cs.val.to_s
+ if pname == "files" then
+ var res = new Array[Instance]
+ for f in str.files do res.add v.string_instance(f)
+ return v.array_instance(res, v.get_primitive_class("String").mclass_type)
+ end
else if pname == "calloc_string" then
return v.native_string_instance("!" * args[1].to_i)
else if cname == "NativeArray" then
else if pname == "length" then
return v.int_instance(recvval.length)
else if pname == "copy_to" then
- recvval.copy(0, args[2].to_i, args[1].val.as(Array[Instance]), 0)
+ recvval.copy_to(0, args[2].to_i, args[1].val.as(Array[Instance]), 0)
return null
end
else if cname == "NativeFile" then
end
end
-redef class AbstractArray[E]
- fun copy(start: Int, len: Int, dest: AbstractArray[E], new_start: Int)
- do
- self.copy_to(start, len, dest, new_start)
- end
-end
-
redef class AAttrPropdef
redef fun call(v, mpropdef, args)
do
--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Copyright 2012 Jean Privat <jean@pryen.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.
+
+# Loading of Nit source files
+module loader
+
+import modelbuilder_base
+
+redef class ToolContext
+ # Option --path
+ var opt_path = new OptionArray("Set include path for loaders (may be used more than once)", "-I", "--path")
+
+ # Option --only-metamodel
+ var opt_only_metamodel = new OptionBool("Stop after meta-model processing", "--only-metamodel")
+
+ # Option --only-parse
+ var opt_only_parse = new OptionBool("Only proceed to parse step of loaders", "--only-parse")
+
+ redef init
+ do
+ super
+ option_context.add_option(opt_path, opt_only_parse, opt_only_metamodel)
+ end
+end
+
+redef class ModelBuilder
+ redef init
+ do
+ super
+
+ # Setup the paths value
+ paths.append(toolcontext.opt_path.value)
+
+ var path_env = "NIT_PATH".environ
+ if not path_env.is_empty then
+ paths.append(path_env.split_with(':'))
+ end
+
+ var nit_dir = toolcontext.nit_dir
+ var libname = "{nit_dir}/lib"
+ if libname.file_exists then paths.add(libname)
+ end
+
+ # Load a bunch of modules.
+ # `modules` can contains filenames or module names.
+ # Imported modules are automatically loaded and modelized.
+ # The result is the corresponding model elements.
+ # Errors and warnings are printed with the toolcontext.
+ #
+ # Note: class and property model elements are not analysed.
+ fun parse(modules: Sequence[String]): Array[MModule]
+ do
+ var time0 = get_time
+ # Parse and recursively load
+ self.toolcontext.info("*** PARSE ***", 1)
+ var mmodules = new ArraySet[MModule]
+ for a in modules do
+ var nmodule = self.load_module(a)
+ if nmodule == null then continue # Skip error
+ # Load imported module
+ build_module_importation(nmodule)
+
+ mmodules.add(nmodule.mmodule.as(not null))
+ end
+ var time1 = get_time
+ self.toolcontext.info("*** END PARSE: {time1-time0} ***", 2)
+
+ self.toolcontext.check_errors
+
+ if toolcontext.opt_only_parse.value then
+ self.toolcontext.info("*** ONLY PARSE...", 1)
+ exit(0)
+ end
+
+ return mmodules.to_a
+ end
+
+ # The list of directories to search for top level modules
+ # The list is initially set with:
+ #
+ # * the toolcontext --path option
+ # * the NIT_PATH environment variable
+ # * `toolcontext.nit_dir`
+ # Path can be added (or removed) by the client
+ var paths = new Array[String]
+
+ # Like (and used by) `get_mmodule_by_name` but just return the ModulePath
+ fun search_mmodule_by_name(anode: nullable ANode, mgroup: nullable MGroup, name: String): nullable ModulePath
+ do
+ # First, look in groups
+ var c = mgroup
+ while c != null do
+ var dirname = c.filepath
+ if dirname == null then break # virtual group
+ if dirname.has_suffix(".nit") then break # singleton project
+
+ # Second, try the directory to find a file
+ var try_file = dirname + "/" + name + ".nit"
+ if try_file.file_exists then
+ var res = self.identify_file(try_file.simplify_path)
+ assert res != null
+ return res
+ end
+
+ # Third, try if the requested module is itself a group
+ try_file = dirname + "/" + name + "/" + name + ".nit"
+ if try_file.file_exists then
+ var res = self.identify_file(try_file.simplify_path)
+ assert res != null
+ return res
+ end
+
+ c = c.parent
+ end
+
+ # Look at some known directories
+ var lookpaths = self.paths
+
+ # Look in the directory of the group project also (even if not explicitly in the path)
+ if mgroup != null then
+ # path of the root group
+ var dirname = mgroup.mproject.root.filepath
+ if dirname != null then
+ dirname = dirname.join_path("..").simplify_path
+ if not lookpaths.has(dirname) and dirname.file_exists then
+ lookpaths = lookpaths.to_a
+ lookpaths.add(dirname)
+ end
+ end
+ end
+
+ var candidate = search_module_in_paths(anode.hot_location, name, lookpaths)
+
+ if candidate == null then
+ if mgroup != null then
+ error(anode, "Error: cannot find module {name} from {mgroup.name}. tried {lookpaths.join(", ")}")
+ else
+ error(anode, "Error: cannot find module {name}. tried {lookpaths.join(", ")}")
+ end
+ return null
+ end
+ return candidate
+ end
+
+ # Get a module by its short name; if required, the module is loaded, parsed and its hierarchies computed.
+ # If `mgroup` is set, then the module search starts from it up to the top level (see `paths`);
+ # if `mgroup` is null then the module is searched in the top level only.
+ # If no module exists or there is a name conflict, then an error on `anode` is displayed and null is returned.
+ fun get_mmodule_by_name(anode: nullable ANode, mgroup: nullable MGroup, name: String): nullable MModule
+ do
+ var path = search_mmodule_by_name(anode, mgroup, name)
+ if path == null then return null # Forward error
+ var res = self.load_module(path.filepath)
+ if res == null then return null # Forward error
+ # Load imported module
+ build_module_importation(res)
+ return res.mmodule.as(not null)
+ end
+
+ # Search a module `name` from path `lookpaths`.
+ # If found, the path of the file is returned
+ private fun search_module_in_paths(location: nullable Location, name: String, lookpaths: Collection[String]): nullable ModulePath
+ do
+ var candidate: nullable String = null
+ for dirname in lookpaths do
+ var try_file = (dirname + "/" + name + ".nit").simplify_path
+ if try_file.file_exists then
+ if candidate == null then
+ candidate = try_file
+ else if candidate != try_file then
+ # try to disambiguate conflicting modules
+ var abs_candidate = module_absolute_path(candidate)
+ var abs_try_file = module_absolute_path(try_file)
+ if abs_candidate != abs_try_file then
+ toolcontext.error(location, "Error: conflicting module file for {name}: {candidate} {try_file}")
+ end
+ end
+ end
+ try_file = (dirname + "/" + name + "/" + name + ".nit").simplify_path
+ if try_file.file_exists then
+ if candidate == null then
+ candidate = try_file
+ else if candidate != try_file then
+ # try to disambiguate conflicting modules
+ var abs_candidate = module_absolute_path(candidate)
+ var abs_try_file = module_absolute_path(try_file)
+ if abs_candidate != abs_try_file then
+ toolcontext.error(location, "Error: conflicting module file for {name}: {candidate} {try_file}")
+ end
+ end
+ end
+ end
+ if candidate == null then return null
+ return identify_file(candidate)
+ end
+
+ # Cache for `identify_file` by realpath
+ private var identified_files_by_path = new HashMap[String, nullable ModulePath]
+
+ # All the currently identified modules.
+ # See `identify_file`.
+ var identified_files = new Array[ModulePath]
+
+ # Identify a source file
+ # Load the associated project and groups if required
+ #
+ # Silently return `null` if `path` is not a valid module path.
+ fun identify_file(path: String): nullable ModulePath
+ do
+ # special case for not a nit file
+ if path.file_extension != "nit" then
+ # search dirless files in known -I paths
+ if path.dirname == "" then
+ var res = search_module_in_paths(null, path, self.paths)
+ if res != null then return res
+ end
+
+ # Found nothing? maybe it is a group...
+ var candidate = null
+ if path.file_exists then
+ var mgroup = get_mgroup(path)
+ if mgroup != null then
+ var owner_path = mgroup.filepath.join_path(mgroup.name + ".nit")
+ if owner_path.file_exists then candidate = owner_path
+ end
+ end
+
+ if candidate == null then
+ return null
+ end
+ path = candidate
+ end
+
+ # Fast track, the path is already known
+ var pn = path.basename(".nit")
+ var rp = module_absolute_path(path)
+ if identified_files_by_path.has_key(rp) then return identified_files_by_path[rp]
+
+ # Search for a group
+ var mgrouppath = path.join_path("..").simplify_path
+ var mgroup = get_mgroup(mgrouppath)
+
+ if mgroup == null then
+ # singleton project
+ var mproject = new MProject(pn, model)
+ mgroup = new MGroup(pn, mproject, null) # same name for the root group
+ mgroup.filepath = path
+ mproject.root = mgroup
+ toolcontext.info("found project `{pn}` at {path}", 2)
+ end
+
+ var res = new ModulePath(pn, path, mgroup)
+ mgroup.module_paths.add(res)
+
+ identified_files_by_path[rp] = res
+ identified_files.add(res)
+ return res
+ end
+
+ # Groups by path
+ private var mgroups = new HashMap[String, nullable MGroup]
+
+ # Return the mgroup associated to a directory path.
+ # If the directory is not a group null is returned.
+ fun get_mgroup(dirpath: String): nullable MGroup
+ do
+ var rdp = module_absolute_path(dirpath)
+ if mgroups.has_key(rdp) then
+ return mgroups[rdp]
+ end
+
+ # Hack, a group is determined by:
+ # * the presence of a honomymous nit file
+ # * the fact that the directory is named `src`
+ var pn = rdp.basename(".nit")
+ var mp = dirpath.join_path(pn + ".nit").simplify_path
+
+ var dirpath2 = dirpath
+ if not mp.file_exists then
+ if pn == "src" then
+ # With a src directory, the group name is the name of the parent directory
+ dirpath2 = rdp.dirname
+ pn = dirpath2.basename("")
+ else
+ return null
+ end
+ end
+
+ # check parent directory
+ var parentpath = dirpath.join_path("..").simplify_path
+ var parent = get_mgroup(parentpath)
+
+ var mgroup
+ if parent == null then
+ # no parent, thus new project
+ var mproject = new MProject(pn, model)
+ mgroup = new MGroup(pn, mproject, null) # same name for the root group
+ mproject.root = mgroup
+ toolcontext.info("found project `{mproject}` at {dirpath}", 2)
+ else
+ mgroup = new MGroup(pn, parent.mproject, parent)
+ toolcontext.info("found sub group `{mgroup.full_name}` at {dirpath}", 2)
+ end
+ var readme = dirpath2.join_path("README.md")
+ if not readme.file_exists then readme = dirpath2.join_path("README")
+ if readme.file_exists then
+ var mdoc = new MDoc
+ var s = new IFStream.open(readme)
+ while not s.eof do
+ mdoc.content.add(s.read_line)
+ end
+ mgroup.mdoc = mdoc
+ mdoc.original_mentity = mgroup
+ end
+ mgroup.filepath = dirpath
+ mgroups[rdp] = mgroup
+ return mgroup
+ end
+
+ # Force the identification of all ModulePath of the group and sub-groups.
+ fun visit_group(mgroup: MGroup) do
+ var p = mgroup.filepath
+ for f in p.files do
+ var fp = p/f
+ var g = get_mgroup(fp)
+ if g != null then visit_group(g)
+ identify_file(fp)
+ end
+ end
+
+ # Transform relative paths (starting with '../') into absolute paths
+ private fun module_absolute_path(path: String): String do
+ return getcwd.join_path(path).simplify_path
+ end
+
+ # Try to load a module AST using a path.
+ # Display an error if there is a problem (IO / lexer / parser) and return null
+ fun load_module_ast(filename: String): nullable AModule
+ do
+ if filename.file_extension != "nit" then
+ self.toolcontext.error(null, "Error: file {filename} is not a valid nit module.")
+ return null
+ end
+ if not filename.file_exists then
+ self.toolcontext.error(null, "Error: file {filename} not found.")
+ return null
+ end
+
+ self.toolcontext.info("load module {filename}", 2)
+
+ # Load the file
+ var file = new IFStream.open(filename)
+ var lexer = new Lexer(new SourceFile(filename, file))
+ var parser = new Parser(lexer)
+ var tree = parser.parse
+ file.close
+
+ # Handle lexer and parser error
+ var nmodule = tree.n_base
+ if nmodule == null then
+ var neof = tree.n_eof
+ assert neof isa AError
+ error(neof, neof.message)
+ return null
+ end
+
+ return nmodule
+ end
+
+ # Try to load a module using a path.
+ # Display an error if there is a problem (IO / lexer / parser) and return null.
+ # Note: usually, you do not need this method, use `get_mmodule_by_name` instead.
+ #
+ # The MModule is created however, the importation is not performed,
+ # therefore you should call `build_module_importation`.
+ fun load_module(filename: String): nullable AModule
+ do
+ # Look for the module
+ var file = identify_file(filename)
+ if file == null then
+ toolcontext.error(null, "Error: cannot find module `{filename}`.")
+ return null
+ end
+
+ # Already known and loaded? then return it
+ var mmodule = file.mmodule
+ if mmodule != null then
+ return mmodule2nmodule[mmodule]
+ end
+
+ # Load it manually
+ var nmodule = load_module_ast(file.filepath)
+ if nmodule == null then return null # forward error
+
+ # build the mmodule and load imported modules
+ mmodule = build_a_mmodule(file.mgroup, file.name, nmodule)
+
+ if mmodule == null then return null # forward error
+
+ # Update the file information
+ file.mmodule = mmodule
+
+ return nmodule
+ end
+
+ # Injection of a new module without source.
+ # Used by the interpreter.
+ fun load_rt_module(parent: nullable MModule, nmodule: AModule, mod_name: String): nullable AModule
+ do
+ # Create the module
+
+ var mgroup = null
+ if parent != null then mgroup = parent.mgroup
+ var mmodule = new MModule(model, mgroup, mod_name, nmodule.location)
+ nmodule.mmodule = mmodule
+ nmodules.add(nmodule)
+ self.mmodule2nmodule[mmodule] = nmodule
+
+ if parent!= null then
+ var imported_modules = new Array[MModule]
+ imported_modules.add(parent)
+ mmodule.set_visibility_for(parent, intrude_visibility)
+ mmodule.set_imported_mmodules(imported_modules)
+ else
+ build_module_importation(nmodule)
+ end
+
+ return nmodule
+ end
+
+ # Visit the AST and create the `MModule` object
+ private fun build_a_mmodule(mgroup: nullable MGroup, mod_name: String, nmodule: AModule): nullable MModule
+ do
+ # Check the module name
+ var decl = nmodule.n_moduledecl
+ if decl == null then
+ #warning(nmodule, "Warning: Missing 'module' keyword") #FIXME: NOT YET FOR COMPATIBILITY
+ else
+ var decl_name = decl.n_name.n_id.text
+ if decl_name != mod_name then
+ error(decl.n_name, "Error: module name missmatch; declared {decl_name} file named {mod_name}")
+ end
+ end
+
+ # Create the module
+ var mmodule = new MModule(model, mgroup, mod_name, nmodule.location)
+ nmodule.mmodule = mmodule
+ nmodules.add(nmodule)
+ self.mmodule2nmodule[mmodule] = nmodule
+
+ if decl != null then
+ var ndoc = decl.n_doc
+ if ndoc != null then
+ var mdoc = ndoc.to_mdoc
+ mmodule.mdoc = mdoc
+ mdoc.original_mentity = mmodule
+ else
+ advice(decl, "missing-doc", "Documentation warning: Undocumented module `{mmodule}`")
+ end
+ end
+
+ return mmodule
+ end
+
+ # Analyze the module importation and fill the module_importation_hierarchy
+ #
+ # Unless you used `load_module`, the importation is already done and this method does a no-op.
+ fun build_module_importation(nmodule: AModule)
+ do
+ if nmodule.is_importation_done then return
+ nmodule.is_importation_done = true
+ var mmodule = nmodule.mmodule.as(not null)
+ var stdimport = true
+ var imported_modules = new Array[MModule]
+ for aimport in nmodule.n_imports do
+ stdimport = false
+ if not aimport isa AStdImport then
+ continue
+ end
+ var mgroup = mmodule.mgroup
+ if aimport.n_name.n_quad != null then mgroup = null # Start from top level
+ for grp in aimport.n_name.n_path do
+ var path = search_mmodule_by_name(grp, mgroup, grp.text)
+ if path == null then return # Skip error
+ mgroup = path.mgroup
+ end
+ var mod_name = aimport.n_name.n_id.text
+ var sup = self.get_mmodule_by_name(aimport.n_name, mgroup, mod_name)
+ if sup == null then continue # Skip error
+ aimport.mmodule = sup
+ imported_modules.add(sup)
+ var mvisibility = aimport.n_visibility.mvisibility
+ if mvisibility == protected_visibility then
+ error(aimport.n_visibility, "Error: only properties can be protected.")
+ return
+ end
+ if sup == mmodule then
+ error(aimport.n_name, "Error: Dependency loop in module {mmodule}.")
+ end
+ if sup.in_importation < mmodule then
+ error(aimport.n_name, "Error: Dependency loop between modules {mmodule} and {sup}.")
+ return
+ end
+ mmodule.set_visibility_for(sup, mvisibility)
+ end
+ if stdimport then
+ var mod_name = "standard"
+ var sup = self.get_mmodule_by_name(nmodule, null, mod_name)
+ if sup != null then # Skip error
+ imported_modules.add(sup)
+ mmodule.set_visibility_for(sup, public_visibility)
+ end
+ end
+ self.toolcontext.info("{mmodule} imports {imported_modules.join(", ")}", 3)
+ mmodule.set_imported_mmodules(imported_modules)
+
+ # Force standard to be public if imported
+ for sup in mmodule.in_importation.greaters do
+ if sup.name == "standard" then
+ mmodule.set_visibility_for(sup, public_visibility)
+ end
+ end
+
+ # TODO: Correctly check for useless importation
+ # It is even doable?
+ var directs = mmodule.in_importation.direct_greaters
+ for nim in nmodule.n_imports do
+ if not nim isa AStdImport then continue
+ var im = nim.mmodule
+ if im == null then continue
+ if directs.has(im) then continue
+ # This generates so much noise that it is simpler to just comment it
+ #warning(nim, "Warning: possible useless importation of {im}")
+ end
+ end
+
+ # All the loaded modules
+ var nmodules = new Array[AModule]
+
+ # Register the nmodule associated to each mmodule
+ # FIXME: why not refine the `MModule` class with a nullable attribute?
+ var mmodule2nmodule = new HashMap[MModule, AModule]
+end
+
+# File-system location of a module (file) that is identified but not always loaded.
+class ModulePath
+ # The name of the module
+ # (it's the basename of the filepath)
+ var name: String
+
+ # The human path of the module
+ var filepath: String
+
+ # The group (and the project) of the possible module
+ var mgroup: MGroup
+
+ # The loaded module (if any)
+ var mmodule: nullable MModule = null
+
+ redef fun to_s do return filepath
+end
+
+redef class MGroup
+ # Modules paths associated with the group
+ var module_paths = new Array[ModulePath]
+
+ # Is the group interesting for a final user?
+ #
+ # Groups are mandatory in the model but for simple projects they are not
+ # always interesting.
+ #
+ # A interesting group has, at least, one of the following true:
+ #
+ # * it has 2 modules or more
+ # * it has a subgroup
+ # * it has a documentation
+ fun is_interesting: Bool
+ do
+ return module_paths.length > 1 or mmodules.length > 1 or not in_nesting.direct_smallers.is_empty or mdoc != null
+ end
+
+end
+
+redef class AStdImport
+ # The imported module once determined
+ var mmodule: nullable MModule = null
+end
+
+redef class AModule
+ # The associated MModule once build by a `ModelBuilder`
+ var mmodule: nullable MModule
+ # Flag that indicate if the importation is already completed
+ var is_importation_done: Bool = false
+end
var file: nullable SourceFile
var line_start: Int
var line_end: Int
+
+ # Start of this location on `line_start`
+ #
+ # A `column_start` of 1 means the first column or character.
+ #
+ # If `column_start == 0` this location concerns the whole line.
+ #
+ # Require: `column_start >= 0`
var column_start: Int
+
var column_end: Int
# The index in the start character in the source
while line_end+1 < string.length and string.chars[line_end+1] != '\n' and string.chars[line_end+1] != '\r' do
line_end += 1
end
- var lstart = string.substring(line_start, l.column_start - 1)
+ var lstart
+ if l.column_start > 0 then
+ lstart = string.substring(line_start, l.column_start - 1)
+ else
+ lstart = ""
+ end
var cend
if i != l.line_end then
cend = line_end - line_start + 1
end
if csv then
- var csvh = new CSVDocument
+ var csvh = new CsvDocument
+ csvh.format = new CsvFormat('"', ';', "\n")
csvh.header = ["povr", "ovr", "pext", "ext", "pspe", "spe", "prep", "rep", "eq"]
for mclass in mclasses do
var povr = mclass.is_pure_overrider(vis).object_id
var prep = mclass.is_pure_replacer(vis).object_id
var rep = mclass.is_replacer(vis).object_id
var eq = mclass.is_equal(vis).object_id
- csvh.add_line(povr, ovr, pext, ext, pspe, spe, prep, rep, eq)
+ csvh.add_record(povr, ovr, pext, ext, pspe, spe, prep, rep, eq)
end
csvh.save("{out}/inheritance_behaviour.csv")
end
end
# Export the metric set in CSV format
- fun to_csv: CSVDocument do
- var csv = new CSVDocument
+ fun to_csv: CsvDocument do
+ var csv = new CsvDocument
+
+ csv.format = new CsvFormat('"', ';', "\n")
# set csv headers
csv.header.add("entry")
line.add("n/a")
end
end
- csv.lines.add(line)
+ csv.records.add(line)
end
return csv
end
# The documentation associated to the entity
var mdoc: nullable MDoc is writable
+ # The documentation associated to the entity or their main nested entity.
+ #
+ # MProject fall-back to their root MGroup
+ # MGroup fall-back to their default_mmodule
+ # Other entities do not fall-back
+ #
+ # One may use `MDoc::original_mentity` to retrieve the original
+ # source of the documentation.
+ fun mdoc_or_fallback: nullable MDoc do return mdoc
+
# Is the entity deprecated?
#
# Used for warnings and in documentation.
# All known modules
var mmodules = new Array[MModule]
- # placebo for old module nesting hierarchy.
- # where mainmodule < mainmodule::nestedmodule
- #
- # TODO REMOVE, rely on mgroup instead
- var mmodule_nesting_hierarchy = new POSet[MModule]
-
# Full module importation hierarchy including private or nested links.
var mmodule_importation_hierarchy = new POSet[MModule]
# Return `null` if the group has no default module or if the default
# module is not loaded.
var default_mmodule: nullable MModule = null
+
+ redef fun mdoc_or_fallback
+ do
+ if mdoc != null then return mdoc
+ if default_mmodule == null then return null
+ return default_mmodule.mdoc_or_fallback
+ end
end
# A Nit module is usually associated with a Nit source file.
# Alias for `name`
redef fun to_s do return self.name
- # placebo for old module nesting hierarchy
- # The view of the module in the `model.mmodule_nesting_hierarchy`
- #
- # TODO REMOVE, rely on mgroup instead
- var in_nesting: POSetElement[MModule] is noinit
-
# The view of the module in the `model.mmodule_importation_hierarchy`
var in_importation: POSetElement[MModule] is noinit
do
model.mmodules_by_name.add_one(name, self)
model.mmodules.add(self)
- self.in_nesting = model.mmodule_nesting_hierarchy.add_node(self)
if mgroup != null then
mgroup.mmodules.add(self)
if mgroup.name == name then
# placebo for old module nesting hierarchy
var direct_owner = mgroup.default_mmodule
if direct_owner == self then
- # The module is the new owner of its own group, thus adopt the other modules
- for m in mgroup.mmodules do
- if m == self then continue
- model.mmodule_nesting_hierarchy.add_edge(self, m)
- end
# The potential owner is the default_mmodule of the parent group
if mgroup.parent != null then direct_owner = mgroup.parent.default_mmodule
end
- if direct_owner != self and direct_owner != null then
- model.mmodule_nesting_hierarchy.add_edge(direct_owner, self)
- end
end
self.in_importation = model.mmodule_importation_hierarchy.add_node(self)
end
var msg = "Fatal Error: more than one primitive class {name}:"
for c in cla do msg += " {c.full_name}"
print msg
- exit(1)
+ #exit(1)
end
return cla.first
end
self.mparameters = mparametertypes
var mclass_type = new MGenericType(self, mparametertypes)
self.mclass_type = mclass_type
- self.get_mtype_cache.add(mclass_type)
+ self.get_mtype_cache[mparametertypes] = mclass_type
else
self.mclass_type = new MClassType(self)
end
do
assert mtype_arguments.length == self.arity
if self.arity == 0 then return self.mclass_type
- for t in self.get_mtype_cache do
- if t.arguments == mtype_arguments then
- return t
- end
- end
- var res = new MGenericType(self, mtype_arguments)
- self.get_mtype_cache.add res
+ var res = get_mtype_cache.get_or_null(mtype_arguments)
+ if res != null then return res
+ res = new MGenericType(self, mtype_arguments)
+ self.get_mtype_cache[mtype_arguments.to_a] = res
return res
end
- private var get_mtype_cache = new Array[MGenericType]
+ private var get_mtype_cache = new HashMap[Array[MType], MGenericType]
end
do
var sub = self
if sub == sup then return true
+
+ #print "1.is {sub} a {sup}? ===="
+
if anchor == null then
assert not sub.need_anchor
assert not sup.need_anchor
else
+ # First, resolve the formal types to the simplest equivalent forms in the receiver
assert sub.can_resolve_for(anchor, null, mmodule)
+ sub = sub.lookup_fixed(mmodule, anchor)
assert sup.can_resolve_for(anchor, null, mmodule)
- end
-
- # First, resolve the formal types to a common version in the receiver
- # The trick here is that fixed formal type will be associated to the bound
- # And unfixed formal types will be associated to a canonical formal type.
- if sub isa MParameterType or sub isa MVirtualType then
- assert anchor != null
- sub = sub.resolve_for(anchor.mclass.mclass_type, anchor, mmodule, false)
- end
- if sup isa MParameterType or sup isa MVirtualType then
- assert anchor != null
- sup = sup.resolve_for(anchor.mclass.mclass_type, anchor, mmodule, false)
+ sup = sup.lookup_fixed(mmodule, anchor)
end
# Does `sup` accept null or not?
end
# Now the case of direct null and nullable is over.
- # A unfixed formal type can only accept itself
- if sup isa MParameterType or sup isa MVirtualType then
- return sub == sup
- end
-
# If `sub` is a formal type, then it is accepted if its bound is accepted
- if sub isa MParameterType or sub isa MVirtualType then
+ while sub isa MParameterType or sub isa MVirtualType do
+ #print "3.is {sub} a {sup}?"
+
+ # A unfixed formal type can only accept itself
+ if sub == sup then return true
+
assert anchor != null
- sub = sub.anchor_to(mmodule, anchor)
+ sub = sub.lookup_bound(mmodule, anchor)
+
+ #print "3.is {sub} a {sup}?"
# Manage the second layer of null/nullable
if sub isa MNullableType then
return sup_accept_null
end
end
+ #print "4.is {sub} a {sup}? <- no more resolution"
assert sub isa MClassType # It is the only remaining type
+ # A unfixed formal type can only accept itself
+ if sup isa MParameterType or sup isa MVirtualType then
+ return false
+ end
+
if sup isa MNullType then
# `sup` accepts only null
return false
# types to their bounds.
#
# Example
+ #
# class A end
# class B super A end
# class X end
# super G[B]
# redef type U: Y
# end
+ #
# Map[T,U] anchor_to H #-> Map[B,Y]
#
# Explanation of the example:
# In Nit, for each super-class of a type, there is a equivalent super-type.
#
# Example:
+ #
+ # ~~~nitish
# class G[T, U] end
# class H[V] super G[V, Bool] end
+ #
# H[Int] supertype_to G #-> G[Int, Bool]
+ # ~~~
#
# REQUIRE: `super_mclass` is a super-class of `self`
# REQUIRE: `self.need_anchor implies anchor != null and self.can_resolve_for(anchor, null, mmodule)`
#
# ## Example 1
#
- # class G[E] end
- # class H[F] super G[F] end
- # class X[Z] end
+ # ~~~
+ # class G[E] end
+ # class H[F] super G[F] end
+ # class X[Z] end
+ # ~~~
#
# * Array[E].resolve_for(H[Int]) #-> Array[Int]
# * Array[E].resolve_for(G[Z], X[Int]) #-> Array[Z]
#
# ## Example 2
#
- # class A[E]
- # fun foo(e:E):E is abstract
- # end
- # class B super A[Int] end
+ # ~~~
+ # class A[E]
+ # fun foo(e:E):E is abstract
+ # end
+ # class B super A[Int] end
+ # ~~~
#
# The signature on foo is (e: E): E
# If we resolve the signature for B, we get (e:Int):Int
#
# ## Example 3
#
- # class A[E]
- # fun foo(e:E) is abstract
- # end
- # class B[F]
- # var a: A[Array[F]]
- # fun bar do a.foo(x) # <- x is here
- # end
+ # ~~~nitish
+ # class A[E]
+ # fun foo(e:E):E is abstract
+ # end
+ # class C[F]
+ # var a: A[Array[F]]
+ # fun bar do a.foo(x) # <- x is here
+ # end
+ # ~~~
#
# The first question is: is foo available on `a`?
#
# The static type of a is `A[Array[F]]`, that is an open type.
# in order to find a method `foo`, whe must look at a resolved type.
#
- # A[Array[F]].anchor_to(B[nullable Object]) #-> A[Array[nullable Object]]
+ # A[Array[F]].anchor_to(C[nullable Object]) #-> A[Array[nullable Object]]
#
# the method `foo` exists in `A[Array[nullable Object]]`, therefore `foo` exists for `a`.
#
#
# the signature of `foo` is `foo(e:E)`, thus we must resolve the type E
#
- # E.resolve_for(A[Array[F]],B[nullable Object]) #-> Array[F]
+ # E.resolve_for(A[Array[F]],C[nullable Object]) #-> Array[F]
#
# The resolution can be done because `E` make sense for the class A (see `can_resolve_for`)
#
# ENSURE: `not self.need_anchor implies result == self`
fun resolve_for(mtype: MType, anchor: nullable MClassType, mmodule: MModule, cleanup_virtual: Bool): MType is abstract
+ # Resolve formal type to its verbatim bound.
+ # If the type is not formal, just return self
+ #
+ # The result is returned exactly as declared in the "type" property (verbatim).
+ # So it could be another formal type.
+ #
+ # In case of conflict, the method aborts.
+ fun lookup_bound(mmodule: MModule, resolved_receiver: MType): MType do return self
+
+ # Resolve the formal type to its simplest equivalent form.
+ #
+ # Formal types are either free or fixed.
+ # When it is fixed, it means that it is equivalent with a simpler type.
+ # When a formal type is free, it means that it is only equivalent with itself.
+ # This method return the most simple equivalent type of `self`.
+ #
+ # This method is mainly used for subtype test in order to sanely compare fixed.
+ #
+ # By default, return self.
+ # See the redefinitions for specific behavior in each kind of type.
+ fun lookup_fixed(mmodule: MModule, resolved_receiver: MType): MType do return self
+
# Can the type be resolved?
#
# In order to resolve open types, the formal types must make sence.
# class B[F]
# end
#
- # * E.can_resolve_for(A[Int]) #-> true, E make sense in A
- # * E.can_resolve_for(B[Int]) #-> false, E does not make sense in B
- # * B[E].can_resolve_for(A[F], B[Object]) #-> true,
- # B[E] is a red hearing only the E is important,
- # E make sense in A
+ # ~~~nitish
+ # E.can_resolve_for(A[Int]) #-> true, E make sense in A
+ #
+ # E.can_resolve_for(B[Int]) #-> false, E does not make sense in B
+ #
+ # B[E].can_resolve_for(A[F], B[Object]) #-> true,
+ # # B[E] is a red hearing only the E is important,
+ # # E make sense in A
+ # ~~~
#
# REQUIRE: `anchor != null implies not anchor.need_anchor`
# REQUIRE: `mtype.need_anchor implies anchor != null and mtype.can_resolve_for(anchor, null, mmodule)`
redef fun collect_mclasses(mmodule)
do
+ if collect_mclasses_last_module == mmodule then return collect_mclasses_last_module_cache
assert not self.need_anchor
var cache = self.collect_mclasses_cache
if not cache.has_key(mmodule) then
self.collect_things(mmodule)
end
- return cache[mmodule]
+ var res = cache[mmodule]
+ collect_mclasses_last_module = mmodule
+ collect_mclasses_last_module_cache = res
+ return res
end
+ private var collect_mclasses_last_module: nullable MModule = null
+ private var collect_mclasses_last_module_cache: Set[MClass] is noinit
+
redef fun collect_mtypes(mmodule)
do
assert not self.need_anchor
# The property associated with the type.
# Its the definitions of this property that determine the bound or the virtual type.
- var mproperty: MProperty
+ var mproperty: MVirtualTypeProp
redef fun model do return self.mproperty.intro_mclassdef.mmodule.model
- # Lookup the bound for a given resolved_receiver
- # The result may be a other virtual type (or a parameter type)
- #
- # The result is returned exactly as declared in the "type" property (verbatim).
- #
- # In case of conflict, the method aborts.
- fun lookup_bound(mmodule: MModule, resolved_receiver: MType): MType
+ redef fun lookup_bound(mmodule: MModule, resolved_receiver: MType): MType
+ do
+ return lookup_single_definition(mmodule, resolved_receiver).bound.as(not null)
+ end
+
+ private fun lookup_single_definition(mmodule: MModule, resolved_receiver: MType): MVirtualTypeDef
do
assert not resolved_receiver.need_anchor
var props = self.mproperty.lookup_definitions(mmodule, resolved_receiver)
if props.is_empty then
abort
else if props.length == 1 then
- return props.first.as(MVirtualTypeDef).bound.as(not null)
+ return props.first
end
var types = new ArraySet[MType]
+ var res = props.first
for p in props do
- types.add(p.as(MVirtualTypeDef).bound.as(not null))
+ types.add(p.bound.as(not null))
+ if not res.is_fixed then res = p
end
if types.length == 1 then
- return types.first
+ return res
end
abort
end
- # Is the virtual type fixed for a given resolved_receiver?
- fun is_fixed(mmodule: MModule, resolved_receiver: MType): Bool
+ # A VT is fixed when:
+ # * the VT is (re-)defined with the annotation `is fixed`
+ # * the VT is (indirectly) bound to an enum class (see `enum_kind`) since there is no subtype possible
+ # * the receiver is an enum class since there is no subtype possible
+ redef fun lookup_fixed(mmodule: MModule, resolved_receiver: MType): MType
do
assert not resolved_receiver.need_anchor
- var props = self.mproperty.lookup_definitions(mmodule, resolved_receiver)
- if props.is_empty then
- abort
- end
- for p in props do
- if p.as(MVirtualTypeDef).is_fixed then return true
- end
- return false
+ resolved_receiver = resolved_receiver.as_notnullable
+ assert resolved_receiver isa MClassType # It is the only remaining type
+
+ var prop = lookup_single_definition(mmodule, resolved_receiver)
+ var res = prop.bound.as(not null)
+
+ # Recursively lookup the fixed result
+ res = res.lookup_fixed(mmodule, resolved_receiver)
+
+ # 1. For a fixed VT, return the resolved bound
+ if prop.is_fixed then return res
+
+ # 2. For a enum boud, return the bound
+ if res isa MClassType and res.mclass.kind == enum_kind then return res
+
+ # 3. for a enum receiver return the bound
+ if resolved_receiver.mclass.kind == enum_kind then return res
+
+ return self
end
redef fun resolve_for(mtype, anchor, mmodule, cleanup_virtual)
do
+ if not cleanup_virtual then return self
assert can_resolve_for(mtype, anchor, mmodule)
# self is a virtual type declared (or inherited) in mtype
# The point of the function it to get the bound of the virtual type that make sense for mtype
# But because mtype is maybe a virtual/formal type, we need to get a real receiver first
#print "{class_name}: {self}/{mtype}/{anchor}?"
- var resolved_reciever
+ var resolved_receiver
if mtype.need_anchor then
assert anchor != null
- resolved_reciever = mtype.resolve_for(anchor, null, mmodule, true)
+ resolved_receiver = mtype.resolve_for(anchor, null, mmodule, true)
else
- resolved_reciever = mtype
+ resolved_receiver = mtype
end
# Now, we can get the bound
- var verbatim_bound = lookup_bound(mmodule, resolved_reciever)
+ var verbatim_bound = lookup_bound(mmodule, resolved_receiver)
# The bound is exactly as declared in the "type" property, so we must resolve it again
var res = verbatim_bound.resolve_for(mtype, anchor, mmodule, cleanup_virtual)
- #print "{class_name}: {self}/{mtype}/{anchor} -> {self}/{resolved_receiver}/{anchor} -> {verbatim_bound}/{mtype}/{anchor} -> {res}"
-
- # What to return here? There is a bunch a special cases:
- # If 'cleanup_virtual' we must return the resolved type, since we cannot return self
- if cleanup_virtual then return res
- # If the receiver is a intern class, then the virtual type cannot be redefined since there is no possible subclass. self is just fixed. so simply return the resolution
- if resolved_reciever isa MNullableType then resolved_reciever = resolved_reciever.mtype
- if resolved_reciever.as(MClassType).mclass.kind == enum_kind then return res
- # If the resolved type isa MVirtualType, it means that self was bound to it, and cannot be unbound. self is just fixed. so return the resolution.
- if res isa MVirtualType then return res
- # If we are final, just return the resolution
- if is_fixed(mmodule, resolved_reciever) then return res
- # If the resolved type isa intern class, then there is no possible valid redefinition in any potential subclass. self is just fixed. so simply return the resolution
- if res isa MClassType and res.mclass.kind == enum_kind then return res
- # TODO: What if bound to a MParameterType?
- # Note that Nullable types can always be redefined by the non nullable version, so there is no specific case on it.
- # If anything apply, then `self' cannot be resolved, so return self
- return self
+ return res
end
redef fun can_resolve_for(mtype, anchor, mmodule)
# directly to the parameter types of the super-classes.
#
# Example:
+#
# class A[E]
# fun e: E is abstract
# end
# class B[F]
# super A[Array[F]]
# end
+#
# In the class definition B[F], `F` is a valid type but `E` is not.
# However, `self.e` is a valid method call, and the signature of `e` is
# declared `e: E`.
redef fun to_s do return name
- # Resolve the bound for a given resolved_receiver
- # The result may be a other virtual type (or a parameter type)
- fun lookup_bound(mmodule: MModule, resolved_receiver: MType): MType
+ redef fun lookup_bound(mmodule: MModule, resolved_receiver: MType): MType
do
assert not resolved_receiver.need_anchor
+ resolved_receiver = resolved_receiver.as_notnullable
+ assert resolved_receiver isa MClassType # It is the only remaining type
var goalclass = self.mclass
+ if resolved_receiver.mclass == goalclass then
+ return resolved_receiver.arguments[self.rank]
+ end
var supertypes = resolved_receiver.collect_mtypes(mmodule)
for t in supertypes do
if t.mclass == goalclass then
abort
end
+ # A PT is fixed when:
+ # * Its bound is a enum class (see `enum_kind`).
+ # The PT is just useless, but it is still a case.
+ # * More usually, the `resolved_receiver` is a subclass of `self.mclass`,
+ # so it is necessarily fixed in a `super` clause, either with a normal type
+ # or with another PT.
+ # See `resolve_for` for examples about related issues.
+ redef fun lookup_fixed(mmodule: MModule, resolved_receiver: MType): MType
+ do
+ assert not resolved_receiver.need_anchor
+ resolved_receiver = resolved_receiver.as_notnullable
+ assert resolved_receiver isa MClassType # It is the only remaining type
+ var res = self.resolve_for(resolved_receiver.mclass.mclass_type, resolved_receiver, mmodule, false)
+ return res
+ end
+
redef fun resolve_for(mtype, anchor, mmodule, cleanup_virtual)
do
assert can_resolve_for(mtype, anchor, mmodule)
resolved_receiver = anchor.arguments[resolved_receiver.rank]
if resolved_receiver isa MNullableType then resolved_receiver = resolved_receiver.mtype
end
- assert resolved_receiver isa MClassType
+ assert resolved_receiver isa MClassType # It is the only remaining type
# Eh! The parameter is in the current class.
# So we return the corresponding argument, no mater what!
return self.mtype.can_resolve_for(mtype, anchor, mmodule)
end
+ # Efficiently returns `mtype.lookup_fixed(mmodule, resolved_receiver).as_nullable`
+ redef fun lookup_fixed(mmodule, resolved_receiver)
+ do
+ var t = mtype.lookup_fixed(mmodule, resolved_receiver)
+ if t == mtype then return self
+ return t.as_nullable
+ end
+
redef fun depth do return self.mtype.depth
redef fun length do return self.mtype.length
import model_base
private import more_collections
import poset
+import mdoc
# A Nit project, that encompass a product
class MProject
# MProject are always roots of the concerns hierarchy
redef fun parent_concern do return null
+
+ redef fun mdoc_or_fallback
+ do
+ if mdoc != null then return mdoc
+ return root.mdoc_or_fallback
+ end
end
# A group of modules in a project
return mclasses
end
- fun in_nesting_intro_mclasses(min_visibility: MVisibility): Set[MClass] do
- var res = new HashSet[MClass]
- for mmodule in in_nesting.greaters do
- for mclass in mmodule.filter_intro_mclasses(min_visibility) do
- if mclass.visibility < min_visibility then continue
- res.add mclass
- end
- end
- return res
- end
-
- fun in_nesting_redef_mclasses(min_visibility: MVisibility): Set[MClass] do
- var res = new HashSet[MClass]
- for mmodule in self.in_nesting.greaters do
- for mclass in mmodule.filter_redef_mclasses(min_visibility) do
- if mclass.visibility < min_visibility then continue
- res.add mclass
- end
- end
- return res
- end
-
- fun in_nesting_intro_mclassdefs(min_visibility: MVisibility): Set[MClassDef] do
- var res = new HashSet[MClassDef]
- for mmodule in in_nesting.greaters do
- res.add_all mmodule.intro_mclassdefs(min_visibility)
- end
- return res
- end
-
- fun in_nesting_redef_mclassdefs(min_visibility: MVisibility): Set[MClassDef] do
- var res = new HashSet[MClassDef]
- for mmodule in self.in_nesting.greaters do
- res.add_all mmodule.redef_mclassdefs(min_visibility)
- end
- return res
- end
-
redef fun concern_rank is cached do
var max = 0
for p in in_importation.direct_greaters do
end
return max + 1
end
+
+ # Find all mmodules nested in `self` if `self` is the default module of a `MGroup`.
+ fun nested_mmodules: Array[MModule] do
+ var res = new Array[MModule]
+ var mgroup = mgroup
+ if mgroup == null or self != mgroup.default_mmodule then return res
+ for mmodule in mgroup.mmodules do
+ if mmodule == self then continue
+ res.add mmodule
+ end
+ for nested in mgroup.in_nesting.direct_smallers do
+ var default = nested.default_mmodule
+ if default == null then continue
+ res.add default
+ end
+ return res
+ end
end
redef class MClass
#
# Comparison is made with the formula:
#
-# a.concern_rank + a.booster_rank <=> b.concern_rank + b.booster_ran
+# ~~~nitish
+# a.concern_rank + a.booster_rank <=> b.concern_rank + b.booster_ran
+# ~~~
#
# If both `a` and `b` have the same ranking,
# ordering is based on lexicographic comparison of `a.name` and `b.name`
# See the License for the specific language governing permissions and
# limitations under the License.
-# Load nit source files and build the associated model
-#
-# FIXME better doc
-#
-# FIXME split this module into submodules
-# FIXME add missing error checks
module modelbuilder
-import model
+import loader
import phase
private import more_collections
###
redef class ToolContext
- # Option --path
- var opt_path = new OptionArray("Set include path for loaders (may be used more than once)", "-I", "--path")
-
- # Option --only-metamodel
- var opt_only_metamodel = new OptionBool("Stop after meta-model processing", "--only-metamodel")
-
- # Option --only-parse
- var opt_only_parse = new OptionBool("Only proceed to parse step of loaders", "--only-parse")
-
# Option --ignore-visibility
var opt_ignore_visibility = new OptionBool("Do not check, and produce errors, on visibility issues.", "--ignore-visibility")
redef init
do
super
- option_context.add_option(opt_path, opt_only_parse, opt_only_metamodel, opt_ignore_visibility)
+ option_context.add_option(opt_ignore_visibility)
end
- # The modelbuilder 1-to-1 associated with the toolcontext
- fun modelbuilder: ModelBuilder do return modelbuilder_real.as(not null)
-
- private var modelbuilder_real: nullable ModelBuilder = null
-
# Combine module to make a single one if required.
fun make_main_module(mmodules: Array[MModule]): MModule
do
end
-# A model builder knows how to load nit source files and build the associated model
-class ModelBuilder
- # The model where new modules, classes and properties are added
- var model: Model
-
- # The toolcontext used to control the interaction with the user (getting options and displaying messages)
- var toolcontext: ToolContext
-
+redef class ModelBuilder
# Run phases on all loaded modules
fun run_phases
do
end
end
- # Instantiate a modelbuilder for a model and a toolcontext
- # Important, the options of the toolcontext must be correctly set (parse_option already called)
- init
- do
- assert toolcontext.modelbuilder_real == null
- toolcontext.modelbuilder_real = self
-
- # Setup the paths value
- paths.append(toolcontext.opt_path.value)
-
- var path_env = "NIT_PATH".environ
- if not path_env.is_empty then
- paths.append(path_env.split_with(':'))
- end
-
- var nit_dir = toolcontext.nit_dir
- var libname = "{nit_dir}/lib"
- if libname.file_exists then paths.add(libname)
- end
-
- # Load a bunch of modules.
- # `modules` can contains filenames or module names.
- # Imported modules are automatically loaded and modelized.
- # The result is the corresponding model elements.
- # Errors and warnings are printed with the toolcontext.
- #
- # Note: class and property model element are not analysed.
- fun parse(modules: Sequence[String]): Array[MModule]
- do
- var time0 = get_time
- # Parse and recursively load
- self.toolcontext.info("*** PARSE ***", 1)
- var mmodules = new ArraySet[MModule]
- for a in modules do
- var nmodule = self.load_module(a)
- if nmodule == null then continue # Skip error
- mmodules.add(nmodule.mmodule.as(not null))
- end
- var time1 = get_time
- self.toolcontext.info("*** END PARSE: {time1-time0} ***", 2)
-
- self.toolcontext.check_errors
-
- if toolcontext.opt_only_parse.value then
- self.toolcontext.info("*** ONLY PARSE...", 1)
- exit(0)
- end
-
- return mmodules.to_a
- end
-
- # Return a class named `name` visible by the module `mmodule`.
- # Visibility in modules is correctly handled.
- # If no such a class exists, then null is returned.
- # If more than one class exists, then an error on `anode` is displayed and null is returned.
- # FIXME: add a way to handle class name conflict
- fun try_get_mclass_by_name(anode: ANode, mmodule: MModule, name: String): nullable MClass
- do
- var classes = model.get_mclasses_by_name(name)
- if classes == null then
- return null
- end
-
- var res: nullable MClass = null
- for mclass in classes do
- if not mmodule.in_importation <= mclass.intro_mmodule then continue
- if not mmodule.is_visible(mclass.intro_mmodule, mclass.visibility) then continue
- if res == null then
- res = mclass
- else
- error(anode, "Ambigous class name '{name}'; conflict between {mclass.full_name} and {res.full_name}")
- return null
- end
- end
- return res
- end
-
- # Return a property named `name` on the type `mtype` visible in the module `mmodule`.
- # Visibility in modules is correctly handled.
- # Protected properties are returned (it is up to the caller to check and reject protected properties).
- # If no such a property exists, then null is returned.
- # If more than one property exists, then an error on `anode` is displayed and null is returned.
- # FIXME: add a way to handle property name conflict
- fun try_get_mproperty_by_name2(anode: ANode, mmodule: MModule, mtype: MType, name: String): nullable MProperty
- do
- var props = self.model.get_mproperties_by_name(name)
- if props == null then
- return null
- end
-
- var cache = self.try_get_mproperty_by_name2_cache[mmodule, mtype, name]
- if cache != null then return cache
-
- var res: nullable MProperty = null
- var ress: nullable Array[MProperty] = null
- for mprop in props do
- if not mtype.has_mproperty(mmodule, mprop) then continue
- if not mmodule.is_visible(mprop.intro_mclassdef.mmodule, mprop.visibility) then continue
-
- # new-factories are invisible outside of the class
- if mprop isa MMethod and mprop.is_new and (not mtype isa MClassType or mprop.intro_mclassdef.mclass != mtype.mclass) then
- continue
- end
-
- if res == null then
- res = mprop
- continue
- end
-
- # Two global properties?
- # First, special case for init, keep the most specific ones
- if res isa MMethod and mprop isa MMethod and res.is_init and mprop.is_init then
- var restype = res.intro_mclassdef.bound_mtype
- var mproptype = mprop.intro_mclassdef.bound_mtype
- if mproptype.is_subtype(mmodule, null, restype) then
- # found a most specific constructor, so keep it
- res = mprop
- continue
- end
- end
-
- # Ok, just keep all prop in the ress table
- if ress == null then
- ress = new Array[MProperty]
- ress.add(res)
- end
- ress.add(mprop)
- end
-
- # There is conflict?
- if ress != null and res isa MMethod and res.is_init then
- # special case forinit again
- var restype = res.intro_mclassdef.bound_mtype
- var ress2 = new Array[MProperty]
- for mprop in ress do
- var mproptype = mprop.intro_mclassdef.bound_mtype
- if not restype.is_subtype(mmodule, null, mproptype) then
- ress2.add(mprop)
- else if not mprop isa MMethod or not mprop.is_init then
- ress2.add(mprop)
- end
- end
- if ress2.is_empty then
- ress = null
- else
- ress = ress2
- ress.add(res)
- end
- end
-
- if ress != null then
- assert ress.length > 1
- var s = new Array[String]
- for mprop in ress do s.add mprop.full_name
- self.error(anode, "Ambigous property name '{name}' for {mtype}; conflict between {s.join(" and ")}")
- end
-
- self.try_get_mproperty_by_name2_cache[mmodule, mtype, name] = res
- return res
- end
-
- private var try_get_mproperty_by_name2_cache = new HashMap3[MModule, MType, String, nullable MProperty]
-
-
- # Alias for try_get_mproperty_by_name2(anode, mclassdef.mmodule, mclassdef.mtype, name)
- fun try_get_mproperty_by_name(anode: ANode, mclassdef: MClassDef, name: String): nullable MProperty
- do
- return try_get_mproperty_by_name2(anode, mclassdef.mmodule, mclassdef.bound_mtype, name)
- end
-
- # The list of directories to search for top level modules
- # The list is initially set with :
- # * the toolcontext --path option
- # * the NIT_PATH environment variable
- # * `toolcontext.nit_dir`
- # Path can be added (or removed) by the client
- var paths = new Array[String]
-
- # Like (an used by) `get_mmodule_by_name` but just return the ModulePath
- private fun search_mmodule_by_name(anode: ANode, mgroup: nullable MGroup, name: String): nullable ModulePath
- do
- # First, look in groups
- var c = mgroup
- while c != null do
- var dirname = c.filepath
- if dirname == null then break # virtual group
- if dirname.has_suffix(".nit") then break # singleton project
-
- # Second, try the directory to find a file
- var try_file = dirname + "/" + name + ".nit"
- if try_file.file_exists then
- var res = self.identify_file(try_file.simplify_path)
- assert res != null
- return res
- end
-
- # Third, try if the requested module is itself a group
- try_file = dirname + "/" + name + "/" + name + ".nit"
- if try_file.file_exists then
- var res = self.identify_file(try_file.simplify_path)
- assert res != null
- return res
- end
-
- c = c.parent
- end
-
- # Look at some known directories
- var lookpaths = self.paths
-
- # Look in the directory of the group project also (even if not explicitely in the path)
- if mgroup != null then
- # path of the root group
- var dirname = mgroup.mproject.root.filepath
- if dirname != null then
- dirname = dirname.join_path("..").simplify_path
- if not lookpaths.has(dirname) and dirname.file_exists then
- lookpaths = lookpaths.to_a
- lookpaths.add(dirname)
- end
- end
- end
-
- var candidate = search_module_in_paths(anode.hot_location, name, lookpaths)
-
- if candidate == null then
- if mgroup != null then
- error(anode, "Error: cannot find module {name} from {mgroup.name}. tried {lookpaths.join(", ")}")
- else
- error(anode, "Error: cannot find module {name}. tried {lookpaths.join(", ")}")
- end
- return null
- end
- return candidate
- end
-
- # Get a module by its short name; if required, the module is loaded, parsed and its hierarchies computed.
- # If `mgroup` is set, then the module search starts from it up to the top level (see `paths`);
- # if `mgroup` is null then the module is searched in the top level only.
- # If no module exists or there is a name conflict, then an error on `anode` is displayed and null is returned.
- fun get_mmodule_by_name(anode: ANode, mgroup: nullable MGroup, name: String): nullable MModule
- do
- var path = search_mmodule_by_name(anode, mgroup, name)
- if path == null then return null # Forward error
- var res = self.load_module(path.filepath)
- if res == null then return null # Forward error
- return res.mmodule.as(not null)
- end
-
- # Search a module `name` from path `lookpaths`.
- # If found, the path of the file is returned
- private fun search_module_in_paths(location: nullable Location, name: String, lookpaths: Collection[String]): nullable ModulePath
- do
- var candidate: nullable String = null
- for dirname in lookpaths do
- var try_file = (dirname + "/" + name + ".nit").simplify_path
- if try_file.file_exists then
- if candidate == null then
- candidate = try_file
- else if candidate != try_file then
- # try to disambiguate conflicting modules
- var abs_candidate = module_absolute_path(candidate)
- var abs_try_file = module_absolute_path(try_file)
- if abs_candidate != abs_try_file then
- toolcontext.error(location, "Error: conflicting module file for {name}: {candidate} {try_file}")
- end
- end
- end
- try_file = (dirname + "/" + name + "/" + name + ".nit").simplify_path
- if try_file.file_exists then
- if candidate == null then
- candidate = try_file
- else if candidate != try_file then
- # try to disambiguate conflicting modules
- var abs_candidate = module_absolute_path(candidate)
- var abs_try_file = module_absolute_path(try_file)
- if abs_candidate != abs_try_file then
- toolcontext.error(location, "Error: conflicting module file for {name}: {candidate} {try_file}")
- end
- end
- end
- end
- if candidate == null then return null
- return identify_file(candidate)
- end
-
- # cache for `identify_file` by realpath
- private var identified_files = new HashMap[String, nullable ModulePath]
-
- # Identify a source file
- # Load the associated project and groups if required
- private fun identify_file(path: String): nullable ModulePath
- do
- # special case for not a nit file
- if path.file_extension != "nit" then
- # search in known -I paths
- var res = search_module_in_paths(null, path, self.paths)
- if res != null then return res
-
- # Found nothins? maybe it is a group...
- var candidate = null
- if path.file_exists then
- var mgroup = get_mgroup(path)
- if mgroup != null then
- var owner_path = mgroup.filepath.join_path(mgroup.name + ".nit")
- if owner_path.file_exists then candidate = owner_path
- end
- end
-
- if candidate == null then
- toolcontext.error(null, "Error: cannot find module `{path}`.")
- return null
- end
- path = candidate
- end
-
- # Fast track, the path is already known
- var pn = path.basename(".nit")
- var rp = module_absolute_path(path)
- if identified_files.has_key(rp) then return identified_files[rp]
-
- # Search for a group
- var mgrouppath = path.join_path("..").simplify_path
- var mgroup = get_mgroup(mgrouppath)
-
- if mgroup == null then
- # singleton project
- var mproject = new MProject(pn, model)
- mgroup = new MGroup(pn, mproject, null) # same name for the root group
- mgroup.filepath = path
- mproject.root = mgroup
- toolcontext.info("found project `{pn}` at {path}", 2)
- end
-
- var res = new ModulePath(pn, path, mgroup)
- mgroup.module_paths.add(res)
-
- identified_files[rp] = res
- return res
- end
-
- # groups by path
- private var mgroups = new HashMap[String, nullable MGroup]
-
- # return the mgroup associated to a directory path
- # if the directory is not a group null is returned
- private fun get_mgroup(dirpath: String): nullable MGroup
- do
- var rdp = module_absolute_path(dirpath)
- if mgroups.has_key(rdp) then
- return mgroups[rdp]
- end
-
- # Hack, a group is determined by:
- # * the presence of a honomymous nit file
- # * the fact that the directory is named `src`
- var pn = rdp.basename(".nit")
- var mp = dirpath.join_path(pn + ".nit").simplify_path
-
- var dirpath2 = dirpath
- if not mp.file_exists then
- if pn == "src" then
- # With a src directory, the group name is the name of the parent directory
- dirpath2 = rdp.dirname
- pn = dirpath2.basename("")
- else
- return null
- end
- end
-
- # check parent directory
- var parentpath = dirpath.join_path("..").simplify_path
- var parent = get_mgroup(parentpath)
-
- var mgroup
- if parent == null then
- # no parent, thus new project
- var mproject = new MProject(pn, model)
- mgroup = new MGroup(pn, mproject, null) # same name for the root group
- mproject.root = mgroup
- toolcontext.info("found project `{mproject}` at {dirpath}", 2)
- else
- mgroup = new MGroup(pn, parent.mproject, parent)
- toolcontext.info("found sub group `{mgroup.full_name}` at {dirpath}", 2)
- end
- var readme = dirpath2.join_path("README.md")
- if not readme.file_exists then readme = dirpath2.join_path("README")
- if readme.file_exists then
- var mdoc = new MDoc
- var s = new IFStream.open(readme)
- while not s.eof do
- mdoc.content.add(s.read_line)
- end
- mgroup.mdoc = mdoc
- mdoc.original_mentity = mgroup
- end
- mgroup.filepath = dirpath
- mgroups[rdp] = mgroup
- return mgroup
- end
-
- # Transform relative paths (starting with '../') into absolute paths
- private fun module_absolute_path(path: String): String do
- return getcwd.join_path(path).simplify_path
- end
-
- # Try to load a module AST using a path.
- # Display an error if there is a problem (IO / lexer / parser) and return null
- fun load_module_ast(filename: String): nullable AModule
- do
- if filename.file_extension != "nit" then
- self.toolcontext.error(null, "Error: file {filename} is not a valid nit module.")
- return null
- end
- if not filename.file_exists then
- self.toolcontext.error(null, "Error: file {filename} not found.")
- return null
- end
-
- self.toolcontext.info("load module {filename}", 2)
-
- # Load the file
- var file = new IFStream.open(filename)
- var lexer = new Lexer(new SourceFile(filename, file))
- var parser = new Parser(lexer)
- var tree = parser.parse
- file.close
-
- # Handle lexer and parser error
- var nmodule = tree.n_base
- if nmodule == null then
- var neof = tree.n_eof
- assert neof isa AError
- error(neof, neof.message)
- return null
- end
-
- return nmodule
- end
-
- # Try to load a module and its imported modules using a path.
- # Display an error if there is a problem (IO / lexer / parser / importation) and return null
- # Note: usually, you do not need this method, use `get_mmodule_by_name` instead.
- fun load_module(filename: String): nullable AModule
- do
- # Look for the module
- var file = identify_file(filename)
- if file == null then return null # forward error
-
- # Already known and loaded? then return it
- var mmodule = file.mmodule
- if mmodule != null then
- return mmodule2nmodule[mmodule]
- end
-
- # Load it manually
- var nmodule = load_module_ast(file.filepath)
- if nmodule == null then return null # forward error
-
- # build the mmodule and load imported modules
- mmodule = build_a_mmodule(file.mgroup, file.name, nmodule)
-
- if mmodule == null then return null # forward error
-
- # Update the file information
- file.mmodule = mmodule
-
- # Load imported module
- build_module_importation(nmodule)
-
- return nmodule
- end
-
- # Injection of a new module without source.
- # Used by the interpreted
- fun load_rt_module(parent: nullable MModule, nmodule: AModule, mod_name: String): nullable AModule
- do
- # Create the module
-
- var mgroup = null
- if parent != null then mgroup = parent.mgroup
- var mmodule = new MModule(model, mgroup, mod_name, nmodule.location)
- nmodule.mmodule = mmodule
- nmodules.add(nmodule)
- self.mmodule2nmodule[mmodule] = nmodule
-
- if parent!= null then
- var imported_modules = new Array[MModule]
- imported_modules.add(parent)
- mmodule.set_visibility_for(parent, intrude_visibility)
- mmodule.set_imported_mmodules(imported_modules)
- else
- build_module_importation(nmodule)
- end
-
- return nmodule
- end
-
- # Visit the AST and create the `MModule` object
- private fun build_a_mmodule(mgroup: nullable MGroup, mod_name: String, nmodule: AModule): nullable MModule
- do
- # Check the module name
- var decl = nmodule.n_moduledecl
- if decl == null then
- #warning(nmodule, "Warning: Missing 'module' keyword") #FIXME: NOT YET FOR COMPATIBILITY
- else
- var decl_name = decl.n_name.n_id.text
- if decl_name != mod_name then
- error(decl.n_name, "Error: module name missmatch; declared {decl_name} file named {mod_name}")
- end
- end
-
- # Create the module
- var mmodule = new MModule(model, mgroup, mod_name, nmodule.location)
- nmodule.mmodule = mmodule
- nmodules.add(nmodule)
- self.mmodule2nmodule[mmodule] = nmodule
-
- if decl != null then
- var ndoc = decl.n_doc
- if ndoc != null then
- var mdoc = ndoc.to_mdoc
- mmodule.mdoc = mdoc
- mdoc.original_mentity = mmodule
- else
- advice(decl, "missing-doc", "Documentation warning: Undocumented module `{mmodule}`")
- end
- end
-
- return mmodule
- end
-
- # Analysis the module importation and fill the module_importation_hierarchy
- private fun build_module_importation(nmodule: AModule)
- do
- if nmodule.is_importation_done then return
- nmodule.is_importation_done = true
- var mmodule = nmodule.mmodule.as(not null)
- var stdimport = true
- var imported_modules = new Array[MModule]
- for aimport in nmodule.n_imports do
- stdimport = false
- if not aimport isa AStdImport then
- continue
- end
- var mgroup = mmodule.mgroup
- if aimport.n_name.n_quad != null then mgroup = null # Start from top level
- for grp in aimport.n_name.n_path do
- var path = search_mmodule_by_name(grp, mgroup, grp.text)
- if path == null then return # Skip error
- mgroup = path.mgroup
- end
- var mod_name = aimport.n_name.n_id.text
- var sup = self.get_mmodule_by_name(aimport.n_name, mgroup, mod_name)
- if sup == null then continue # Skip error
- aimport.mmodule = sup
- imported_modules.add(sup)
- var mvisibility = aimport.n_visibility.mvisibility
- if mvisibility == protected_visibility then
- error(aimport.n_visibility, "Error: only properties can be protected.")
- return
- end
- if sup == mmodule then
- error(aimport.n_name, "Error: Dependency loop in module {mmodule}.")
- end
- if sup.in_importation < mmodule then
- error(aimport.n_name, "Error: Dependency loop between modules {mmodule} and {sup}.")
- return
- end
- mmodule.set_visibility_for(sup, mvisibility)
- end
- if stdimport then
- var mod_name = "standard"
- var sup = self.get_mmodule_by_name(nmodule, null, mod_name)
- if sup != null then # Skip error
- imported_modules.add(sup)
- mmodule.set_visibility_for(sup, public_visibility)
- end
- end
- self.toolcontext.info("{mmodule} imports {imported_modules.join(", ")}", 3)
- mmodule.set_imported_mmodules(imported_modules)
-
- # Force standard to be public if imported
- for sup in mmodule.in_importation.greaters do
- if sup.name == "standard" then
- mmodule.set_visibility_for(sup, public_visibility)
- end
- end
-
- # TODO: Correctly check for useless importation
- # It is even doable?
- var directs = mmodule.in_importation.direct_greaters
- for nim in nmodule.n_imports do
- if not nim isa AStdImport then continue
- var im = nim.mmodule
- if im == null then continue
- if directs.has(im) then continue
- # This generates so much noise that it is simpler to just comment it
- #warning(nim, "Warning: possible useless importation of {im}")
- end
- end
-
- # All the loaded modules
- var nmodules = new Array[AModule]
-
- # Register the nmodule associated to each mmodule
- # FIXME: why not refine the `MModule` class with a nullable attribute?
- var mmodule2nmodule = new HashMap[MModule, AModule]
-
- # Helper function to display an error on a node.
- # Alias for `self.toolcontext.error(n.hot_location, text)`
- fun error(n: ANode, text: String)
- do
- self.toolcontext.error(n.hot_location, text)
- end
-
- # Helper function to display a warning on a node.
- # Alias for: `self.toolcontext.warning(n.hot_location, text)`
- fun warning(n: ANode, tag, text: String)
- do
- self.toolcontext.warning(n.hot_location, tag, text)
- end
-
- # Helper function to display an advice on a node.
- # Alias for: `self.toolcontext.advice(n.hot_location, text)`
- fun advice(n: ANode, tag, text: String)
- do
- self.toolcontext.advice(n.hot_location, tag, text)
- end
-
- # Force to get the primitive method named `name` on the type `recv` or do a fatal error on `n`
- fun force_get_primitive_method(n: nullable ANode, name: String, recv: MClass, mmodule: MModule): MMethod
- do
- var res = mmodule.try_get_primitive_method(name, recv)
- if res == null then
- var l = null
- if n != null then l = n.hot_location
- self.toolcontext.fatal_error(l, "Fatal Error: {recv} must have a property named {name}.")
- abort
- end
- return res
- end
-end
-
-# placeholder to a module file identified but not always loaded in a project
-private class ModulePath
- # The name of the module
- # (it's the basename of the filepath)
- var name: String
-
- # The human path of the module
- var filepath: String
-
- # The group (and the project) of the possible module
- var mgroup: MGroup
-
- # The loaded module (if any)
- var mmodule: nullable MModule = null
-
- redef fun to_s do return filepath
-end
-
-redef class MGroup
- # modules paths associated with the group
- private var module_paths = new Array[ModulePath]
-end
-
-redef class AStdImport
- # The imported module once determined
- var mmodule: nullable MModule = null
-end
-
-redef class AModule
- # The associated MModule once build by a `ModelBuilder`
- var mmodule: nullable MModule
- # Flag that indicate if the importation is already completed
- var is_importation_done: Bool = false
-end
-
-redef class AVisibility
- # The visibility level associated with the AST node class
- fun mvisibility: MVisibility is abstract
-end
-redef class AIntrudeVisibility
- redef fun mvisibility do return intrude_visibility
-end
-redef class APublicVisibility
- redef fun mvisibility do return public_visibility
-end
-redef class AProtectedVisibility
- redef fun mvisibility do return protected_visibility
-end
-redef class APrivateVisibility
- redef fun mvisibility do return private_visibility
-end
-
-redef class ADoc
- private var mdoc_cache: nullable MDoc
- fun to_mdoc: MDoc
- do
- var res = mdoc_cache
- if res != null then return res
- res = new MDoc
- for c in n_comment do
- var text = c.text
- if text.length < 2 then
- res.content.add ""
- continue
- end
- assert text.chars[0] == '#'
- if text.chars[1] == ' ' then
- text = text.substring_from(2) # eat starting `#` and space
- else
- text = text.substring_from(1) # eat atarting `#` only
- end
- if text.chars.last == '\n' then text = text.substring(0, text.length-1) # drop \n
- res.content.add(text)
- end
- mdoc_cache = res
- return res
- end
end
--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Copyright 2012 Jean Privat <jean@pryen.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.
+
+# Load nit source files and build the associated model
+#
+# FIXME better doc
+#
+# FIXME split this module into submodules
+# FIXME add missing error checks
+module modelbuilder_base
+
+import model
+import toolcontext
+import parser
+
+private import more_collections
+
+###
+
+redef class ToolContext
+
+ # The modelbuilder 1-to-1 associated with the toolcontext
+ fun modelbuilder: ModelBuilder do return modelbuilder_real.as(not null)
+
+ private var modelbuilder_real: nullable ModelBuilder = null
+
+end
+
+# A model builder knows how to load nit source files and build the associated model
+class ModelBuilder
+ # The model where new modules, classes and properties are added
+ var model: Model
+
+ # The toolcontext used to control the interaction with the user (getting options and displaying messages)
+ var toolcontext: ToolContext
+
+ # Instantiate a modelbuilder for a model and a toolcontext
+ # Important, the options of the toolcontext must be correctly set (parse_option already called)
+ init
+ do
+ assert toolcontext.modelbuilder_real == null
+ toolcontext.modelbuilder_real = self
+ end
+
+ # Return a class named `name` visible by the module `mmodule`.
+ # Visibility in modules is correctly handled.
+ # If no such a class exists, then null is returned.
+ # If more than one class exists, then an error on `anode` is displayed and null is returned.
+ # FIXME: add a way to handle class name conflict
+ fun try_get_mclass_by_name(anode: ANode, mmodule: MModule, name: String): nullable MClass
+ do
+ var classes = model.get_mclasses_by_name(name)
+ if classes == null then
+ return null
+ end
+
+ var res: nullable MClass = null
+ for mclass in classes do
+ if not mmodule.in_importation <= mclass.intro_mmodule then continue
+ if not mmodule.is_visible(mclass.intro_mmodule, mclass.visibility) then continue
+ if res == null then
+ res = mclass
+ else
+ error(anode, "Ambigous class name '{name}'; conflict between {mclass.full_name} and {res.full_name}")
+ return null
+ end
+ end
+ return res
+ end
+
+ # Return a property named `name` on the type `mtype` visible in the module `mmodule`.
+ # Visibility in modules is correctly handled.
+ # Protected properties are returned (it is up to the caller to check and reject protected properties).
+ # If no such a property exists, then null is returned.
+ # If more than one property exists, then an error on `anode` is displayed and null is returned.
+ # FIXME: add a way to handle property name conflict
+ fun try_get_mproperty_by_name2(anode: ANode, mmodule: MModule, mtype: MType, name: String): nullable MProperty
+ do
+ var props = self.model.get_mproperties_by_name(name)
+ if props == null then
+ return null
+ end
+
+ var cache = self.try_get_mproperty_by_name2_cache[mmodule, mtype, name]
+ if cache != null then return cache
+
+ var res: nullable MProperty = null
+ var ress: nullable Array[MProperty] = null
+ for mprop in props do
+ if not mtype.has_mproperty(mmodule, mprop) then continue
+ if not mmodule.is_visible(mprop.intro_mclassdef.mmodule, mprop.visibility) then continue
+
+ # new-factories are invisible outside of the class
+ if mprop isa MMethod and mprop.is_new and (not mtype isa MClassType or mprop.intro_mclassdef.mclass != mtype.mclass) then
+ continue
+ end
+
+ if res == null then
+ res = mprop
+ continue
+ end
+
+ # Two global properties?
+ # First, special case for init, keep the most specific ones
+ if res isa MMethod and mprop isa MMethod and res.is_init and mprop.is_init then
+ var restype = res.intro_mclassdef.bound_mtype
+ var mproptype = mprop.intro_mclassdef.bound_mtype
+ if mproptype.is_subtype(mmodule, null, restype) then
+ # found a most specific constructor, so keep it
+ res = mprop
+ continue
+ end
+ end
+
+ # Ok, just keep all prop in the ress table
+ if ress == null then
+ ress = new Array[MProperty]
+ ress.add(res)
+ end
+ ress.add(mprop)
+ end
+
+ # There is conflict?
+ if ress != null and res isa MMethod and res.is_init then
+ # special case forinit again
+ var restype = res.intro_mclassdef.bound_mtype
+ var ress2 = new Array[MProperty]
+ for mprop in ress do
+ var mproptype = mprop.intro_mclassdef.bound_mtype
+ if not restype.is_subtype(mmodule, null, mproptype) then
+ ress2.add(mprop)
+ else if not mprop isa MMethod or not mprop.is_init then
+ ress2.add(mprop)
+ end
+ end
+ if ress2.is_empty then
+ ress = null
+ else
+ ress = ress2
+ ress.add(res)
+ end
+ end
+
+ if ress != null then
+ assert ress.length > 1
+ var s = new Array[String]
+ for mprop in ress do s.add mprop.full_name
+ self.error(anode, "Ambigous property name '{name}' for {mtype}; conflict between {s.join(" and ")}")
+ end
+
+ self.try_get_mproperty_by_name2_cache[mmodule, mtype, name] = res
+ return res
+ end
+
+ private var try_get_mproperty_by_name2_cache = new HashMap3[MModule, MType, String, nullable MProperty]
+
+
+ # Alias for try_get_mproperty_by_name2(anode, mclassdef.mmodule, mclassdef.mtype, name)
+ fun try_get_mproperty_by_name(anode: ANode, mclassdef: MClassDef, name: String): nullable MProperty
+ do
+ return try_get_mproperty_by_name2(anode, mclassdef.mmodule, mclassdef.bound_mtype, name)
+ end
+
+ # Helper function to display an error on a node.
+ # Alias for `self.toolcontext.error(n.hot_location, text)`
+ fun error(n: nullable ANode, text: String)
+ do
+ var l = null
+ if n != null then l = n.hot_location
+ self.toolcontext.error(l, text)
+ end
+
+ # Helper function to display a warning on a node.
+ # Alias for: `self.toolcontext.warning(n.hot_location, text)`
+ fun warning(n: nullable ANode, tag, text: String)
+ do
+ var l = null
+ if n != null then l = n.hot_location
+ self.toolcontext.warning(l, tag, text)
+ end
+
+ # Helper function to display an advice on a node.
+ # Alias for: `self.toolcontext.advice(n.hot_location, text)`
+ fun advice(n: nullable ANode, tag, text: String)
+ do
+ var l = null
+ if n != null then l = n.hot_location
+ self.toolcontext.advice(l, tag, text)
+ end
+
+ # Force to get the primitive method named `name` on the type `recv` or do a fatal error on `n`
+ fun force_get_primitive_method(n: nullable ANode, name: String, recv: MClass, mmodule: MModule): MMethod
+ do
+ var res = mmodule.try_get_primitive_method(name, recv)
+ if res == null then
+ var l = null
+ if n != null then l = n.hot_location
+ self.toolcontext.fatal_error(l, "Fatal Error: {recv} must have a property named {name}.")
+ abort
+ end
+ return res
+ end
+end
+
+redef class AVisibility
+ # The visibility level associated with the AST node class
+ fun mvisibility: MVisibility is abstract
+end
+redef class AIntrudeVisibility
+ redef fun mvisibility do return intrude_visibility
+end
+redef class APublicVisibility
+ redef fun mvisibility do return public_visibility
+end
+redef class AProtectedVisibility
+ redef fun mvisibility do return protected_visibility
+end
+redef class APrivateVisibility
+ redef fun mvisibility do return private_visibility
+end
+
+redef class ADoc
+ private var mdoc_cache: nullable MDoc
+ fun to_mdoc: MDoc
+ do
+ var res = mdoc_cache
+ if res != null then return res
+ res = new MDoc
+ for c in n_comment do
+ var text = c.text
+ if text.length < 2 then
+ res.content.add ""
+ continue
+ end
+ assert text.chars[0] == '#'
+ if text.chars[1] == ' ' then
+ text = text.substring_from(2) # eat starting `#` and space
+ else
+ text = text.substring_from(1) # eat atarting `#` only
+ end
+ if text.chars.last == '\n' then text = text.substring(0, text.length-1) # drop \n
+ res.content.add(text)
+ end
+ mdoc_cache = res
+ return res
+ end
+end
warning(nfdt, "useless-bound", "Warning: Useless formal parameter type since `{bound}` cannnot have subclasses.")
end
else if mclass.mclassdefs.is_empty then
+ if objectclass == null then
+ error(nfd, "Error: Formal parameter type `{pname}' unbounded but no Object class exist.")
+ return
+ end
# No bound, then implicitely bound by nullable Object
var bound = objectclass.mclass_type.as_nullable
bounds.add(bound)
end
end
- # Register the nclassdef associated to each mclassdef
- # FIXME: why not refine the `MClassDef` class with a nullable attribute?
- var mclassdef2nclassdef = new HashMap[MClassDef, AClassdef]
+ # Registration of the nclassdef associated to each mclassdef
+ private var mclassdef2nclassdef = new HashMap[MClassDef, AClassdef]
# Return the static type associated to the node `ntype`.
# `mmodule` and `mclassdef` is the context where the call is made (used to understand formal types)
# Analysis and verification of property definitions to instantiate model element
module modelize_property
-import modelize_class
+intrude import modelize_class
private import annotation
redef class ToolContext
end
redef class ModelBuilder
- # Register the npropdef associated to each mpropdef
- # FIXME: why not refine the `MPropDef` class with a nullable attribute?
- var mpropdef2npropdef = new HashMap[MPropDef, APropdef]
+ # Registration of the npropdef associated to each mpropdef.
+ #
+ # Public clients need to use `mpropdef2node` to access stuff.
+ private var mpropdef2npropdef = new HashMap[MPropDef, APropdef]
+
+ # Retrieve the associated AST node of a mpropertydef.
+ # This method is used to associate model entity with syntactic entities.
+ #
+ # If the property definition is not associated with a node, returns node.
+ fun mpropdef2node(mpropdef: MPropDef): nullable ANode
+ do
+ var res: nullable ANode = mpropdef2npropdef.get_or_null(mpropdef)
+ if res != null then return res
+ if mpropdef isa MMethodDef and mpropdef.mproperty.is_root_init then
+ res = mclassdef2nclassdef.get_or_null(mpropdef.mclassdef)
+ if res != null then return res
+ end
+ return null
+ end
+
+ # Retrieve all the attributes nodes localy definied
+ # FIXME think more about this method and how the separations separate/global and ast/model should be done.
+ fun collect_attr_propdef(mclassdef: MClassDef): Array[AAttrPropdef]
+ do
+ var res = new Array[AAttrPropdef]
+ var n = mclassdef2nclassdef.get_or_null(mclassdef)
+ if n == null then return res
+ for npropdef in n.n_propdefs do
+ if npropdef isa AAttrPropdef then
+ res.add(npropdef)
+ end
+ end
+ return res
+ end
# Build the properties of `nclassdef`.
# REQUIRE: all superclasses are built.
build_properties(mclassdef2nclassdef[superclassdef])
end
+ mclassdef.build_self_type(self, nclassdef)
for nclassdef2 in nclassdef.all_defs do
for npropdef in nclassdef2.n_propdefs do
npropdef.build_property(self, mclassdef)
# Look for most-specific new-stype init definitions
var spropdefs = the_root_init_mmethod.lookup_super_definitions(mclassdef.mmodule, mclassdef.bound_mtype)
if spropdefs.is_empty then
- toolcontext.fatal_error(nclassdef.location, "Fatal error: {mclassdef} does not specialize {the_root_init_mmethod.intro_mclassdef}. Possible duplication of the root class `Object`?")
+ toolcontext.error(nclassdef.location, "Error: {mclassdef} does not specialize {the_root_init_mmethod.intro_mclassdef}. Possible duplication of the root class `Object`?")
+ return
end
# Search the longest-one and checks for conflict
# What is the `APropdef` associated to a `MProperty`?
# Used to check multiple definition of a property.
var mprop2npropdef: Map[MProperty, APropdef] = new HashMap[MProperty, APropdef]
+
+ # Build the virtual type `SELF` only for introduction `MClassDef`
+ fun build_self_type(modelbuilder: ModelBuilder, nclassdef: AClassdef)
+ do
+ if not is_intro then return
+
+ var name = "SELF"
+ var mprop = modelbuilder.try_get_mproperty_by_name(nclassdef, self, name)
+
+ # If SELF type is declared nowherer?
+ if mprop == null then return
+
+ # SELF is not a virtual type? it is weird but we ignore it
+ if not mprop isa MVirtualTypeProp then return
+
+ # Is this the intro of SELF in the library?
+ var intro = mprop.intro
+ var intro_mclassdef = intro.mclassdef
+ if intro_mclassdef == self then
+ var nintro = modelbuilder.mpropdef2npropdef[intro]
+
+ # SELF must be declared in Object, otherwise this will create conflicts
+ if intro_mclassdef.mclass.name != "Object" then
+ modelbuilder.error(nintro, "Error: the virtual type SELF must be declared in Object.")
+ end
+
+ # SELF must be public
+ if mprop.visibility != public_visibility then
+ modelbuilder.error(nintro, "Error: the virtual type SELF must be public.")
+ end
+
+ # SELF must not be fixed
+ if intro.is_fixed then
+ modelbuilder.error(nintro, "Error: the virtual type SELF cannot be fixed.")
+ end
+
+ return
+ end
+
+ # This class introduction inherits a SELF
+ # We insert an artificial property to update it
+ var mpropdef = new MVirtualTypeDef(self, mprop, self.location)
+ mpropdef.bound = mclass.mclass_type
+ end
end
redef class APropdef
mprop.is_init = is_init
mprop.is_new = n_kwnew != null
if parent isa ATopClassdef then mprop.is_toplevel = true
- if not self.check_redef_keyword(modelbuilder, mclassdef, n_kwredef, false, mprop) then return
+ self.check_redef_keyword(modelbuilder, mclassdef, n_kwredef, false, mprop)
else
if not mprop.is_root_init and not self.check_redef_keyword(modelbuilder, mclassdef, n_kwredef, not self isa AMainMethPropdef, mprop) then return
check_redef_property_visibility(modelbuilder, self.n_visibility, mprop)
msignature = mpropdef.mproperty.intro.msignature
if msignature == null then return # Skip error
+ # The local signature is adapted to use the local formal types, if any.
+ msignature = msignature.resolve_for(mclassdef.mclass.mclass_type, mclassdef.bound_mtype, mmodule, false)
+
# Check inherited signature arity
if param_names.length != msignature.arity then
var node: ANode
if mtype == null then return
end
+ var inherited_type: nullable MType = null
# Inherit the type from the getter (usually an abstract getter)
- if mtype == null and mreadpropdef != null and not mreadpropdef.is_intro then
+ if mreadpropdef != null and not mreadpropdef.is_intro then
var msignature = mreadpropdef.mproperty.intro.msignature
if msignature == null then return # Error, thus skipped
- mtype = msignature.return_mtype
+ inherited_type = msignature.return_mtype
+ if inherited_type != null then
+ # The inherited type is adapted to use the local formal types, if any.
+ inherited_type = inherited_type.resolve_for(mclassdef.mclass.mclass_type, mclassdef.bound_mtype, mmodule, false)
+ if mtype == null then mtype = inherited_type
+ end
end
var nexpr = self.n_expr
if mtype == null then return
end
- else if ntype != null then
+ else if ntype != null and inherited_type == mtype then
if nexpr isa ANewExpr then
var xmtype = modelbuilder.resolve_mtype(mmodule, mclassdef, nexpr.n_type)
if xmtype == mtype then
var mpropdef = new MVirtualTypeDef(mclassdef, mprop, self.location)
self.mpropdef = mpropdef
modelbuilder.mpropdef2npropdef[mpropdef] = self
+ if mpropdef.is_intro then
+ modelbuilder.toolcontext.info("{mpropdef} introduces new type {mprop.full_name}", 4)
+ else
+ modelbuilder.toolcontext.info("{mpropdef} redefines type {mprop.full_name}", 4)
+ end
set_doc(mpropdef, modelbuilder)
var atfixed = get_single_annotation("fixed", modelbuilder)
# Check redefinitions
bound = mpropdef.bound.as(not null)
for p in mpropdef.mproperty.lookup_super_definitions(mmodule, anchor) do
- var supbound = p.bound.as(not null)
+ var supbound = p.bound
+ if supbound == null then break # broken super bound, skip error
if p.is_fixed then
modelbuilder.error(self, "Redef Error: Virtual type {mpropdef.mproperty} is fixed in super-class {p.mclassdef.mclass}")
break
# `MProperty`
#
# * labels: `MProperty`, `model_name` and `MEntity`. Must also have `MMethod`,
-# `MAttribute` or `MVirtualTypeProp`, depending on the class of the represented
-# entity.
+# `MAttribute` `MVirtualTypeProp` or `MInnerClass`, depending on the class of
+# the represented entity.
# * `full_name`: fully qualified name.
# * `visibility`: visibility of the property.
# * `is_init`: Indicates if the property is a constructor. Exists only if the
# * `(:MProperty)-[:INTRO_CLASSDEF]->(:MClassDef)`: classdef that introduces
# the property.
#
+# Additional relationship for `MInnerClass`:
+#
+# * `(:MInnerClassDef)-[:NESTS]->(:MClass)`: actual inner class.
+#
# `MPropDef`
#
# * labels: `MPropDef`, `model_name` and `MEntity`. Must also have `MMethodDef`,
-# `MAttributeDef` or `MVirtualTypeDef`, depending on the class of the
-# represented entity.
+# `MAttributeDef`, `MVirtualTypeDef` or `MInnerClassDef`, depending on the
+# class of the represented entity.
# * `location`: origin of the definition. SEE: `Location.to_s`.
# * `(:MPropDef)-[:DEFINES]->(:MProperty)`: associated property.
#
# is bound in this definition. Exists only if this definition bound the virtual
# type to an effective type.
#
+# Additional relationship for `MInnerClassDef`:
+#
+# * `(:MInnerClassDef)-[:NESTS]->(:MClassDef)`: actual inner class'
+# definition.
+#
# `MType`
#
# * labels: `MType`, `model_name` and `MEntity`. Must also have `MClassType`,
#
# For example, if the source code contains:
#
+# ~~~nitish
# fun foo(a: A, b: B, c: C)
+# ~~~
#
# The `MSignature` node will contain a property
# `parameter_names = ["a", "b", "c"]` so the MSignature can be reconstructed
node.labels.add "MAttribute"
else if mproperty isa MVirtualTypeProp then
node.labels.add "MVirtualTypeProp"
+ else if mproperty isa MInnerClass then
+ node.labels.add "MInnerClass"
+ node.out_edges.add(new NeoEdge(node, "NESTS", to_node(mproperty.inner)))
end
node.out_edges.add(new NeoEdge(node, "INTRO_CLASSDEF", to_node(mproperty.intro_mclassdef)))
return node
mprop = new MAttribute(intro_mclassdef, name, visibility)
else if node.labels.has("MVirtualTypeProp") then
mprop = new MVirtualTypeProp(intro_mclassdef, name, visibility)
+ else if node.labels.has("MInnerClass") then
+ var inner = to_mclass(model, node.out_nodes("NESTS").first)
+ mprop = new MInnerClass(intro_mclassdef, name, visibility, inner)
end
if mprop == null then
print "not yet implemented to_mproperty for {node.labels.join(",")}"
if bound != null then
node.out_edges.add(new NeoEdge(node, "BOUND", to_node(bound)))
end
+ else if mpropdef isa MInnerClassDef then
+ node.labels.add "MInnerClassDef"
+ node.out_edges.add(new NeoEdge(node, "NESTS", to_node(mpropdef.inner)))
end
return node
end
mentities[node.id.as(Int)] = mpropdef
var bound = node.out_nodes("BOUND")
if not bound.is_empty then mpropdef.bound = to_mtype(model, bound.first)
+ else if node.labels.has("MInnerClassDef") then
+ var inner = to_mclassdef(model, node.out_nodes("NESTS").first)
+ mpropdef = new MInnerClassDef(mclassdef,
+ mproperty.as(MInnerClass), location, inner)
+ mentities[node.id.as(Int)] = mpropdef
end
if mpropdef == null then
print "not yet implemented to_mpropdef for {node.labels.join(",")}"
var parent = null
if opt_loop.value then
- var nruntime = modelbuilder.load_module("niti_runtime")
- if nruntime == null then
+ parent = modelbuilder.get_mmodule_by_name(null, null, "niti_runtime")
+ if parent == null then
toolcontext.check_errors
abort
end
- parent = nruntime.mmodule
end
modelbuilder.load_rt_module(parent, amodule, "-")
# Disable `cached` because it causes issues when printing transformed AST. FIXME
toolcontext.cached_phase.disabled = true
+# Try to colorize, even if programs are non valid
+toolcontext.keep_going = true
+
var opt_fragment = new OptionBool("Omit document header and footer", "-f", "--fragment")
var opt_first_line = new OptionInt("Start the source file at this line (default: 1)", 0, "--first-line")
var opt_last_line = new OptionInt("End the source file at this line (default: to the end)", 0, "--last-line")
# Simple tool to list Nit source files
module nitls
-intrude import modelbuilder
+import modelbuilder
import ordered_tree
+import console
class ProjTree
super OrderedTree[Object]
var opt_paths = false
+ var tc: ToolContext
redef fun display(o)
do
if opt_paths then
return o.filepath.as(not null)
else
- return "{o.name} ({o.filepath.to_s})"
+ var d = ""
+ if o.mdoc != null then
+ if tc.opt_no_color.value then
+ d = ": {o.mdoc.content.first}"
+ else
+ d = ": {o.mdoc.content.first.green}"
+ end
+ end
+ if tc.opt_no_color.value then
+ return "{o.name}{d} ({o.filepath.to_s})"
+ else
+ return "{o.name}{d} ({o.filepath.yellow})"
+ end
end
else if o isa ModulePath then
if opt_paths then
return o.filepath
else
- return "{o.name} ({o.filepath})"
+ var d = ""
+ var dd = ""
+ if o.mmodule != null and o.mmodule.mdoc != null then
+ if tc.opt_no_color.value then
+ d = ": {o.mmodule.mdoc.content.first}"
+ else
+ d = ": {o.mmodule.mdoc.content.first.green}"
+ end
+ end
+ if o.mmodule != null and not o.mmodule.in_importation.direct_greaters.is_empty then
+ var ms = new Array[String]
+ for m in o.mmodule.in_importation.direct_greaters do
+ if m.mgroup.mproject == o.mmodule.mgroup.mproject then
+ ms.add m.name
+ else
+ ms.add m.full_name
+ end
+ end
+ if tc.opt_no_color.value then
+ dd = " ({ms.join(" ")})"
+ else
+ dd = " ({ms.join(" ")})".light_gray
+ end
+ end
+ if tc.opt_no_color.value then
+ return "{o.name.bold}{d} ({o.filepath.to_s}){dd}"
+ else
+ return "{o.name.bold}{d} ({o.filepath.yellow}){dd}"
+ end
end
else
abort
end
end
+class AlphaEntityComparator
+ super Comparator
+ fun nameof(a: COMPARED): String
+ do
+ if a isa MGroup then
+ return a.name
+ else if a isa ModulePath then
+ return a.name
+ else
+ abort
+ end
+ end
+ redef fun compare(a,b)
+ do
+ return nameof(a) <=> nameof(b)
+ end
+end
+
var tc = new ToolContext
var opt_keep = new OptionBool("Ignore errors and files that are not a Nit source file", "-k", "--keep")
tc.option_context.add_option(opt_keep, opt_recursive, opt_tree, opt_source, opt_project, opt_depends, opt_paths, opt_make)
tc.tooldescription = "Usage: nitls [OPTION]... <file.nit|directory>...\nLists the projects and/or paths of Nit sources files."
+tc.accept_no_arguments = true
tc.process_options(args)
if opt_make.value then
print tc.tooldescription
exit 1
end
+if sum == 0 then opt_project.value = true
+tc.keep_going = opt_keep.value
var model = new Model
var mb = new ModelBuilder(model, tc)
-if opt_depends.value then
- if opt_recursive.value then
- print "-M incompatible with -r"
- exit 1
+if tc.option_context.rest.is_empty then tc.option_context.rest.add "."
+var files
+if opt_recursive.value then
+ files = new Array[String]
+ for d in tc.option_context.rest do
+ var pipe = new IProcess("find", d, "-name", "*.nit")
+ while not pipe.eof do
+ var l = pipe.read_line
+ if l == "" then break # last line
+ l = l.substring(0,l.length-1) # strip last oef
+ files.add l
+ end
+ pipe.close
+ pipe.wait
+ if pipe.status != 0 and not opt_keep.value then exit 1
end
-
- mb.parse(tc.option_context.rest)
else
- var files
- if opt_recursive.value then
- files = new Array[String]
- for d in tc.option_context.rest do
- var pipe = new IProcess("find", d, "-name", "*.nit")
- while not pipe.eof do
- var l = pipe.read_line
- if l == "" then break # last line
- l = l.substring(0,l.length-1) # strip last oef
- files.add l
+ files = tc.option_context.rest
+end
+
+if sum == 0 then
+ # If one of the file is a group, default is `opt_tree` instead of `opt_project`
+ for a in files do
+ var g = mb.get_mgroup(a)
+ if g != null then
+ opt_tree.value = true
+ opt_project.value = false
+ break
+ end
+ end
+end
+
+# Identify all relevant files
+for a in files do
+ var g = mb.get_mgroup(a)
+ var mp = mb.identify_file(a)
+ if g != null and not opt_project.value then
+ mb.visit_group(g)
+ end
+ if g == null and mp == null then
+ # not a group not a module, then look at files in the directory
+ var fs = a.files
+ for f in fs do
+ g = mb.get_mgroup(a/f)
+ if g != null and not opt_project.value then
+ mb.visit_group(g)
end
- pipe.close
- pipe.wait
- if pipe.status != 0 and not opt_keep.value then exit 1
+ mp = mb.identify_file(a/f)
+ #print "{a/f}: {mp or else "?"}"
end
- else
- files = tc.option_context.rest
end
+end
- for a in files do
- var mp = mb.identify_file(a)
- if mp == null then
- if not opt_keep.value then tc.check_errors
+# Load modules to get more informations
+for mp in mb.identified_files do
+ if not opt_paths.value or opt_depends.value then
+ var mm = mb.load_module(mp.filepath)
+ if mm != null and opt_depends.value then
+ mb.build_module_importation(mm)
end
end
end
+#tc.check_errors
-if sum == 0 then opt_project.value = true
+var ot = new ProjTree(tc)
+var sorter = new AlphaEntityComparator
if opt_tree.value then
- var ot = new ProjTree
ot.opt_paths = opt_paths.value
for p in model.mprojects do
for g in p.mgroups do
- ot.add(g.parent, g)
+ var pa = g.parent
+ if g.is_interesting then
+ ot.add(pa, g)
+ pa = g
+ end
for mp in g.module_paths do
- ot.add(g, mp)
+ ot.add(pa, mp)
end
end
end
- ot.sort_with(new CachedAlphaComparator)
+ ot.sort_with(sorter)
ot.write_to(stdout)
end
if opt_source.value then
- var list = new Array[String]
+ var list = new Array[ModulePath]
for p in model.mprojects do
for g in p.mgroups do
for mp in g.module_paths do
- if opt_paths.value then
- list.add(mp.filepath)
- else
- list.add("{g.full_name}/{mp.name} ({mp.filepath})")
- end
+ list.add mp
end
end
end
- alpha_comparator.sort(list)
- for l in list do print l
+ sorter.sort(list)
+ for mp in list do
+ if opt_paths.value then
+ print mp.filepath
+ else
+ print "{mp.mgroup.full_name}/{ot.display(mp)}"
+ end
+ end
end
if opt_project.value then
- var list = new Array[String]
+ var list = new Array[MGroup]
for p in model.mprojects do
- var path = p.root.filepath.as(not null)
+ list.add p.root.as(not null)
+ end
+ sorter.sort(list)
+ for g in list do
+ var path = g.filepath.as(not null)
if opt_paths.value then
- list.add(path)
+ print path
else
- list.add("{p.name} ({path})")
+ var d = ""
+ var md = g.mdoc_or_fallback
+ if md != null then
+ if tc.opt_no_color.value then
+ d = ": {md.content.first}"
+ else
+ d = ": {md.content.first.green}"
+ end
+ end
+ if tc.opt_no_color.value then
+ print "{g.name}{d} ({path})"
+ else
+ print "{g.name}{d} ({path.yellow})"
+ end
end
end
- alpha_comparator.sort(list)
- for l in list do print l
end
import parser
import modelbuilder # builder only for externcalls
+private import compiler::abstract_compiler
redef class MMethod
# Short name of this method in C (without the class name)
redef class MModule
# Mangled name of this module in C
- fun cname: String do return name
+ fun cname: String do return c_name # FIXME this is a hack to keep the internal FFI
+ # API independent of the compilers while still using the `MModule::c_name` service.
end
redef class MMethodDef
# `nitpretty` is a tool able to pretty print Nit files.
#
-# Usage:
-#
-# nitpretty source.nit
-#
-# Main options:
-#
-# * `-o res.nit` output result into `res.nit`
-# * `--diff` show diff between `source` and `res`
-# * `--meld` open diff with `meld`
-# * `--check` check the format of multiple source files
-# * `--check --meld` perform `--check` and open `meld` for each difference
-#
-# ## Specification
-#
-# The specification of the pretty printing is described here.
-#
-# * Default indentation level is one `'\t'` character and
-# is increased by one for each indentation level.
-# * Default line max-size is 80.
-#
-# ### Comments
-#
-# There is many categories of comments:
-#
-# `Licence comments` are attached to the top of the file
-# no blank line before, one after.
-#
-# # This is a licence comment
-#
-# # Documentation for module `foo`
-# module foo
-#
-# `ADoc` are documentation comments attached to a `AModule`, `AClassdef`, `APropdef`.
-#
-# They are printed before the definition with a blank line before and no after
-# at the same indentation level than the definition.
-#
-# # Documentation for module `foo`
-# module foo
-#
-# # Documentation for class `Bar`
-# class Bar
-# # Documentation for method `baz`
-# fun baz do end
-# end
-#
-# `Block comments` are comments composed of one or more line rattached to nothing.
-# They are displayed with one blank line before and after at current indent level.
-#
-# <blank>
-# # block
-# # comment
-# <blank>
-#
-# `Attached comments` are comments attached to a production.
-# They are printed as this.
-#
-# fun foo do # attached comment
-# end
-#
-# `nitpretty` automatically remove multiple blanks between comments:
-#
-# # Licence
-# # ...
-# <blank>
-# # Block comment
-#
-# ### Inlining
-#
-# Productions are automatically inlined when possible.
-#
-# Conditions:
-#
-# * the production must be syntactically inlinable
-# * the inlined production length is less than `PrettyPrinterVisitor::max-size`
-# * the production do not contains any comments
-#
-# ### Modules
-#
-# * There is a blank between the module declaration and its imports
-# * There is no blank between imports and only one after
-# * There is a blank between each extern block definition
-# * There is a blank between each class definition
-# * There is no blank line at the end of the module
-#
-# # Documentation for module `foo`
-# module foo
-#
-# import a
-# # import b
-# import c
-#
-# # Documentation for class `Bar`
-# class Bar end
-#
-# class Baz end # not a `ADoc` comment
-#
-#
-# ### Classes
-#
-# * There is no blank between the class definition and its super-classes declarations
-# * There is no blank between two inlined property definition
-# * There is a blank between each block definition
-# * There no blank line at the end of the class definition
-#
-# # Documentation for class `Bar`
-# class Bar end
-#
-# class Baz
-# super Bar
-#
-# fun a is abstract
-# private fun b do end
-#
-# fun c do
-# # ...
-# end
-# end
-#
-# Generic types have no espace after or before brackets and are separated by a comma and a space:
-#
-# class A[E: Type1, F: Type1] do end
-#
-# ### Blocks
-#
-# * Inlined productions have no blank lines between them
-# * Block productions have a blank before and after
-#
-# var a = 10
-# var b = 0
-#
-# if a > b then
-# # is positive
-# print "positive"
-# end
-#
-# print "end"
-#
-# ### Calls and Binary Ops
-#
-# Arguments are always printed separated with a comma and a space:
-#
-# foo(a, b, c)
-#
-# Binary ops are always printed wrapped with spaces:
-#
-# var c = 1 + 2
-#
-# Calls and binary ops can be splitted to fit the `max-size` constraint.
-# Breaking priority is given to arguments declaration after the comma.
-#
-# return foo("aaaaaaaaaaaaaaaaaaaaaaaaaa", "bbbbbbbbbbbbbbbbbbbbbbbbbbb",
-# "cccccccccccccccccccccccccc")
-#
-# Binary ops can also be broken to fit the `max-size` limit:
-#
-# return "aaaaaaaaaaaaaaaaaaaaaaaaaa" + "bbbbbbbbbbbbbbbbbbbbbbbbbbb" +
-# "cccccccccccccccccccccccccc"
-#
-module nitpretty
-
-import template
-import toolcontext
-import modelbuilder
-import astutil
-
-# The `PrettyPrinterVisitor` is used to visit a node and pretty print it.
-#
-# The main method here is `visit` that performs the pretty printing of a `ANode`.
-#
-# Because some tokens like `TComment` are not stored in the AST,
-# we visit the AST like traditionnal visitor and also maintain a
-# pointer to the `current_token` (actually the next one to be printed).
-#
-# Visited productions are in charges to move the token pointer using methods such as:
-#
-# * `consume`: print `current_token` and move to the next one
-# * `skip`: move to the next token without printing the current one
-# * `skip_to`: move to a specified token skipping all the tokens before
-# * `catch_up`: consume all the tokens between `current_token` and a specified token
-# * `finish_line`: consume all the tokens between `current_token` and the end of line
-class PrettyPrinterVisitor
- # Pretty print `n`.
- fun pretty(n: ANode): Template do
- clear
- n.parentize_tokens
-
- if n isa Prod then
- current_token = n.first_token
- visit n
- else if n isa Token then
- var p = n.parent
-
- while p != null and not p isa Prod do
- p = p.parent
- end
-
- current_token = p.first_token
- visit p
- end
-
- return tpl.as(not null)
- end
-
- # Pretty print the whole `nmodule` with comments before and after.
- fun pretty_nmodule(nmodule: AModule): Template do
- clear
- nmodule.parentize_tokens
- current_token = nmodule.location.file.first_token
- visit nmodule
- catch_up nmodule.location.file.last_token
- tpl.add "\n"
- return tpl.as(not null)
- end
-
- # Prepare `self` for a new visit.
- private fun clear do
- tpl = new Template
- current_token = null
- indent = 0
- current_length = 0
- previous_length = 0
- wait_addn = 0
- end
-
- # Visit `n` if not null.
- fun visit(n: nullable ANode) do
- if n == null then return
- n.accept_pretty_printer self
- end
-
- # Visit a list of `Anode`.
- fun visit_list(n: nullable ANodes[ANode]) do
- if n == null then return
- n.accept_pretty_printer self
- end
-
- # Is the node inlinable and can fit on the line.
- fun can_inline(n: nullable ANode): Bool do
- if n == null then return true
- if n.must_be_inline then return true
- if n.must_be_block then return false
- # check length
- if n.collect_length + current_length > max_size then return false
- # check block is inlinable
- return n.is_inlinable
- end
-
- # Collect all `TComment` between `from` and `to`.
- fun collect_comments(from: nullable ANode, to: nullable ANode): Array[TComment] do
- var res = new Array[TComment]
- if from isa Prod then from = from.first_token
- if to isa Prod then to = to.first_token
- if from == null or to == null then return res
-
- while from != to do
- if from isa TComment then res.add from
- from = from.as(Token).next_token
- end
-
- return res
- end
-
- # Token under cursor.
- #
- # This is the next token to visit.
- var current_token: nullable Token = null
-
- # Skip the `current_token`.
- fun skip do current_token = current_token.next_token
-
- # Skip `current_token` until the end of line.
- fun skip_line do current_token = current_token.last_real_token_in_line
-
- # Skip `current_token` until `target` is reached.
- fun skip_to(target: nullable Token) do
- if target == null then return
- while current_token != target do skip
- end
-
- # Visit `current_token`.
- fun consume(token: String) do
- assert current_token.text == token
- visit current_token
- end
-
- # Is there token to visit between `current_token` and `target`?
- fun need_catch_up(target: nullable Token): Bool do
- if target == null then return false
- return current_token != target
- end
-
- # Visit all tokens between `current_token` and `target`.
- fun catch_up(target: nullable ANode) do
- if target == null then return
- if current_token == null then return
- var token: Token
- if target isa Token then
- token = target
- else if target isa Prod then
- token = target.first_token.as(not null)
- else
- abort
- end
- assert current_token.location <= token.location
- while current_token != token do visit current_token
- end
-
- # Visit all tokens between `current_token` and the end of line.
- fun finish_line do
- if current_token isa TComment then
- adds
- visit current_token
- end
-
- while current_token isa TEol do skip
- end
-
- # The template under construction.
- private var tpl: nullable Template = null
-
- # Current indent level.
- var indent = 0
-
- # Size of a tabulation in spaces.
- var tab_size = 8
-
- # Max line size.
- var max_size = 80
-
- # Length of the current line.
- var current_length = 0
-
- # Length of the previous line.
- var previous_length = 0
-
- # Is the last line a blank line?
- fun last_line_is_blank: Bool do return previous_length == 0
-
- # Add `t` to current template.
- fun add(t: String) do
- if t.is_empty then return
- while wait_addn > 0 do
- tpl.add "\n"
- wait_addn -= 1
- end
- tpl.add t
- current_length += t.length
- end
-
- # Add a `'\n'`.
- fun addn do
- if current_length == 0 and last_line_is_blank then return
- previous_length = current_length
- current_length = 0
- wait_addn += 1
- end
-
- # End of line chars are stored until another char is added.
- # This avoid empty files with only a '`\n`'.
- private var wait_addn = 0
-
- # Add `'\t' * indent`.
- fun addt do add "\t" * indent
-
- # Add a space.
- fun adds do add " "
-
- fun visit_recv(n_expr: AExpr) do
- if not n_expr isa AImplicitSelfExpr then
- visit n_expr
- consume "."
- end
- end
-end
-
-# Base framework redefs
-
-redef class ANodes[E]
- private fun accept_pretty_printer(v: PrettyPrinterVisitor) do
- for e in self do
- var e_can_inline = v.can_inline(e)
-
- if e != first then
- if not e_can_inline then
- v.add ","
- v.addn
- v.addt
- v.addt
- else
- v.add ", "
- end
- end
-
- v.visit e
- end
- end
-end
-
-redef class ANode
- # Start visit of `self` using a `PrettyPrinterVisitor`
- private fun accept_pretty_printer(v: PrettyPrinterVisitor) is abstract
-
- # Collect the length (in `Char`) of the node.
- private fun collect_length: Int is abstract
-
- # Is `self` printable in one line?
- private fun is_inlinable: Bool do return true
-
- # Force `self` to be rendered as a block.
- private var force_block = false
-
- # Does `self` have to be rendered as a block?
- private fun must_be_block: Bool do return force_block
-
- # Force `self` to be rendered as a line.
- private var force_inline = false
-
- # Does `self` have be rendered as a line?
- private fun must_be_inline: Bool do
- if parent != null and parent.must_be_inline then return true
- return force_inline
- end
-
- # Does `self` was written in one line before transformation?
- private fun was_inline: Bool is abstract
-end
-
-redef class Token
- redef fun accept_pretty_printer(v) do
- v.add text.trim
- v.current_token = next_token
- end
-
- redef fun collect_length do return text.length
- redef fun is_inlinable do return true
- redef fun was_inline do return true
-end
-
-redef class Prod
- redef fun accept_pretty_printer(v) do v.visit first_token
-
- # The token where the production really start (skipping ADoc).
- private fun start_token: nullable Token do return first_token
-
- # Collect all `TComment` contained in the production
- # (between `start_token` and `end_token`).
- private fun collect_comments: Array[TComment] do
- var res = new Array[TComment]
- if start_token == null or last_token == null then return res
- var token = start_token
-
- while token != last_token do
- if token isa TComment then res.add token
- token = token.next_token
- end
-
- return res
- end
-
- redef fun collect_length do
- var res = 0
- if start_token == null or last_token == null then return res
- var token = start_token
-
- while token != last_token do
- res += token.text.length
- token = token.next_token
- end
-
- res += token.text.length
- return res
- end
-
- redef fun was_inline do
- return first_token.location.line_start == last_token.location.line_end
- end
-end
-
-# Comments
-
-redef class TComment
- redef fun accept_pretty_printer(v) do
- if is_adoc then
- v.addt
- super
- v.addn
- return
- end
-
- if is_licence then
- super
- v.addn
- if is_last_in_group then v.addn
- return
- end
-
- if is_orphan then
- v.addn
- v.addt
- super
- v.addn
- v.addn
- return
- end
-
- if is_inline then
- if next_token isa TComment and is_first_in_group then v.addn
- v.addt
- super
- v.addn
- var prev_token = self.prev_token
- if prev_token isa TComment and prev_token.is_inline and is_last_in_group then v.addn
- return
- end
-
- super
- end
-
- # Is `self` part of an `ADoc`?
- private fun is_adoc: Bool do return parent isa ADoc and parent.parent != null
-
- # Is `self` part of a licence?
- private fun is_licence: Bool do
- var prev_token = self.prev_token
-
- if prev_token == null then
- return true
- else if prev_token isa TComment then
- return prev_token.is_licence
- else
- return false
- end
- end
-
- # Is `self` starts and ends its line?
- private fun is_inline: Bool do
- return self == first_real_token_in_line and self == last_real_token_in_line
- end
-
- # Is `self` an orphan line (blank before and after)?
- private fun is_orphan: Bool do
- return prev_token isa TEol and
- (prev_token.prev_token isa TEol or prev_token.prev_token isa TComment) and
- next_token isa TEol
- end
-
- # Is `self` the first comment of a group of comment?
- private fun is_first_in_group: Bool do return not prev_token isa TComment
-
- # Is `self` the last comment of a group of comments?
- private fun is_last_in_group: Bool do return not next_token isa TComment
-end
-
-redef class ADoc
- redef fun accept_pretty_printer(v) do for comment in n_comment do v.visit comment
- redef fun is_inlinable do return n_comment.length <= 1
-end
-
-# Annotations
-
-redef class AAnnotations
- redef fun accept_pretty_printer(v) do
- v.adds
- v.consume "is"
-
- if v.can_inline(self) then
- v.adds
- for n_item in n_items do
- v.visit n_item
- if n_item != n_items.last then
- v.add ", "
- end
- end
- v.finish_line
- else if n_items.length > 1 then
- v.addn
- v.indent += 1
-
- for n_item in n_items do
- v.addt
- v.visit n_item
- v.finish_line
- v.addn
- end
-
- v.indent -= 1
- end
- if not was_inline and v.current_token isa TKwend then v.skip
- end
-
- redef fun is_inlinable do
- if not super then return false
- for annot in n_items do if not annot.is_inlinable then return false
- return true
- end
-end
-
-redef class AAnnotation
- redef fun accept_pretty_printer(v) do
- v.visit n_atid
- if not n_args.is_empty then
- if n_opar == null then
- v.adds
- else
- v.visit n_opar
- end
- v.visit_list n_args
- v.visit n_cpar
- end
- end
-end
-
-redef class ATypeExpr
- redef fun accept_pretty_printer(v) do v.visit n_type
-end
-
-# Modules
-
-redef class AModule
- redef fun accept_pretty_printer(v) do
- v.catch_up start_token
- v.visit n_moduledecl
-
- if not n_imports.is_empty then
- v.addn
-
- for n_import in n_imports do
- v.catch_up n_import
- v.visit n_import
- end
- end
-
- if not n_extern_code_blocks.is_empty then
- v.addn
-
- for n_extern_block in n_extern_code_blocks do
- v.catch_up n_extern_block
- v.visit n_extern_block
- v.addn
- if n_extern_block != n_extern_code_blocks.last then v.addn
- end
-
- if not n_classdefs.is_empty then v.addn
- end
-
- if not n_classdefs.is_empty then
- v.addn
-
- for n_classdef in n_classdefs do
- v.catch_up n_classdef
- v.visit n_classdef
- if n_classdef != n_classdefs.last then v.addn
- end
- end
-
- assert v.indent == 0
- end
-
- # Skip doc if any.
- redef fun start_token do
- if n_moduledecl != null then return n_moduledecl.first_token
- if not n_imports.is_empty then return n_imports.first.first_token
- if not n_classdefs.is_empty then return n_classdefs.first.first_token
- return first_token
- end
-
- redef fun is_inlinable do return false
-end
-
-redef class AModuledecl
- redef fun accept_pretty_printer(v) do
- v.visit n_doc
- v.visit n_kwmodule
- v.adds
- v.visit n_name
-
- if n_annotations != null then
- var annot_inline = v.can_inline(n_annotations)
- v.visit n_annotations
-
- if not annot_inline then
- if v.current_token isa TKwend then
- v.consume "end"
- v.finish_line
- else
- v.add "end"
- end
- end
- end
-
- v.finish_line
- v.addn
- end
-end
-
-redef class AModuleName
- redef fun accept_pretty_printer(v) do
- for path in n_path do
- v.visit path
- v.add "::"
- end
-
- v.visit n_id
- end
-end
-
-redef class ANoImport
- redef fun accept_pretty_printer(v) do
- v.visit n_kwimport
- v.adds
- v.visit n_kwend
- v.finish_line
- v.addn
- end
-end
-
-redef class AStdImport
- redef fun accept_pretty_printer(v) do
- if not n_visibility isa APublicVisibility then
- v.visit n_visibility
- v.adds
- end
-
- v.visit n_kwimport
- v.adds
- v.visit n_name
- v.finish_line
- v.addn
- end
-end
-
-# Classes
-
-redef class AClassdef
- redef fun accept_pretty_printer(v) do
- for n_propdef in n_propdefs do
- v.catch_up n_propdef
-
- if n_propdef.n_doc != null or not v.can_inline(n_propdef) then
- if n_propdef != n_propdefs.first then v.addn
- v.visit n_propdef
- if n_propdef != n_propdefs.last then v.addn
- else
- v.visit n_propdef
- end
- end
- end
-end
-
-redef class AStdClassdef
- redef fun accept_pretty_printer(v) do
- v.visit n_doc
- var can_inline = v.can_inline(self)
-
- if not n_visibility isa APublicVisibility then
- v.visit n_visibility
- v.adds
- end
-
- if n_kwredef != null then
- v.visit n_kwredef
- v.adds
- end
-
- v.visit n_classkind
- v.adds
- v.visit n_id
-
- if not n_formaldefs.is_empty then
- v.consume "["
- v.visit_list n_formaldefs
- v.consume "]"
- end
-
- if n_extern_code_block != null then
- v.adds
- v.visit n_extern_code_block
- end
-
- if can_inline then
- v.adds
-
- if not n_superclasses.is_empty then
- for n_superclass in n_superclasses do
- v.visit n_superclass
- v.adds
- end
- end
- else
- v.finish_line
- v.addn
- v.indent += 1
-
- for n_superclass in n_superclasses do
- v.catch_up n_superclass
- v.addt
- v.visit n_superclass
- v.finish_line
- v.addn
- end
-
- if not n_superclasses.is_empty and not n_propdefs.is_empty then
- v.addn
- end
-
- super
- v.catch_up n_kwend
- v.indent -= 1
- end
-
- v.visit n_kwend
- v.finish_line
- v.addn
- assert v.indent == 0
- end
-
- redef fun is_inlinable do
- if not super then return false
- if not n_propdefs.is_empty then return false
- if n_superclasses.length > 1 then return false
- if not collect_comments.is_empty then return false
- return true
- end
-
- redef fun start_token do
- if not n_visibility isa APublicVisibility then return n_visibility.first_token
- if n_kwredef != null then return n_kwredef
- return n_classkind.first_token
- end
-end
-
-redef class AAbstractClasskind
- redef fun accept_pretty_printer(v) do
- v.visit n_kwabstract
- v.adds
- v.visit n_kwclass
- end
-end
-
-redef class AExternClasskind
- redef fun accept_pretty_printer(v) do
- v.visit n_kwextern
- v.adds
- v.visit n_kwclass
- end
-end
-
-redef class AFormaldef
- redef fun accept_pretty_printer(v) do
- v.visit n_id
-
- if n_type != null then
- v.consume ":"
- v.adds
- v.visit n_type
- end
- end
-end
-
-redef class AType
- redef fun accept_pretty_printer(v) do
- if n_kwnullable != null then
- v.visit n_kwnullable
- v.adds
- end
-
- v.visit n_id
-
- if not n_types.is_empty then
- v.consume "["
- v.visit_list n_types
- v.consume "]"
- end
- end
-end
-
-redef class ASuperclass
- redef fun accept_pretty_printer(v) do
- v.visit n_kwsuper
- v.adds
- v.visit n_type
- end
-end
-
-# Properties
-
-redef class APropdef
- redef fun accept_pretty_printer(v) do
- v.visit n_doc
- v.addt
-
- if not n_visibility isa APublicVisibility then
- v.visit n_visibility
- v.adds
- end
-
- if n_kwredef != null then
- v.visit n_kwredef
- v.adds
- end
- end
-
- redef fun start_token do
- if n_doc == null then return super
- return n_doc.last_token.next_token
- end
-end
-
-redef class AAttrPropdef
- redef fun accept_pretty_printer(v) do
- super
- v.visit n_kwvar
- v.adds
- v.visit n_id2
-
- if n_type != null then
- v.consume ":"
- v.adds
- v.visit n_type
- end
-
- if n_expr != null then
- v.adds
- v.consume "="
- v.adds
- v.visit n_expr
- end
-
- if n_annotations != null then v.visit n_annotations
- v.finish_line
- v.addn
- end
-
- redef fun first_token do
- if n_doc != null then return n_doc.first_token
- if not n_visibility isa APublicVisibility then return n_visibility.first_token
- if n_kwredef != null then return n_kwredef
- return n_kwvar
- end
-
- redef fun is_inlinable do return true
-end
-
-redef class ATypePropdef
- redef fun accept_pretty_printer(v) do
- super
- v.visit n_kwtype
- v.adds
- v.visit n_id
- v.consume ":"
- v.adds
- v.visit n_type
- v.finish_line
- v.addn
- end
-
- redef fun is_inlinable do return true
-end
-
-redef class AMethPropdef
- redef fun accept_pretty_printer(v) do
- # TODO: Handle extern annotations
-
- var before = v.indent
- var can_inline = v.can_inline(self)
- super
- if n_kwinit != null then v.visit n_kwinit
- if n_kwmeth != null then v.visit n_kwmeth
- if n_kwnew != null then v.visit n_kwnew
-
- if not n_methid == null then
- v.adds
- v.visit n_methid
- end
-
- v.visit n_signature
-
- if n_annotations != null then
- v.visit n_annotations
- else
- v.adds
- end
-
- if n_extern_calls != null or n_extern_code_block != null then
- if n_annotations != null then v.adds
- if n_extern_calls != null then v.visit n_extern_calls
- if n_extern_code_block != null then v.visit n_extern_code_block
- end
-
- var n_block = self.n_block
-
- if n_block != null then
- while not v.current_token isa TKwdo do v.skip
- if n_annotations != null then
- if v.can_inline(n_annotations) then
- v.adds
- else
- v.addt
- end
- end
- v.consume "do"
-
- if can_inline then
- v.adds
-
- if n_block isa ABlockExpr then
- if n_block.n_expr.is_empty then
- v.visit n_block.n_kwend
- else
- v.visit n_block.n_expr.first
- v.current_token = n_block.n_kwend
- v.skip
- end
- else
- v.visit n_block
- if v.current_token isa TKwend then v.skip
- end
- else
- v.finish_line
- v.addn
- v.indent += 1
-
- if n_block isa ABlockExpr then
- n_block.force_block = true
- v.visit n_block
- v.catch_up n_block.n_kwend
- else
- v.addt
- v.visit n_block
- v.addn
- end
-
- v.indent -= 1
- v.addt
- if n_block isa ABlockExpr then
- v.visit n_block.n_kwend
- else
- v.add "end"
- end
- end
- end
-
- v.finish_line
- v.addn
- assert v.indent == before
- end
-
- # Can be inlined if:
- # * block is empty or can be inlined
- # * contains no comments
- redef fun is_inlinable do
- if not super then return false
- if n_annotations != null and not n_annotations.is_inlinable then return false
- if n_block != null and not n_block.is_inlinable then return false
- if n_extern_calls != null and not n_extern_calls.is_inlinable then return false
- if n_extern_code_block != null and not n_extern_code_block.is_inlinable then return false
- if not collect_comments.is_empty then return false
- return true
- end
-end
-
-redef class AMainMethPropdef
- redef fun accept_pretty_printer(v) do
- v.visit n_block
- v.addn
- end
-end
-
-redef class ASignature
- redef fun accept_pretty_printer(v) do
- if not n_params.is_empty then
- v.consume "("
- v.visit_list n_params
- v.consume ")"
- end
-
- if n_type != null then
- v.consume ":"
- v.adds
- v.visit n_type
- end
- end
-end
-
-redef class AParam
- redef fun accept_pretty_printer(v) do
- v.visit n_id
-
- if n_type != null then
- v.consume ":"
- v.adds
- v.visit n_type
- end
-
- if n_dotdotdot != null then v.visit n_dotdotdot
- end
-end
-
-# Extern
-
-redef class AExternCalls
- redef fun accept_pretty_printer(v) do
- var can_inline = v.can_inline(self)
- v.visit n_kwimport
-
- if can_inline then
- v.adds
- v.visit_list n_extern_calls
- else
- v.addn
- v.addt
- v.addt
- v.visit_list n_extern_calls
- end
-
- v.adds
- end
-end
-
-redef class AFullPropExternCall
- redef fun accept_pretty_printer(v) do
- v.visit n_type
- v.visit n_dot
- v.visit n_methid
- end
-end
-
-redef class ALocalPropExternCall
- redef fun accept_pretty_printer(v) do v.visit n_methid
-end
-
-redef class AInitPropExternCall
- redef fun accept_pretty_printer(v) do v.visit n_type
-end
-
-redef class ACastAsExternCall
- redef fun accept_pretty_printer(v) do
- v.visit n_from_type
- v.visit n_dot
- v.visit n_kwas
- v.consume "("
- v.visit n_to_type
- v.consume ")"
- end
-end
-
-redef class AAsNullableExternCall
- redef fun accept_pretty_printer(v) do
- v.visit n_type
- v.consume "."
- v.visit n_kwas
- v.adds
- v.visit n_kwnullable
- end
-end
-
-redef class AAsNotNullableExternCall
- redef fun accept_pretty_printer(v) do
- v.visit n_type
- v.consume "."
- v.visit n_kwas
- v.adds
- v.visit n_kwnot
- v.adds
- v.visit n_kwnullable
- end
-end
-
-redef class AExternCodeBlock
- redef fun accept_pretty_printer(v) do
- if n_in_language != null then
- v.visit n_in_language
- v.adds
- end
-
- v.visit n_extern_code_segment
- end
-
- redef fun is_inlinable do
- if not super then return false
- return n_extern_code_segment.is_inlinable
- end
-end
-
-redef class AInLanguage
- redef fun accept_pretty_printer(v) do
- v.visit n_kwin
- v.adds
- v.visit n_string
- end
-end
-
-redef class TExternCodeSegment
- redef fun accept_pretty_printer(v) do
- var can_inline = v.can_inline(self)
-
- if can_inline then
- super
- else
- var text = text.substring(2, text.length - 4)
- var lines = text.r_trim.split("\n")
-
- if text.is_empty then
- v.add "`\{`\}"
- else
- v.add "`\{"
-
- if not lines.first.trim.is_empty then
- v.addn
- lines.first.l_trim
- v.indent += 1
- v.addt
- v.indent -= 1
- end
-
- for line in lines do
- v.add line.r_trim
- v.addn
- end
-
- v.addt
- v.add "`\}"
- end
-
- v.current_token = next_token
- end
- end
-
- redef fun is_inlinable do
- if not super then return false
- return location.line_start == location.line_end
- end
-end
-
-# Blocks
-
-redef class ABlockExpr
- redef fun accept_pretty_printer(v) do
- var before = v.indent
- var can_inline = v.can_inline(self)
-
- if can_inline and not n_expr.is_empty then
- v.visit n_expr.first
- v.finish_line
- else
- for nexpr in n_expr do
- var expr_inline = v.can_inline(nexpr)
- if not expr_inline and nexpr != n_expr.first then v.addn
- v.catch_up nexpr
- v.addt
- v.visit nexpr
- v.finish_line
- v.addn
- if not expr_inline and nexpr != n_expr.last then v.addn
- end
- end
-
- assert v.indent == before
- end
-
- redef fun is_inlinable do
- if not super then return false
- if not collect_comments.is_empty then return false
-
- if not n_expr.is_empty then
- if n_expr.length > 1 then return false
- if not n_expr.first.is_inlinable then return false
- end
-
- return true
- end
-end
-
-redef class AIfExpr
- redef fun accept_pretty_printer(v) do
- var before = v.indent
- var can_inline = v.can_inline(self)
- v.visit n_kwif
- v.adds
-
- if v.can_inline(n_expr) then
- v.visit n_expr
- v.adds
- else
- v.visit n_expr
- v.addn
- v.addt
- end
-
- # skip comments before `then` token
- while not v.current_token isa TKwthen do v.skip
- v.consume "then"
- var n_else = self.n_else
-
- if can_inline then
- v.adds
- if n_then != null then v.visit n_then
-
- if has_else(v) then
- n_else.force_inline = true
- v.adds
- v.consume "else"
- v.adds
- v.visit n_else
- else if n_then == null then
- v.add "end"
- end
-
- v.skip_to last_token.last_real_token_in_line
- else
- v.finish_line
- v.addn
- v.indent += 1
-
- if n_then != null then
- if n_then isa ABlockExpr then
- n_then.force_block = true
- v.visit n_then
- else
- v.addt
- v.visit n_then
- v.addn
- end
- end
-
- if has_else(v) then
- while not v.current_token isa TKwelse do
- v.consume v.current_token.text
- end
-
- v.indent -= 1
- v.addt
- v.consume "else"
-
- if n_else isa AIfExpr then
- n_else.force_block = true
- v.adds
- v.visit n_else
- else
- v.finish_line
- v.addn
- v.indent += 1
-
- if n_else isa ABlockExpr then
- n_else.force_block = true
- v.visit n_else
- else
- v.addt
- v.visit n_else
- v.addn
- end
-
- if last_token isa TKwend then
- v.catch_up last_token
- v.indent -= 1
- v.addt
- v.consume "end"
- else
- v.indent -= 1
- v.addt
- v.add "end"
- end
- end
- else
- if last_token.location >= v.current_token.location then v.catch_up last_token
- v.indent -= 1
- v.addt
- v.add "end"
- if v.current_token isa TKwend then v.skip
- end
- end
-
- assert v.indent == before
- end
-
- redef fun is_inlinable do
- if not super then return false
- if n_then != null and not n_then.is_inlinable then return false
- var n_else = self.n_else
- if (n_else isa ABlockExpr and not n_else.n_expr.is_empty) or
- (not n_else isa ABlockExpr and n_else != null) then
- return false
- end
- if not collect_comments.is_empty then return false
- return true
- end
-
- # Does this `if` statement contains a `else` part?
- private fun has_else(v: PrettyPrinterVisitor): Bool do
- var n_else = n_else
- if n_else == null then return false
- var n_kwelse = collect_kwelse
- if n_kwelse == null then return false
-
- if n_else isa ABlockExpr then
- var comments: Array[TComment]
-
- if n_then == null then
- comments = v.collect_comments(n_expr.last_token, n_else.last_token)
- else
- comments = v.collect_comments(n_then.last_token, n_else.last_token)
- end
-
- if not comments.is_empty then return true
- return not n_else.n_expr.is_empty
- end
-
- return true
- end
-
- # Lookup for `else` token in `self`.
- private fun collect_kwelse: nullable TKwelse do
- var token = first_token
-
- while token != last_token do
- if token isa TKwelse then return token
- token = token.next_token
- end
-
- return null
- end
-end
-
-# Used to factorize work on loops.
-private class ALoopHelper
- super AExpr
-
- fun loop_block: nullable ANode is abstract
- fun loop_label: nullable ANode is abstract
-
- fun visit_loop_block(v: PrettyPrinterVisitor) do
- var n_block = loop_block
- v.finish_line
- v.addn
- v.indent += 1
-
- if n_block isa ABlockExpr then
- n_block.force_block = true
- v.visit n_block
- v.catch_up n_block.n_kwend
- v.indent -= 1
- v.addt
- v.visit n_block.n_kwend
- else
- v.addt
- v.visit n_block
- v.addn
- v.indent -= 1
- v.addt
- v.add "end"
- end
-
- if loop_label != null then
- v.adds
- v.visit loop_label
- end
- end
-
- fun visit_loop_inline(v: PrettyPrinterVisitor) do
- var n_block = loop_block
- v.adds
-
- if n_block isa ABlockExpr then
- if n_block.n_expr.is_empty then
- v.visit n_block.n_kwend
- else
- v.visit n_block.n_expr.first
- v.current_token = n_block.n_kwend
- v.skip
- end
- else
- v.visit n_block
- if v.current_token isa TKwend then v.skip
- end
-
- if loop_label != null then
- v.adds
- v.visit loop_label
- end
- end
-
- redef fun is_inlinable do
- var n_block = loop_block
- if not super then return false
- if n_block isa ABlockExpr and not n_block.is_inlinable then return false
- if not collect_comments.is_empty then return false
- return true
- end
-end
-
-redef class ALoopExpr
- super ALoopHelper
-
- redef fun loop_block do return n_block
- redef fun loop_label do return n_label
-
- redef fun accept_pretty_printer(v) do
- var can_inline = v.can_inline(self)
- v.visit n_kwloop
- if can_inline then visit_loop_inline v else visit_loop_block v
- end
-end
-
-redef class AWhileExpr
- super ALoopHelper
-
- redef fun loop_block do return n_block
- redef fun loop_label do return n_label
-
- redef fun accept_pretty_printer(v) do
- var can_inline = v.can_inline(self)
- v.visit n_kwwhile
- v.adds
- v.visit n_expr
- v.adds
- v.visit n_kwdo
- if can_inline then visit_loop_inline v else visit_loop_block v
- end
-end
-
-redef class ADoExpr
- super ALoopHelper
-
- redef fun loop_block do return n_block
- redef fun loop_label do return n_label
-
- redef fun accept_pretty_printer(v) do
- var can_inline = v.can_inline(self)
- v.visit n_kwdo
- if can_inline then visit_loop_inline v else visit_loop_block v
- end
-end
-
-redef class AForExpr
- super ALoopHelper
-
- redef fun loop_block do return n_block
- redef fun loop_label do return n_label
-
- redef fun accept_pretty_printer(v) do
- var can_inline = v.can_inline(self)
- v.visit n_kwfor
- v.adds
-
- for n_id in n_ids do
- v.visit n_id
- if n_id != n_ids.last then v.add ", "
- end
-
- v.adds
- v.consume "in"
- v.adds
- v.visit n_expr
- v.adds
- v.visit n_kwdo
- if can_inline then visit_loop_inline v else visit_loop_block v
- end
-end
-
-redef class ABreakExpr
- redef fun accept_pretty_printer(v) do
- v.visit n_kwbreak
-
- if n_expr != null then
- v.adds
- v.visit n_expr
- end
-
- if n_label != null then
- v.adds
- v.visit n_label
- end
- end
-
- redef fun is_inlinable do return true
-end
-
-redef class AContinueExpr
- redef fun accept_pretty_printer(v) do
- v.visit n_kwcontinue
-
- if n_expr != null then
- v.adds
- v.visit n_expr
- end
-
- if n_label != null then
- v.adds
- v.visit n_label
- end
- end
-
- redef fun is_inlinable do return true
-end
-
-# Calls
-
-redef class ASendExpr
- redef fun is_inlinable do return true
-end
-
-redef class ACallExpr
- redef fun accept_pretty_printer(v) do
- var can_inline = v.can_inline(self)
- v.visit_recv n_expr
-
- if not n_expr isa AImplicitSelfExpr and not can_inline then
- v.addn
- v.addt
- v.addt
- end
-
- v.visit n_id
-
- if not n_args.n_exprs.is_empty then
- if is_stmt and n_args.n_exprs.length == 1 then
- v.adds
- if v.current_token isa TOpar then v.skip
- v.visit n_args.n_exprs.first
- if v.current_token isa TCpar then v.skip
- else
- if v.current_token isa TOpar then
- v.consume "("
- else
- v.adds
- end
-
- v.visit_list n_args.n_exprs
- if v.current_token isa TCpar then v.consume ")"
- end
- end
- end
-
- # Is the call alone on its line?
- fun is_stmt: Bool do return parent isa ABlockExpr
-end
-
-redef class ACallAssignExpr
- redef fun accept_pretty_printer(v) do
- v.visit_recv n_expr
- v.visit n_id
-
- if not n_args.n_exprs.is_empty then
- v.consume "("
- v.visit_list n_args.n_exprs
- v.consume ")"
- end
-
- v.adds
- v.consume "="
- v.adds
- v.visit n_value
- end
-end
-
-redef class ACallReassignExpr
- redef fun accept_pretty_printer(v) do
- v.visit_recv n_expr
- v.visit n_id
-
- if not n_args.n_exprs.is_empty then
- v.consume "("
- v.visit_list n_args.n_exprs
- v.consume ")"
- end
-
- v.adds
- v.visit n_assign_op
- v.adds
- v.visit n_value
- end
-end
-
-redef class ABraExpr
- redef fun accept_pretty_printer(v) do
- v.visit n_expr
-
- if not n_args.n_exprs.is_empty then
- v.consume "["
- v.visit_list n_args.n_exprs
- v.consume "]"
- end
- end
-end
-
-redef class ABraAssignExpr
- redef fun accept_pretty_printer(v) do
- v.visit n_expr
-
- if not n_args.n_exprs.is_empty then
- v.consume "["
- v.visit_list n_args.n_exprs
- v.consume "]"
- end
-
- v.adds
- v.visit n_assign
- v.adds
- v.visit n_value
- end
-end
-
-redef class ABraReassignExpr
- redef fun accept_pretty_printer(v) do
- v.visit n_expr
-
- if not n_args.n_exprs.is_empty then
- v.consume "["
- v.visit_list n_args.n_exprs
- v.consume "]"
- end
-
- v.adds
- v.visit n_assign_op
- v.adds
- v.visit n_value
- end
-end
-
-redef class AAssignMethid
- redef fun accept_pretty_printer(v) do
- v.visit n_id
- v.visit n_assign
- end
-end
-
-redef class ABraMethid
- redef fun accept_pretty_printer(v) do
- v.visit n_obra
- v.visit n_cbra
- end
-end
-
-redef class ABraassignMethid
- redef fun accept_pretty_printer(v) do
- v.visit n_obra
- v.visit n_cbra
- v.visit n_assign
- end
-end
-
-redef class AInitExpr
- redef fun accept_pretty_printer(v) do
- if not n_expr isa AImplicitSelfExpr then
- v.visit n_expr
- v.consume "."
- end
-
- v.visit n_kwinit
-
- if not n_args.n_exprs.is_empty then
- v.consume "("
- v.visit_list n_args.n_exprs
- v.consume ")"
- end
- end
-end
-
-redef class ANewExpr
- redef fun accept_pretty_printer(v) do
- var can_inline = v.can_inline(self)
- v.visit n_kwnew
- v.adds
- v.visit n_type
-
- if n_id != null then
- v.consume "."
-
- if not can_inline then
- v.addn
- v.addt
- v.addt
- end
-
- v.visit n_id
- end
-
- if not n_args.n_exprs.is_empty then
- v.consume "("
- v.visit_list n_args.n_exprs
- v.consume ")"
- end
- end
-
- redef fun is_inlinable do return true
-end
-
-# Attributes
-
-redef class AAttrExpr
- redef fun accept_pretty_printer(v) do
- v.visit_recv n_expr
- v.visit n_id
- end
-
- redef fun is_inlinable do return true
-end
-
-redef class AAttrAssignExpr
- redef fun accept_pretty_printer(v) do
- v.visit_recv n_expr
- v.visit n_id
- v.adds
- v.visit n_assign
- v.adds
- v.visit n_value
- end
-end
-
-redef class AAttrReassignExpr
- redef fun accept_pretty_printer(v) do
- v.visit_recv n_expr
- v.visit n_id
- v.adds
- v.visit n_assign_op
- v.adds
- v.visit n_value
- end
-end
-
-# Exprs
-
-redef class AVardeclExpr
- redef fun accept_pretty_printer(v) do
- v.visit n_kwvar
- v.adds
- v.visit n_id
-
- if n_type != null then
- v.consume ":"
- v.adds
- v.visit n_type
- end
-
- if n_expr != null then
- v.adds
- v.consume "="
- v.adds
- v.visit n_expr
- end
- end
-
- redef fun is_inlinable do return true
-end
-
-redef class AVarAssignExpr
- redef fun accept_pretty_printer(v) do
- v.visit n_id
- v.adds
- v.visit n_assign
- v.adds
- v.visit n_value
- end
-end
-
-redef class AAssertExpr
- redef fun accept_pretty_printer(v) do
- var can_inline = v.can_inline(self)
- v.visit n_kwassert
-
- if n_id != null then
- v.adds
- v.visit n_id
- v.consume ":"
- end
-
- v.adds
- v.visit n_expr
- var n_else = self.n_else
-
- if n_else != null then
- v.adds
- v.consume "else"
-
- if can_inline then
- v.adds
- v.visit n_else
- else
- v.addn
-
- if n_else isa ABlockExpr then
- v.indent += 1
- n_else.force_block = true
- v.visit n_else
- v.indent -= 1
- v.addt
- v.visit n_else.n_kwend
- else
- v.indent += 1
- v.addt
- v.visit n_else
- v.addn
- v.indent -= 1
- v.addt
- v.add "end"
- end
- end
- end
- end
-
- redef fun is_inlinable do
- if not super then return false
- if n_else != null and not n_else.is_inlinable then return false
- return true
- end
-end
-
-redef class AReturnExpr
- redef fun accept_pretty_printer(v) do
- v.visit n_kwreturn
-
- if n_expr != null then
- v.adds
- v.visit n_expr
- end
- end
-end
-
-redef class ASuperExpr
- redef fun accept_pretty_printer(v) do
- v.visit n_kwsuper
-
- if not n_args.n_exprs.is_empty then
- if is_stmt and n_args.n_exprs.length == 1 then
- v.adds
- if v.current_token isa TOpar then v.skip
- v.visit n_args.n_exprs.first
- if v.current_token isa TCpar then v.skip
- else
- if v.current_token isa TOpar then
- v.consume "("
- else
- v.adds
- end
-
- v.visit_list n_args.n_exprs
- if v.current_token isa TCpar then v.consume ")"
- end
- end
- end
-
- # Is the call alone on its line?
- fun is_stmt: Bool do return self.first_token.is_starting_line
-
- redef fun is_inlinable do return true
-end
-
-redef class AOnceExpr
- redef fun accept_pretty_printer(v) do
- v.visit n_kwonce
- v.adds
- v.visit n_expr
- end
-
- redef fun is_inlinable do return true
-end
-
-redef class AAbortExpr
- redef fun accept_pretty_printer(v) do v.visit n_kwabort
- redef fun is_inlinable do return true
-end
-
-redef class ANotExpr
- redef fun accept_pretty_printer(v) do
- v.visit n_kwnot
- v.adds
- v.visit n_expr
- end
-end
-
-redef class AAsCastExpr
- redef fun accept_pretty_printer(v) do
- v.visit n_expr
- v.consume "."
- v.visit n_kwas
- v.visit n_opar
- v.visit n_type
- v.visit n_cpar
- end
-end
-
-redef class AAsNotnullExpr
- redef fun accept_pretty_printer(v) do
- v.visit n_expr
- v.consume "."
- v.visit n_kwas
- v.visit n_opar
- v.visit n_kwnot
- v.adds
- v.visit n_kwnull
- v.visit n_cpar
- end
-end
-
-# Binops
-
-# Used to factorize work on Or, And, Implies and Binop expressions.
-private class ABinOpHelper
- super AExpr
-
- fun bin_expr1: AExpr is abstract
- fun bin_expr2: AExpr is abstract
-
- # Operator string
- fun bin_op: String is abstract
-
- redef fun accept_pretty_printer(v) do
- var can_inline = v.can_inline(self)
-
- if not can_inline then
- if (self isa ABinopExpr and bin_expr1 isa ABinopExpr) or
- (self isa AAndExpr and (bin_expr1 isa AAndExpr or bin_expr1 isa AOrExpr)) or
- (self isa AOrExpr and (bin_expr1 isa AAndExpr or bin_expr1 isa AOrExpr))
- then
- bin_expr1.force_block = true
- end
- end
-
- v.visit bin_expr1
- v.adds
- v.consume bin_op
-
- if can_inline then
- v.adds
- v.visit bin_expr2
- else
- v.addn
- v.addt
- v.addt
- v.visit bin_expr2
- end
- end
-end
-
-redef class AAndExpr
- super ABinOpHelper
-
- redef fun bin_expr1 do return n_expr
- redef fun bin_expr2 do return n_expr2
- redef fun bin_op do return "and"
-end
-
-redef class AOrExpr
- super ABinOpHelper
-
- redef fun bin_expr1 do return n_expr
- redef fun bin_expr2 do return n_expr2
- redef fun bin_op do return "or"
-end
-
-redef class AImpliesExpr
- super ABinOpHelper
-
- redef fun bin_expr1 do return n_expr
- redef fun bin_expr2 do return n_expr2
- redef fun bin_op do return "implies"
-end
-
-redef class ABinopExpr
- super ABinOpHelper
-
- redef fun bin_expr1 do return n_expr
- redef fun bin_expr2 do return n_expr2
-end
-
-redef class AEqExpr
- redef fun bin_op do return "=="
-end
-
-redef class AGeExpr
- redef fun bin_op do return ">="
-end
-
-redef class AGgExpr
- redef fun bin_op do return ">>"
-end
-
-redef class AGtExpr
- redef fun bin_op do return ">"
-end
-
-redef class ALeExpr
- redef fun bin_op do return "<="
-end
-
-redef class ALlExpr
- redef fun bin_op do return "<<"
-end
-
-redef class ALtExpr
- redef fun bin_op do return "<"
-end
-
-redef class AMinusExpr
- redef fun bin_op do return "-"
-end
-
-redef class ANeExpr
- redef fun bin_op do return "!="
-end
-
-redef class APercentExpr
- redef fun bin_op do return "%"
-end
-
-redef class APlusExpr
- redef fun bin_op do return "+"
-end
-
-redef class ASlashExpr
- redef fun bin_op do return "/"
-end
-
-redef class AStarExpr
- redef fun bin_op do return "*"
-end
-
-redef class AStarstarExpr
- redef fun bin_op do return "**"
-end
-
-redef class AStarshipExpr
- redef fun bin_op do return "<=>"
-end
-
-redef class AIsaExpr
- redef fun accept_pretty_printer(v) do
- v.visit n_expr
- v.adds
- v.consume "isa"
- v.adds
- v.visit n_type
- end
-end
-
-redef class AOrElseExpr
- redef fun accept_pretty_printer(v) do
- v.visit n_expr
- v.adds
- v.consume "or"
- v.adds
- v.consume "else"
- v.adds
- v.visit n_expr2
- end
-
- redef fun is_inlinable do return true
-end
-
-# Syntax
-
-redef class AUminusExpr
- redef fun accept_pretty_printer(v) do
- v.consume "-"
- v.visit n_expr
- end
-end
-
-redef class ANullExpr
- redef fun accept_pretty_printer(v) do v.visit n_kwnull
- redef fun is_inlinable do return true
-end
-
-redef class AParExpr
- redef fun accept_pretty_printer(v) do
- v.visit n_opar
- v.visit n_expr
- v.visit n_cpar
- end
-end
-
-redef class AArrayExpr
- redef fun accept_pretty_printer(v) do
- v.consume "["
- v.visit_list n_exprs.n_exprs
- v.consume "]"
- end
-end
-
-redef class ACrangeExpr
- redef fun accept_pretty_printer(v) do
- v.visit n_obra
- v.visit n_expr
- v.consume ".."
- v.visit n_expr2
- v.visit n_cbra
- end
-end
-
-redef class AOrangeExpr
- redef fun accept_pretty_printer(v) do
- v.visit n_obra
- v.visit n_expr
- v.consume ".."
- v.visit n_expr2
- v.visit n_cbra
- end
-end
-
-# Strings
-
-redef class AStringFormExpr
- redef fun accept_pretty_printer(v) do
- var can_inline = v.can_inline(self)
-
- if can_inline then
- v.visit n_string
- else
- var text = n_string.text
- var i = 0
-
- while i < text.length do
- v.add text[i].to_s
-
- if v.current_length >= v.max_size and i <= text.length - 3 then
- v.add "\" +"
- v.addn
- v.indent += 1
- v.addt
- v.indent -= 1
- v.add "\""
- end
-
- i += 1
- end
-
- v.current_token = n_string.next_token
- end
- end
-end
-
-redef class ASuperstringExpr
- redef fun accept_pretty_printer(v) do
- for n_expr in n_exprs do v.visit n_expr
- end
-
- redef fun must_be_inline do
- if super then return true
-
- if not n_exprs.is_empty then
- var first = n_exprs.first
- return first isa AStringFormExpr and first.n_string.text.has_prefix("\"\"\"")
- end
-
- return false
- end
-end
+# See `man nitpretty` for more infos.
+import pretty
redef class ToolContext
+ # The working directory used to store temp files.
var opt_dir = new OptionString("Working directory (default is '.nitpretty')", "--dir")
+ # Output pretty printed code with this filename.
var opt_output = new OptionString("Output name (default is pretty.nit)", "-o",
"--output")
+ # Show diff between source and pretty printed code.
var opt_diff = new OptionBool("Show diff between source and output", "--diff")
+ # Show diff between source and pretty printed code using meld.
var opt_meld = new OptionBool("Show diff between source and output using meld",
"--meld")
+ # Check formatting instead of pretty printing.
+ #
+ # This option create a tempory pretty printed file then check if
+ # the output of the diff command on the source file and the pretty
+ # printed one is empty.
var opt_check = new OptionBool("Check format of Nit source files", "--check")
end
--- /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.
+
+# Library used to pretty print Nit code.
+#
+# Usage:
+#
+# import parser_util
+# var tc = new ToolContext
+# var nmodule = tc.parse_something("class A\nfun toto : Int do return 5\nend")
+# var ppv = new PrettyPrinterVisitor
+# var pmodule = ppv.pretty(nmodule)
+# assert pmodule.write_to_string == """
+# class A
+# \tfun toto: Int do return 5
+# end"""
+#
+# See `nitpretty` tool for more documentation.
+module pretty
+
+import template
+import toolcontext
+import modelbuilder
+import astutil
+
+# The `PrettyPrinterVisitor` is used to visit a node and pretty print it.
+#
+# The main method here is `visit` that performs the pretty printing of a `ANode`.
+#
+# Because some tokens like `TComment` are not stored in the AST,
+# we visit the AST like traditionnal visitor and also maintain a
+# pointer to the `current_token` (actually the next one to be printed).
+#
+# Visited productions are in charges to move the token pointer using methods such as:
+#
+# * `consume`: print `current_token` and move to the next one
+# * `skip`: move to the next token without printing the current one
+# * `skip_to`: move to a specified token skipping all the tokens before
+# * `catch_up`: consume all the tokens between `current_token` and a specified token
+# * `finish_line`: consume all the tokens between `current_token` and the end of line
+class PrettyPrinterVisitor
+ # Pretty print `n`.
+ fun pretty(n: ANode): Template do
+ clear
+ n.parentize_tokens
+
+ if n isa Prod then
+ current_token = n.first_token
+ visit n
+ else if n isa Token then
+ var p = n.parent
+
+ while p != null and not p isa Prod do
+ p = p.parent
+ end
+
+ current_token = p.first_token
+ visit p
+ end
+
+ return tpl.as(not null)
+ end
+
+ # Pretty print the whole `nmodule` with comments before and after.
+ fun pretty_nmodule(nmodule: AModule): Template do
+ clear
+ nmodule.parentize_tokens
+ current_token = nmodule.location.file.first_token
+ visit nmodule
+ catch_up nmodule.location.file.last_token
+ tpl.add "\n"
+ return tpl.as(not null)
+ end
+
+ # Prepare `self` for a new visit.
+ private fun clear do
+ tpl = new Template
+ current_token = null
+ indent = 0
+ current_length = 0
+ previous_length = 0
+ wait_addn = 0
+ end
+
+ # Visit `n` if not null.
+ fun visit(n: nullable ANode) do
+ if n == null then return
+ n.accept_pretty_printer self
+ end
+
+ # Visit a list of `Anode`.
+ fun visit_list(n: nullable ANodes[ANode]) do
+ if n == null then return
+ n.accept_pretty_printer self
+ end
+
+ # Is the node inlinable and can fit on the line.
+ fun can_inline(n: nullable ANode): Bool do
+ if n == null then return true
+ if n.must_be_inline then return true
+ if n.must_be_block then return false
+ # check length
+ if n.collect_length + current_length > max_size then return false
+ # check block is inlinable
+ return n.is_inlinable
+ end
+
+ # Collect all `TComment` between `from` and `to`.
+ fun collect_comments(from: nullable ANode, to: nullable ANode): Array[TComment] do
+ var res = new Array[TComment]
+ if from isa Prod then from = from.first_token
+ if to isa Prod then to = to.first_token
+ if from == null or to == null then return res
+
+ while from != to do
+ if from isa TComment then res.add from
+ from = from.as(Token).next_token
+ end
+
+ return res
+ end
+
+ # Token under cursor.
+ #
+ # This is the next token to visit.
+ var current_token: nullable Token = null
+
+ # Skip the `current_token`.
+ fun skip do current_token = current_token.next_token
+
+ # Skip `current_token` until the end of line.
+ fun skip_line do current_token = current_token.last_real_token_in_line
+
+ # Skip `current_token` until `target` is reached.
+ fun skip_to(target: nullable Token) do
+ if target == null then return
+ while current_token != target do skip
+ end
+
+ # Visit `current_token`.
+ fun consume(token: String) do
+ assert current_token.text == token
+ visit current_token
+ end
+
+ # Is there token to visit between `current_token` and `target`?
+ fun need_catch_up(target: nullable Token): Bool do
+ if target == null then return false
+ return current_token != target
+ end
+
+ # Visit all tokens between `current_token` and `target`.
+ fun catch_up(target: nullable ANode) do
+ if target == null then return
+ if current_token == null then return
+ var token: Token
+ if target isa Token then
+ token = target
+ else if target isa Prod then
+ token = target.first_token.as(not null)
+ else
+ abort
+ end
+ assert current_token.location <= token.location
+ while current_token != token do visit current_token
+ end
+
+ # Visit all tokens between `current_token` and the end of line.
+ fun finish_line do
+ if current_token isa TComment then
+ adds
+ visit current_token
+ end
+
+ while current_token isa TEol do skip
+ end
+
+ # The template under construction.
+ private var tpl: nullable Template = null
+
+ # Current indent level.
+ var indent = 0
+
+ # Size of a tabulation in spaces.
+ var tab_size = 8
+
+ # Max line size.
+ var max_size = 80
+
+ # Length of the current line.
+ var current_length = 0
+
+ # Length of the previous line.
+ var previous_length = 0
+
+ # Is the last line a blank line?
+ fun last_line_is_blank: Bool do return previous_length == 0
+
+ # Add `t` to current template.
+ fun add(t: String) do
+ if t.is_empty then return
+ while wait_addn > 0 do
+ tpl.add "\n"
+ wait_addn -= 1
+ end
+ tpl.add t
+ current_length += t.length
+ end
+
+ # Add a `'\n'`.
+ fun addn do
+ if current_length == 0 and last_line_is_blank then return
+ previous_length = current_length
+ current_length = 0
+ wait_addn += 1
+ end
+
+ # End of line chars are stored until another char is added.
+ # This avoid empty files with only a '`\n`'.
+ private var wait_addn = 0
+
+ # Add `'\t' * indent`.
+ fun addt do add "\t" * indent
+
+ # Add a space.
+ fun adds do add " "
+
+ # Visit explicit receiver, implicit self will be ignored.
+ fun visit_recv(n_expr: AExpr) do
+ if not n_expr isa AImplicitSelfExpr then
+ visit n_expr
+ consume "."
+ end
+ end
+end
+
+# Base framework redefs
+
+redef class ANodes[E]
+ private fun accept_pretty_printer(v: PrettyPrinterVisitor) do
+ for e in self do
+ var e_can_inline = v.can_inline(e)
+
+ if e != first then
+ if not e_can_inline then
+ v.add ","
+ v.addn
+ v.addt
+ v.addt
+ else
+ v.add ", "
+ end
+ end
+
+ v.visit e
+ end
+ end
+end
+
+redef class ANode
+ # Start visit of `self` using a `PrettyPrinterVisitor`
+ private fun accept_pretty_printer(v: PrettyPrinterVisitor) is abstract
+
+ # Collect the length (in `Char`) of the node.
+ private fun collect_length: Int is abstract
+
+ # Is `self` printable in one line?
+ private fun is_inlinable: Bool do return true
+
+ # Force `self` to be rendered as a block.
+ private var force_block = false
+
+ # Does `self` have to be rendered as a block?
+ private fun must_be_block: Bool do return force_block
+
+ # Force `self` to be rendered as a line.
+ private var force_inline = false
+
+ # Does `self` have be rendered as a line?
+ private fun must_be_inline: Bool do
+ if parent != null and parent.must_be_inline then return true
+ return force_inline
+ end
+
+ # Does `self` was written in one line before transformation?
+ private fun was_inline: Bool is abstract
+end
+
+redef class Token
+ redef fun accept_pretty_printer(v) do
+ v.add text.trim
+ v.current_token = next_token
+ end
+
+ redef fun collect_length do return text.length
+ redef fun is_inlinable do return true
+ redef fun was_inline do return true
+end
+
+redef class Prod
+ redef fun accept_pretty_printer(v) do v.visit first_token
+
+ # The token where the production really start (skipping ADoc).
+ private fun start_token: nullable Token do return first_token
+
+ # Collect all `TComment` contained in the production
+ # (between `start_token` and `end_token`).
+ private fun collect_comments: Array[TComment] do
+ var res = new Array[TComment]
+ if start_token == null or last_token == null then return res
+ var token = start_token
+
+ while token != last_token do
+ if token isa TComment then res.add token
+ token = token.next_token
+ end
+
+ return res
+ end
+
+ redef fun collect_length do
+ var res = 0
+ if start_token == null or last_token == null then return res
+ var token = start_token
+
+ while token != last_token do
+ res += token.text.length
+ token = token.next_token
+ end
+
+ res += token.text.length
+ return res
+ end
+
+ redef fun was_inline do
+ return first_token.location.line_start == last_token.location.line_end
+ end
+end
+
+# Comments
+
+redef class TComment
+ redef fun accept_pretty_printer(v) do
+ if is_adoc then
+ v.addt
+ super
+ v.addn
+ return
+ end
+
+ if is_licence then
+ super
+ v.addn
+ if is_last_in_group then v.addn
+ return
+ end
+
+ if is_orphan then
+ v.addn
+ v.addt
+ super
+ v.addn
+ v.addn
+ return
+ end
+
+ if is_inline then
+ if next_token isa TComment and is_first_in_group then v.addn
+ v.addt
+ super
+ v.addn
+ var prev_token = self.prev_token
+ if prev_token isa TComment and prev_token.is_inline and is_last_in_group then v.addn
+ return
+ end
+
+ super
+ end
+
+ # Is `self` part of an `ADoc`?
+ private fun is_adoc: Bool do return parent isa ADoc and parent.parent != null
+
+ # Is `self` part of a licence?
+ private fun is_licence: Bool do
+ var prev_token = self.prev_token
+
+ if prev_token == null then
+ return true
+ else if prev_token isa TComment then
+ return prev_token.is_licence
+ else
+ return false
+ end
+ end
+
+ # Is `self` starts and ends its line?
+ private fun is_inline: Bool do
+ return self == first_real_token_in_line and self == last_real_token_in_line
+ end
+
+ # Is `self` an orphan line (blank before and after)?
+ private fun is_orphan: Bool do
+ return prev_token isa TEol and
+ (prev_token.prev_token isa TEol or prev_token.prev_token isa TComment) and
+ next_token isa TEol
+ end
+
+ # Is `self` the first comment of a group of comment?
+ private fun is_first_in_group: Bool do return not prev_token isa TComment
+
+ # Is `self` the last comment of a group of comments?
+ private fun is_last_in_group: Bool do return not next_token isa TComment
+end
+
+redef class ADoc
+ redef fun accept_pretty_printer(v) do for comment in n_comment do v.visit comment
+ redef fun is_inlinable do return n_comment.length <= 1
+end
+
+# Annotations
+
+redef class AAnnotations
+ redef fun accept_pretty_printer(v) do
+ v.adds
+ v.consume "is"
+
+ if v.can_inline(self) then
+ v.adds
+ for n_item in n_items do
+ v.visit n_item
+ if n_item != n_items.last then
+ v.add ", "
+ end
+ end
+ v.finish_line
+ else if n_items.length > 1 then
+ v.addn
+ v.indent += 1
+
+ for n_item in n_items do
+ v.addt
+ v.visit n_item
+ v.finish_line
+ v.addn
+ end
+
+ v.indent -= 1
+ end
+ if not was_inline and v.current_token isa TKwend then v.skip
+ end
+
+ redef fun is_inlinable do
+ if not super then return false
+ for annot in n_items do if not annot.is_inlinable then return false
+ return true
+ end
+end
+
+redef class AAnnotation
+ redef fun accept_pretty_printer(v) do
+ v.visit n_atid
+ if not n_args.is_empty then
+ if n_opar == null then
+ v.adds
+ else
+ v.visit n_opar
+ end
+ v.visit_list n_args
+ v.visit n_cpar
+ end
+ end
+end
+
+redef class ATypeExpr
+ redef fun accept_pretty_printer(v) do v.visit n_type
+end
+
+# Modules
+
+redef class AModule
+ redef fun accept_pretty_printer(v) do
+ v.catch_up start_token
+ v.visit n_moduledecl
+
+ if not n_imports.is_empty then
+ v.addn
+
+ for n_import in n_imports do
+ v.catch_up n_import
+ v.visit n_import
+ end
+ end
+
+ if not n_extern_code_blocks.is_empty then
+ v.addn
+
+ for n_extern_block in n_extern_code_blocks do
+ v.catch_up n_extern_block
+ v.visit n_extern_block
+ v.addn
+ if n_extern_block != n_extern_code_blocks.last then v.addn
+ end
+
+ if not n_classdefs.is_empty then v.addn
+ end
+
+ if not n_classdefs.is_empty then
+ v.addn
+
+ for n_classdef in n_classdefs do
+ v.catch_up n_classdef
+ v.visit n_classdef
+ if n_classdef != n_classdefs.last then v.addn
+ end
+ end
+
+ assert v.indent == 0
+ end
+
+ # Skip doc if any.
+ redef fun start_token do
+ if n_moduledecl != null then return n_moduledecl.first_token
+ if not n_imports.is_empty then return n_imports.first.first_token
+ if not n_classdefs.is_empty then return n_classdefs.first.first_token
+ return first_token
+ end
+
+ redef fun is_inlinable do return false
+end
+
+redef class AModuledecl
+ redef fun accept_pretty_printer(v) do
+ v.visit n_doc
+ v.visit n_kwmodule
+ v.adds
+ v.visit n_name
+
+ if n_annotations != null then
+ var annot_inline = v.can_inline(n_annotations)
+ v.visit n_annotations
+
+ if not annot_inline then
+ if v.current_token isa TKwend then
+ v.consume "end"
+ v.finish_line
+ else
+ v.add "end"
+ end
+ end
+ end
+
+ v.finish_line
+ v.addn
+ end
+end
+
+redef class AModuleName
+ redef fun accept_pretty_printer(v) do
+ for path in n_path do
+ v.visit path
+ v.add "::"
+ end
+
+ v.visit n_id
+ end
+end
+
+redef class ANoImport
+ redef fun accept_pretty_printer(v) do
+ v.visit n_kwimport
+ v.adds
+ v.visit n_kwend
+ v.finish_line
+ v.addn
+ end
+end
+
+redef class AStdImport
+ redef fun accept_pretty_printer(v) do
+ if not n_visibility isa APublicVisibility then
+ v.visit n_visibility
+ v.adds
+ end
+
+ v.visit n_kwimport
+ v.adds
+ v.visit n_name
+ v.finish_line
+ v.addn
+ end
+end
+
+# Classes
+
+redef class AClassdef
+ redef fun accept_pretty_printer(v) do
+ for n_propdef in n_propdefs do
+ v.catch_up n_propdef
+
+ if n_propdef.n_doc != null or not v.can_inline(n_propdef) then
+ if n_propdef != n_propdefs.first then v.addn
+ v.visit n_propdef
+ if n_propdef != n_propdefs.last then v.addn
+ else
+ v.visit n_propdef
+ end
+ end
+ end
+end
+
+redef class AStdClassdef
+ redef fun accept_pretty_printer(v) do
+ v.visit n_doc
+ var can_inline = v.can_inline(self)
+
+ if not n_visibility isa APublicVisibility then
+ v.visit n_visibility
+ v.adds
+ end
+
+ if n_kwredef != null then
+ v.visit n_kwredef
+ v.adds
+ end
+
+ v.visit n_classkind
+ v.adds
+ v.visit n_id
+
+ if not n_formaldefs.is_empty then
+ v.consume "["
+ v.visit_list n_formaldefs
+ v.consume "]"
+ end
+
+ if n_extern_code_block != null then
+ v.adds
+ v.visit n_extern_code_block
+ end
+
+ if can_inline then
+ v.adds
+
+ if not n_superclasses.is_empty then
+ for n_superclass in n_superclasses do
+ v.visit n_superclass
+ v.adds
+ end
+ end
+ else
+ v.finish_line
+ v.addn
+ v.indent += 1
+
+ for n_superclass in n_superclasses do
+ v.catch_up n_superclass
+ v.addt
+ v.visit n_superclass
+ v.finish_line
+ v.addn
+ end
+
+ if not n_superclasses.is_empty and not n_propdefs.is_empty then
+ v.addn
+ end
+
+ super
+ v.catch_up n_kwend
+ v.indent -= 1
+ end
+
+ v.visit n_kwend
+ v.finish_line
+ v.addn
+ assert v.indent == 0
+ end
+
+ redef fun is_inlinable do
+ if not super then return false
+ if not n_propdefs.is_empty then return false
+ if n_superclasses.length > 1 then return false
+ if not collect_comments.is_empty then return false
+ return true
+ end
+
+ redef fun start_token do
+ if not n_visibility isa APublicVisibility then return n_visibility.first_token
+ if n_kwredef != null then return n_kwredef
+ return n_classkind.first_token
+ end
+end
+
+redef class AAbstractClasskind
+ redef fun accept_pretty_printer(v) do
+ v.visit n_kwabstract
+ v.adds
+ v.visit n_kwclass
+ end
+end
+
+redef class AExternClasskind
+ redef fun accept_pretty_printer(v) do
+ v.visit n_kwextern
+ v.adds
+ v.visit n_kwclass
+ end
+end
+
+redef class AFormaldef
+ redef fun accept_pretty_printer(v) do
+ v.visit n_id
+
+ if n_type != null then
+ v.consume ":"
+ v.adds
+ v.visit n_type
+ end
+ end
+end
+
+redef class AType
+ redef fun accept_pretty_printer(v) do
+ if n_kwnullable != null then
+ v.visit n_kwnullable
+ v.adds
+ end
+
+ v.visit n_id
+
+ if not n_types.is_empty then
+ v.consume "["
+ v.visit_list n_types
+ v.consume "]"
+ end
+ end
+end
+
+redef class ASuperclass
+ redef fun accept_pretty_printer(v) do
+ v.visit n_kwsuper
+ v.adds
+ v.visit n_type
+ end
+end
+
+# Properties
+
+redef class APropdef
+ redef fun accept_pretty_printer(v) do
+ v.visit n_doc
+ v.addt
+
+ if not n_visibility isa APublicVisibility then
+ v.visit n_visibility
+ v.adds
+ end
+
+ if n_kwredef != null then
+ v.visit n_kwredef
+ v.adds
+ end
+ end
+
+ redef fun start_token do
+ if n_doc == null then return super
+ return n_doc.last_token.next_token
+ end
+end
+
+redef class AAttrPropdef
+ redef fun accept_pretty_printer(v) do
+ super
+ v.visit n_kwvar
+ v.adds
+ v.visit n_id2
+
+ if n_type != null then
+ v.consume ":"
+ v.adds
+ v.visit n_type
+ end
+
+ if n_expr != null then
+ v.adds
+ v.consume "="
+ v.adds
+ v.visit n_expr
+ end
+
+ if n_annotations != null then v.visit n_annotations
+ v.finish_line
+ v.addn
+ end
+
+ redef fun first_token do
+ if n_doc != null then return n_doc.first_token
+ if not n_visibility isa APublicVisibility then return n_visibility.first_token
+ if n_kwredef != null then return n_kwredef
+ return n_kwvar
+ end
+
+ redef fun is_inlinable do return true
+end
+
+redef class ATypePropdef
+ redef fun accept_pretty_printer(v) do
+ super
+ v.visit n_kwtype
+ v.adds
+ v.visit n_id
+ v.consume ":"
+ v.adds
+ v.visit n_type
+ v.finish_line
+ v.addn
+ end
+
+ redef fun is_inlinable do return true
+end
+
+redef class AMethPropdef
+ redef fun accept_pretty_printer(v) do
+ # TODO: Handle extern annotations
+
+ var before = v.indent
+ var can_inline = v.can_inline(self)
+ super
+ if n_kwinit != null then v.visit n_kwinit
+ if n_kwmeth != null then v.visit n_kwmeth
+ if n_kwnew != null then v.visit n_kwnew
+
+ if not n_methid == null then
+ v.adds
+ v.visit n_methid
+ end
+
+ v.visit n_signature
+
+ if n_annotations != null then
+ v.visit n_annotations
+ else
+ v.adds
+ end
+
+ if n_extern_calls != null or n_extern_code_block != null then
+ if n_annotations != null then v.adds
+ if n_extern_calls != null then v.visit n_extern_calls
+ if n_extern_code_block != null then v.visit n_extern_code_block
+ end
+
+ var n_block = self.n_block
+
+ if n_block != null then
+ while not v.current_token isa TKwdo do v.skip
+ if n_annotations != null then
+ if v.can_inline(n_annotations) then
+ v.adds
+ else
+ v.addt
+ end
+ end
+ v.consume "do"
+
+ if can_inline then
+ v.adds
+
+ if n_block isa ABlockExpr then
+ if n_block.n_expr.is_empty then
+ v.visit n_block.n_kwend
+ else
+ v.visit n_block.n_expr.first
+ v.current_token = n_block.n_kwend
+ v.skip
+ end
+ else
+ v.visit n_block
+ if v.current_token isa TKwend then v.skip
+ end
+ else
+ v.finish_line
+ v.addn
+ v.indent += 1
+
+ if n_block isa ABlockExpr then
+ n_block.force_block = true
+ v.visit n_block
+ v.catch_up n_block.n_kwend
+ else
+ v.addt
+ v.visit n_block
+ v.addn
+ end
+
+ v.indent -= 1
+ v.addt
+ if n_block isa ABlockExpr then
+ v.visit n_block.n_kwend
+ else
+ v.add "end"
+ end
+ end
+ end
+
+ v.finish_line
+ v.addn
+ assert v.indent == before
+ end
+
+ # Can be inlined if:
+ # * block is empty or can be inlined
+ # * contains no comments
+ redef fun is_inlinable do
+ if not super then return false
+ if n_annotations != null and not n_annotations.is_inlinable then return false
+ if n_block != null and not n_block.is_inlinable then return false
+ if n_extern_calls != null and not n_extern_calls.is_inlinable then return false
+ if n_extern_code_block != null and not n_extern_code_block.is_inlinable then return false
+ if not collect_comments.is_empty then return false
+ return true
+ end
+end
+
+redef class AMainMethPropdef
+ redef fun accept_pretty_printer(v) do
+ v.visit n_block
+ v.addn
+ end
+end
+
+redef class ASignature
+ redef fun accept_pretty_printer(v) do
+ if not n_params.is_empty then
+ v.consume "("
+ v.visit_list n_params
+ v.consume ")"
+ end
+
+ if n_type != null then
+ v.consume ":"
+ v.adds
+ v.visit n_type
+ end
+ end
+end
+
+redef class AParam
+ redef fun accept_pretty_printer(v) do
+ v.visit n_id
+
+ if n_type != null then
+ v.consume ":"
+ v.adds
+ v.visit n_type
+ end
+
+ if n_dotdotdot != null then v.visit n_dotdotdot
+ end
+end
+
+# Extern
+
+redef class AExternCalls
+ redef fun accept_pretty_printer(v) do
+ var can_inline = v.can_inline(self)
+ v.visit n_kwimport
+
+ if can_inline then
+ v.adds
+ v.visit_list n_extern_calls
+ else
+ v.addn
+ v.addt
+ v.addt
+ v.visit_list n_extern_calls
+ end
+
+ v.adds
+ end
+end
+
+redef class AFullPropExternCall
+ redef fun accept_pretty_printer(v) do
+ v.visit n_type
+ v.visit n_dot
+ v.visit n_methid
+ end
+end
+
+redef class ALocalPropExternCall
+ redef fun accept_pretty_printer(v) do v.visit n_methid
+end
+
+redef class AInitPropExternCall
+ redef fun accept_pretty_printer(v) do v.visit n_type
+end
+
+redef class ACastAsExternCall
+ redef fun accept_pretty_printer(v) do
+ v.visit n_from_type
+ v.visit n_dot
+ v.visit n_kwas
+ v.consume "("
+ v.visit n_to_type
+ v.consume ")"
+ end
+end
+
+redef class AAsNullableExternCall
+ redef fun accept_pretty_printer(v) do
+ v.visit n_type
+ v.consume "."
+ v.visit n_kwas
+ v.adds
+ v.visit n_kwnullable
+ end
+end
+
+redef class AAsNotNullableExternCall
+ redef fun accept_pretty_printer(v) do
+ v.visit n_type
+ v.consume "."
+ v.visit n_kwas
+ v.adds
+ v.visit n_kwnot
+ v.adds
+ v.visit n_kwnullable
+ end
+end
+
+redef class AExternCodeBlock
+ redef fun accept_pretty_printer(v) do
+ if n_in_language != null then
+ v.visit n_in_language
+ v.adds
+ end
+
+ v.visit n_extern_code_segment
+ end
+
+ redef fun is_inlinable do
+ if not super then return false
+ return n_extern_code_segment.is_inlinable
+ end
+end
+
+redef class AInLanguage
+ redef fun accept_pretty_printer(v) do
+ v.visit n_kwin
+ v.adds
+ v.visit n_string
+ end
+end
+
+redef class TExternCodeSegment
+ redef fun accept_pretty_printer(v) do
+ var can_inline = v.can_inline(self)
+
+ if can_inline then
+ super
+ else
+ var text = text.substring(2, text.length - 4)
+ var lines = text.r_trim.split("\n")
+
+ if text.is_empty then
+ v.add "`\{`\}"
+ else
+ v.add "`\{"
+
+ if not lines.first.trim.is_empty then
+ v.addn
+ lines.first.l_trim
+ v.indent += 1
+ v.addt
+ v.indent -= 1
+ end
+
+ for line in lines do
+ v.add line.r_trim
+ v.addn
+ end
+
+ v.addt
+ v.add "`\}"
+ end
+
+ v.current_token = next_token
+ end
+ end
+
+ redef fun is_inlinable do
+ if not super then return false
+ return location.line_start == location.line_end
+ end
+end
+
+# Blocks
+
+redef class ABlockExpr
+ redef fun accept_pretty_printer(v) do
+ var before = v.indent
+ var can_inline = v.can_inline(self)
+
+ if can_inline and not n_expr.is_empty then
+ v.visit n_expr.first
+ v.finish_line
+ else
+ for nexpr in n_expr do
+ var expr_inline = v.can_inline(nexpr)
+ if not expr_inline and nexpr != n_expr.first then v.addn
+ v.catch_up nexpr
+ v.addt
+ v.visit nexpr
+ v.finish_line
+ v.addn
+ if not expr_inline and nexpr != n_expr.last then v.addn
+ end
+ end
+
+ assert v.indent == before
+ end
+
+ redef fun is_inlinable do
+ if not super then return false
+ if not collect_comments.is_empty then return false
+
+ if not n_expr.is_empty then
+ if n_expr.length > 1 then return false
+ if not n_expr.first.is_inlinable then return false
+ end
+
+ return true
+ end
+end
+
+redef class AIfExpr
+ redef fun accept_pretty_printer(v) do
+ var before = v.indent
+ var can_inline = v.can_inline(self)
+ v.visit n_kwif
+ v.adds
+
+ if v.can_inline(n_expr) then
+ v.visit n_expr
+ v.adds
+ else
+ v.visit n_expr
+ v.addn
+ v.addt
+ end
+
+ # skip comments before `then` token
+ while not v.current_token isa TKwthen do v.skip
+ v.consume "then"
+ var n_else = self.n_else
+
+ if can_inline then
+ v.adds
+ if n_then != null then v.visit n_then
+
+ if has_else(v) then
+ n_else.force_inline = true
+ v.adds
+ v.consume "else"
+ v.adds
+ v.visit n_else
+ else if n_then == null then
+ v.add "end"
+ end
+
+ v.skip_to last_token.last_real_token_in_line
+ else
+ v.finish_line
+ v.addn
+ v.indent += 1
+
+ if n_then != null then
+ if n_then isa ABlockExpr then
+ n_then.force_block = true
+ v.visit n_then
+ else
+ v.addt
+ v.visit n_then
+ v.addn
+ end
+ end
+
+ if has_else(v) then
+ while not v.current_token isa TKwelse do
+ v.consume v.current_token.text
+ end
+
+ v.indent -= 1
+ v.addt
+ v.consume "else"
+
+ if n_else isa AIfExpr then
+ n_else.force_block = true
+ v.adds
+ v.visit n_else
+ else
+ v.finish_line
+ v.addn
+ v.indent += 1
+
+ if n_else isa ABlockExpr then
+ n_else.force_block = true
+ v.visit n_else
+ else
+ v.addt
+ v.visit n_else
+ v.addn
+ end
+
+ if last_token isa TKwend then
+ v.catch_up last_token
+ v.indent -= 1
+ v.addt
+ v.consume "end"
+ else
+ v.indent -= 1
+ v.addt
+ v.add "end"
+ end
+ end
+ else
+ if last_token.location >= v.current_token.location then v.catch_up last_token
+ v.indent -= 1
+ v.addt
+ v.add "end"
+ if v.current_token isa TKwend then v.skip
+ end
+ end
+
+ assert v.indent == before
+ end
+
+ redef fun is_inlinable do
+ if not super then return false
+ if n_then != null and not n_then.is_inlinable then return false
+ var n_else = self.n_else
+ if (n_else isa ABlockExpr and not n_else.n_expr.is_empty) or
+ (not n_else isa ABlockExpr and n_else != null) then
+ return false
+ end
+ if not collect_comments.is_empty then return false
+ return true
+ end
+
+ # Does this `if` statement contains a `else` part?
+ private fun has_else(v: PrettyPrinterVisitor): Bool do
+ var n_else = n_else
+ if n_else == null then return false
+ var n_kwelse = collect_kwelse
+ if n_kwelse == null then return false
+
+ if n_else isa ABlockExpr then
+ var comments: Array[TComment]
+
+ if n_then == null then
+ comments = v.collect_comments(n_expr.last_token, n_else.last_token)
+ else
+ comments = v.collect_comments(n_then.last_token, n_else.last_token)
+ end
+
+ if not comments.is_empty then return true
+ return not n_else.n_expr.is_empty
+ end
+
+ return true
+ end
+
+ # Lookup for `else` token in `self`.
+ private fun collect_kwelse: nullable TKwelse do
+ var token = first_token
+
+ while token != last_token do
+ if token isa TKwelse then return token
+ token = token.next_token
+ end
+
+ return null
+ end
+end
+
+# Used to factorize work on loops.
+private class ALoopHelper
+ super AExpr
+
+ fun loop_block: nullable ANode is abstract
+ fun loop_label: nullable ANode is abstract
+
+ fun visit_loop_block(v: PrettyPrinterVisitor) do
+ var n_block = loop_block
+ v.finish_line
+ v.addn
+ v.indent += 1
+
+ if n_block isa ABlockExpr then
+ n_block.force_block = true
+ v.visit n_block
+ v.catch_up n_block.n_kwend
+ v.indent -= 1
+ v.addt
+ v.visit n_block.n_kwend
+ else
+ v.addt
+ v.visit n_block
+ v.addn
+ v.indent -= 1
+ v.addt
+ v.add "end"
+ end
+
+ if loop_label != null then
+ v.adds
+ v.visit loop_label
+ end
+ end
+
+ fun visit_loop_inline(v: PrettyPrinterVisitor) do
+ var n_block = loop_block
+ v.adds
+
+ if n_block isa ABlockExpr then
+ if n_block.n_expr.is_empty then
+ v.visit n_block.n_kwend
+ else
+ v.visit n_block.n_expr.first
+ v.current_token = n_block.n_kwend
+ v.skip
+ end
+ else
+ v.visit n_block
+ if v.current_token isa TKwend then v.skip
+ end
+
+ if loop_label != null then
+ v.adds
+ v.visit loop_label
+ end
+ end
+
+ redef fun is_inlinable do
+ var n_block = loop_block
+ if not super then return false
+ if n_block isa ABlockExpr and not n_block.is_inlinable then return false
+ if not collect_comments.is_empty then return false
+ return true
+ end
+end
+
+redef class ALoopExpr
+ super ALoopHelper
+
+ redef fun loop_block do return n_block
+ redef fun loop_label do return n_label
+
+ redef fun accept_pretty_printer(v) do
+ var can_inline = v.can_inline(self)
+ v.visit n_kwloop
+ if can_inline then visit_loop_inline v else visit_loop_block v
+ end
+end
+
+redef class AWhileExpr
+ super ALoopHelper
+
+ redef fun loop_block do return n_block
+ redef fun loop_label do return n_label
+
+ redef fun accept_pretty_printer(v) do
+ var can_inline = v.can_inline(self)
+ v.visit n_kwwhile
+ v.adds
+ v.visit n_expr
+ v.adds
+ v.visit n_kwdo
+ if can_inline then visit_loop_inline v else visit_loop_block v
+ end
+end
+
+redef class ADoExpr
+ super ALoopHelper
+
+ redef fun loop_block do return n_block
+ redef fun loop_label do return n_label
+
+ redef fun accept_pretty_printer(v) do
+ var can_inline = v.can_inline(self)
+ v.visit n_kwdo
+ if can_inline then visit_loop_inline v else visit_loop_block v
+ end
+end
+
+redef class AForExpr
+ super ALoopHelper
+
+ redef fun loop_block do return n_block
+ redef fun loop_label do return n_label
+
+ redef fun accept_pretty_printer(v) do
+ var can_inline = v.can_inline(self)
+ v.visit n_kwfor
+ v.adds
+
+ for n_id in n_ids do
+ v.visit n_id
+ if n_id != n_ids.last then v.add ", "
+ end
+
+ v.adds
+ v.consume "in"
+ v.adds
+ v.visit n_expr
+ v.adds
+ v.visit n_kwdo
+ if can_inline then visit_loop_inline v else visit_loop_block v
+ end
+end
+
+redef class ABreakExpr
+ redef fun accept_pretty_printer(v) do
+ v.visit n_kwbreak
+
+ if n_expr != null then
+ v.adds
+ v.visit n_expr
+ end
+
+ if n_label != null then
+ v.adds
+ v.visit n_label
+ end
+ end
+
+ redef fun is_inlinable do return true
+end
+
+redef class AContinueExpr
+ redef fun accept_pretty_printer(v) do
+ v.visit n_kwcontinue
+
+ if n_expr != null then
+ v.adds
+ v.visit n_expr
+ end
+
+ if n_label != null then
+ v.adds
+ v.visit n_label
+ end
+ end
+
+ redef fun is_inlinable do return true
+end
+
+# Calls
+
+redef class ASendExpr
+ redef fun is_inlinable do return true
+end
+
+redef class ACallExpr
+ redef fun accept_pretty_printer(v) do
+ var can_inline = v.can_inline(self)
+ v.visit_recv n_expr
+
+ if not n_expr isa AImplicitSelfExpr and not can_inline then
+ v.addn
+ v.addt
+ v.addt
+ end
+
+ v.visit n_id
+
+ if not n_args.n_exprs.is_empty then
+ if is_stmt and n_args.n_exprs.length == 1 then
+ v.adds
+ if v.current_token isa TOpar then v.skip
+ v.visit n_args.n_exprs.first
+ if v.current_token isa TCpar then v.skip
+ else
+ if v.current_token isa TOpar then
+ v.consume "("
+ else
+ v.adds
+ end
+
+ v.visit_list n_args.n_exprs
+ if v.current_token isa TCpar then v.consume ")"
+ end
+ end
+ end
+
+ # Is the call alone on its line?
+ fun is_stmt: Bool do return parent isa ABlockExpr
+end
+
+redef class ACallAssignExpr
+ redef fun accept_pretty_printer(v) do
+ v.visit_recv n_expr
+ v.visit n_id
+
+ if not n_args.n_exprs.is_empty then
+ v.consume "("
+ v.visit_list n_args.n_exprs
+ v.consume ")"
+ end
+
+ v.adds
+ v.consume "="
+ v.adds
+ v.visit n_value
+ end
+end
+
+redef class ACallReassignExpr
+ redef fun accept_pretty_printer(v) do
+ v.visit_recv n_expr
+ v.visit n_id
+
+ if not n_args.n_exprs.is_empty then
+ v.consume "("
+ v.visit_list n_args.n_exprs
+ v.consume ")"
+ end
+
+ v.adds
+ v.visit n_assign_op
+ v.adds
+ v.visit n_value
+ end
+end
+
+redef class ABraExpr
+ redef fun accept_pretty_printer(v) do
+ v.visit n_expr
+
+ if not n_args.n_exprs.is_empty then
+ v.consume "["
+ v.visit_list n_args.n_exprs
+ v.consume "]"
+ end
+ end
+end
+
+redef class ABraAssignExpr
+ redef fun accept_pretty_printer(v) do
+ v.visit n_expr
+
+ if not n_args.n_exprs.is_empty then
+ v.consume "["
+ v.visit_list n_args.n_exprs
+ v.consume "]"
+ end
+
+ v.adds
+ v.visit n_assign
+ v.adds
+ v.visit n_value
+ end
+end
+
+redef class ABraReassignExpr
+ redef fun accept_pretty_printer(v) do
+ v.visit n_expr
+
+ if not n_args.n_exprs.is_empty then
+ v.consume "["
+ v.visit_list n_args.n_exprs
+ v.consume "]"
+ end
+
+ v.adds
+ v.visit n_assign_op
+ v.adds
+ v.visit n_value
+ end
+end
+
+redef class AAssignMethid
+ redef fun accept_pretty_printer(v) do
+ v.visit n_id
+ v.visit n_assign
+ end
+end
+
+redef class ABraMethid
+ redef fun accept_pretty_printer(v) do
+ v.visit n_obra
+ v.visit n_cbra
+ end
+end
+
+redef class ABraassignMethid
+ redef fun accept_pretty_printer(v) do
+ v.visit n_obra
+ v.visit n_cbra
+ v.visit n_assign
+ end
+end
+
+redef class AInitExpr
+ redef fun accept_pretty_printer(v) do
+ if not n_expr isa AImplicitSelfExpr then
+ v.visit n_expr
+ v.consume "."
+ end
+
+ v.visit n_kwinit
+
+ if not n_args.n_exprs.is_empty then
+ v.consume "("
+ v.visit_list n_args.n_exprs
+ v.consume ")"
+ end
+ end
+end
+
+redef class ANewExpr
+ redef fun accept_pretty_printer(v) do
+ var can_inline = v.can_inline(self)
+ v.visit n_kwnew
+ v.adds
+ v.visit n_type
+
+ if n_id != null then
+ v.consume "."
+
+ if not can_inline then
+ v.addn
+ v.addt
+ v.addt
+ end
+
+ v.visit n_id
+ end
+
+ if not n_args.n_exprs.is_empty then
+ v.consume "("
+ v.visit_list n_args.n_exprs
+ v.consume ")"
+ end
+ end
+
+ redef fun is_inlinable do return true
+end
+
+# Attributes
+
+redef class AAttrExpr
+ redef fun accept_pretty_printer(v) do
+ v.visit_recv n_expr
+ v.visit n_id
+ end
+
+ redef fun is_inlinable do return true
+end
+
+redef class AAttrAssignExpr
+ redef fun accept_pretty_printer(v) do
+ v.visit_recv n_expr
+ v.visit n_id
+ v.adds
+ v.visit n_assign
+ v.adds
+ v.visit n_value
+ end
+end
+
+redef class AAttrReassignExpr
+ redef fun accept_pretty_printer(v) do
+ v.visit_recv n_expr
+ v.visit n_id
+ v.adds
+ v.visit n_assign_op
+ v.adds
+ v.visit n_value
+ end
+end
+
+# Exprs
+
+redef class AVardeclExpr
+ redef fun accept_pretty_printer(v) do
+ v.visit n_kwvar
+ v.adds
+ v.visit n_id
+
+ if n_type != null then
+ v.consume ":"
+ v.adds
+ v.visit n_type
+ end
+
+ if n_expr != null then
+ v.adds
+ v.consume "="
+ v.adds
+ v.visit n_expr
+ end
+ end
+
+ redef fun is_inlinable do return true
+end
+
+redef class AVarAssignExpr
+ redef fun accept_pretty_printer(v) do
+ v.visit n_id
+ v.adds
+ v.visit n_assign
+ v.adds
+ v.visit n_value
+ end
+end
+
+redef class AAssertExpr
+ redef fun accept_pretty_printer(v) do
+ var can_inline = v.can_inline(self)
+ v.visit n_kwassert
+
+ if n_id != null then
+ v.adds
+ v.visit n_id
+ v.consume ":"
+ end
+
+ v.adds
+ v.visit n_expr
+ var n_else = self.n_else
+
+ if n_else != null then
+ v.adds
+ v.consume "else"
+
+ if can_inline then
+ v.adds
+ v.visit n_else
+ else
+ v.addn
+
+ if n_else isa ABlockExpr then
+ v.indent += 1
+ n_else.force_block = true
+ v.visit n_else
+ v.indent -= 1
+ v.addt
+ v.visit n_else.n_kwend
+ else
+ v.indent += 1
+ v.addt
+ v.visit n_else
+ v.addn
+ v.indent -= 1
+ v.addt
+ v.add "end"
+ end
+ end
+ end
+ end
+
+ redef fun is_inlinable do
+ if not super then return false
+ if n_else != null and not n_else.is_inlinable then return false
+ return true
+ end
+end
+
+redef class AReturnExpr
+ redef fun accept_pretty_printer(v) do
+ v.visit n_kwreturn
+
+ if n_expr != null then
+ v.adds
+ v.visit n_expr
+ end
+ end
+end
+
+redef class ASuperExpr
+ redef fun accept_pretty_printer(v) do
+ v.visit n_kwsuper
+
+ if not n_args.n_exprs.is_empty then
+ if is_stmt and n_args.n_exprs.length == 1 then
+ v.adds
+ if v.current_token isa TOpar then v.skip
+ v.visit n_args.n_exprs.first
+ if v.current_token isa TCpar then v.skip
+ else
+ if v.current_token isa TOpar then
+ v.consume "("
+ else
+ v.adds
+ end
+
+ v.visit_list n_args.n_exprs
+ if v.current_token isa TCpar then v.consume ")"
+ end
+ end
+ end
+
+ # Is the call alone on its line?
+ fun is_stmt: Bool do return self.first_token.is_starting_line
+
+ redef fun is_inlinable do return true
+end
+
+redef class AOnceExpr
+ redef fun accept_pretty_printer(v) do
+ v.visit n_kwonce
+ v.adds
+ v.visit n_expr
+ end
+
+ redef fun is_inlinable do return true
+end
+
+redef class AAbortExpr
+ redef fun accept_pretty_printer(v) do v.visit n_kwabort
+ redef fun is_inlinable do return true
+end
+
+redef class ANotExpr
+ redef fun accept_pretty_printer(v) do
+ v.visit n_kwnot
+ v.adds
+ v.visit n_expr
+ end
+end
+
+redef class AAsCastExpr
+ redef fun accept_pretty_printer(v) do
+ v.visit n_expr
+ v.consume "."
+ v.visit n_kwas
+ v.visit n_opar
+ v.visit n_type
+ v.visit n_cpar
+ end
+end
+
+redef class AAsNotnullExpr
+ redef fun accept_pretty_printer(v) do
+ v.visit n_expr
+ v.consume "."
+ v.visit n_kwas
+ v.visit n_opar
+ v.visit n_kwnot
+ v.adds
+ v.visit n_kwnull
+ v.visit n_cpar
+ end
+end
+
+# Binops
+
+# Used to factorize work on Or, And, Implies and Binop expressions.
+private class ABinOpHelper
+ super AExpr
+
+ fun bin_expr1: AExpr is abstract
+ fun bin_expr2: AExpr is abstract
+
+ # Operator string
+ fun bin_op: String is abstract
+
+ redef fun accept_pretty_printer(v) do
+ var can_inline = v.can_inline(self)
+
+ if not can_inline then
+ if (self isa ABinopExpr and bin_expr1 isa ABinopExpr) or
+ (self isa AAndExpr and (bin_expr1 isa AAndExpr or bin_expr1 isa AOrExpr)) or
+ (self isa AOrExpr and (bin_expr1 isa AAndExpr or bin_expr1 isa AOrExpr))
+ then
+ bin_expr1.force_block = true
+ end
+ end
+
+ v.visit bin_expr1
+ v.adds
+ v.consume bin_op
+
+ if can_inline then
+ v.adds
+ v.visit bin_expr2
+ else
+ v.addn
+ v.addt
+ v.addt
+ v.visit bin_expr2
+ end
+ end
+end
+
+redef class AAndExpr
+ super ABinOpHelper
+
+ redef fun bin_expr1 do return n_expr
+ redef fun bin_expr2 do return n_expr2
+ redef fun bin_op do return "and"
+end
+
+redef class AOrExpr
+ super ABinOpHelper
+
+ redef fun bin_expr1 do return n_expr
+ redef fun bin_expr2 do return n_expr2
+ redef fun bin_op do return "or"
+end
+
+redef class AImpliesExpr
+ super ABinOpHelper
+
+ redef fun bin_expr1 do return n_expr
+ redef fun bin_expr2 do return n_expr2
+ redef fun bin_op do return "implies"
+end
+
+redef class ABinopExpr
+ super ABinOpHelper
+
+ redef fun bin_expr1 do return n_expr
+ redef fun bin_expr2 do return n_expr2
+end
+
+redef class AEqExpr
+ redef fun bin_op do return "=="
+end
+
+redef class AGeExpr
+ redef fun bin_op do return ">="
+end
+
+redef class AGgExpr
+ redef fun bin_op do return ">>"
+end
+
+redef class AGtExpr
+ redef fun bin_op do return ">"
+end
+
+redef class ALeExpr
+ redef fun bin_op do return "<="
+end
+
+redef class ALlExpr
+ redef fun bin_op do return "<<"
+end
+
+redef class ALtExpr
+ redef fun bin_op do return "<"
+end
+
+redef class AMinusExpr
+ redef fun bin_op do return "-"
+end
+
+redef class ANeExpr
+ redef fun bin_op do return "!="
+end
+
+redef class APercentExpr
+ redef fun bin_op do return "%"
+end
+
+redef class APlusExpr
+ redef fun bin_op do return "+"
+end
+
+redef class ASlashExpr
+ redef fun bin_op do return "/"
+end
+
+redef class AStarExpr
+ redef fun bin_op do return "*"
+end
+
+redef class AStarstarExpr
+ redef fun bin_op do return "**"
+end
+
+redef class AStarshipExpr
+ redef fun bin_op do return "<=>"
+end
+
+redef class AIsaExpr
+ redef fun accept_pretty_printer(v) do
+ v.visit n_expr
+ v.adds
+ v.consume "isa"
+ v.adds
+ v.visit n_type
+ end
+end
+
+redef class AOrElseExpr
+ redef fun accept_pretty_printer(v) do
+ v.visit n_expr
+ v.adds
+ v.consume "or"
+ v.adds
+ v.consume "else"
+ v.adds
+ v.visit n_expr2
+ end
+
+ redef fun is_inlinable do return true
+end
+
+# Syntax
+
+redef class AUminusExpr
+ redef fun accept_pretty_printer(v) do
+ v.consume "-"
+ v.visit n_expr
+ end
+end
+
+redef class ANullExpr
+ redef fun accept_pretty_printer(v) do v.visit n_kwnull
+ redef fun is_inlinable do return true
+end
+
+redef class AParExpr
+ redef fun accept_pretty_printer(v) do
+ v.visit n_opar
+ v.visit n_expr
+ v.visit n_cpar
+ end
+end
+
+redef class AArrayExpr
+ redef fun accept_pretty_printer(v) do
+ v.consume "["
+ v.visit_list n_exprs.n_exprs
+ v.consume "]"
+ end
+end
+
+redef class ACrangeExpr
+ redef fun accept_pretty_printer(v) do
+ v.visit n_obra
+ v.visit n_expr
+ v.consume ".."
+ v.visit n_expr2
+ v.visit n_cbra
+ end
+end
+
+redef class AOrangeExpr
+ redef fun accept_pretty_printer(v) do
+ v.visit n_obra
+ v.visit n_expr
+ v.consume ".."
+ v.visit n_expr2
+ v.visit n_cbra
+ end
+end
+
+# Strings
+
+redef class AStringFormExpr
+ redef fun accept_pretty_printer(v) do
+ var can_inline = v.can_inline(self)
+
+ if can_inline then
+ v.visit n_string
+ else
+ var text = n_string.text
+ var i = 0
+
+ while i < text.length do
+ v.add text[i].to_s
+
+ if v.current_length >= v.max_size and i <= text.length - 3 then
+ v.add "\" +"
+ v.addn
+ v.indent += 1
+ v.addt
+ v.indent -= 1
+ v.add "\""
+ end
+
+ i += 1
+ end
+
+ v.current_token = n_string.next_token
+ end
+ end
+end
+
+redef class ASuperstringExpr
+ redef fun accept_pretty_printer(v) do
+ for n_expr in n_exprs do v.visit n_expr
+ end
+
+ redef fun must_be_inline do
+ if super then return true
+
+ if not n_exprs.is_empty then
+ var first = n_exprs.first
+ return first isa AStringFormExpr and first.n_string.text.has_prefix("\"\"\"")
+ end
+
+ return false
+ end
+end
# Return a ready-to-save CSV document objet that agregates informations about live types.
# Each discovered type is listed in a line, with its status: resolution, liveness, cast-liveness.
# Note: types are listed in an alphanumeric order to improve human reading.
- fun live_types_to_csv: CSVDocument
+ fun live_types_to_csv: CsvDocument
do
# Gather all kind of type
var typeset = new HashSet[MType]
typeset.add_all(live_open_cast_types)
var types = typeset.to_a
(new CachedAlphaComparator).sort(types)
- var res = new CSVDocument
+ var res = new CsvDocument
+ res.format = new CsvFormat('"', ';', "\n")
res.header = ["Type", "Resolution", "Liveness", "Cast-liveness"]
for t in types do
var reso
if t isa MClassType and (live_types.has(t) or live_open_types.has(t)) then live = "LIVE" else live = "DEAD"
var cast
if live_cast_types.has(t) or live_open_cast_types.has(t) then cast = "CAST LIVE" else cast = "CAST DEAD"
- res.add_line(t, reso, live, cast)
+ res.add_record(t, reso, live, cast)
end
return res
end
var vararg_rank = mmethoddef.msignature.vararg_rank
if vararg_rank > -1 then
- var node = self.modelbuilder.mpropdef2npropdef[mmethoddef]
+ var node = self.modelbuilder.mpropdef2node(mmethoddef)
var elttype = mmethoddef.msignature.mparameters[vararg_rank].mtype
#elttype = elttype.anchor_to(self.mainmodule, v.receiver)
var vararg = self.mainmodule.get_primitive_class("Array").get_mtype([elttype])
add_cast(paramtype)
end
- if not modelbuilder.mpropdef2npropdef.has_key(mmethoddef) then
- # It is an init for a class?
- if mmeth.is_root_init then
- var nclassdef = self.modelbuilder.mclassdef2nclassdef[mmethoddef.mclassdef]
- assert mmethoddef == nclassdef.mfree_init
+ var npropdef = modelbuilder.mpropdef2node(mmethoddef)
- if mmethoddef.mproperty.is_root_init and not mmethoddef.is_intro then
- self.add_super_send(v.receiver, mmethoddef)
- end
- else if mmethoddef.constant_value != null then
- # Make the return type live
- v.add_type(mmethoddef.msignature.return_mtype.as(MClassType))
- else
- abort
+ if npropdef isa AClassdef then
+ # It is an init for a class
+ assert mmethoddef == npropdef.mfree_init
+
+ if mmethoddef.mproperty.is_root_init and not mmethoddef.is_intro then
+ self.add_super_send(v.receiver, mmethoddef)
end
continue
+ else if mmethoddef.constant_value != null then
+ # Make the return type live
+ v.add_type(mmethoddef.msignature.return_mtype.as(MClassType))
+ continue
+ else if npropdef == null then
+ abort
end
- var npropdef = modelbuilder.mpropdef2npropdef[mmethoddef]
-
- if npropdef isa AMethPropdef then
+ if npropdef isa AMethPropdef then
var auto_super_inits = npropdef.auto_super_inits
if auto_super_inits != null then
for auto_super_init in auto_super_inits do
var bound_mtype = mtype.anchor_to(mainmodule, recv)
for cd in bound_mtype.collect_mclassdefs(mainmodule)
do
- if not self.modelbuilder.mclassdef2nclassdef.has_key(cd) then continue
- var nclassdef = self.modelbuilder.mclassdef2nclassdef[cd]
- for npropdef in nclassdef.n_propdefs do
- if not npropdef isa AAttrPropdef then continue
+ for npropdef in modelbuilder.collect_attr_propdef(cd) do
if not npropdef.has_value then continue
var mpropdef = npropdef.mpropdef.as(not null)
var nexpr = self.n_expr
if nexpr != null then
if mtype != null then
- v.visit_expr_subtype(nexpr, mtype)
+ var etype = v.visit_expr_subtype(nexpr, mtype)
+ if etype == mtype then
+ assert ntype != null
+ v.modelbuilder.advice(ntype, "useless-type", "Warning: useless type definition for variable `{variable.name}`")
+ end
else
mtype = v.visit_expr(nexpr)
if mtype == null then return # Skip error
import modelize
import highlight
-import markdown
+import docdown
redef class ModelBuilder
fun test_markdown(page: HTMLTag, mmodule: MModule)
module testing_doc
import testing_base
-intrude import markdown
+intrude import docdown
# Extractor, Executor and Reporter for the tests in a module
class NitUnitExecutor
# All blocks of code from a same `ADoc`
var blocks = new Array[Array[String]]
- redef fun process_code(n: HTMLTag, text: String)
+ # All failures from a same `ADoc`
+ var failures = new Array[String]
+
+ redef fun process_code(n: HTMLTag, text: String, tag: nullable String)
do
# Skip non-blocks
if n.tag != "pre" then return
+ # Skip strict non-nit
+ if tag != null and tag != "nit" and tag != "" then
+ return
+ end
+
# Try to parse it
var ast = toolcontext.parse_something(text)
+ # Skip pure comments
+ if ast isa TComment then return
+
# We want executable code
if not (ast isa AModule or ast isa ABlockExpr or ast isa AExpr) then
- if ndoc != null and n.tag == "pre" and toolcontext.opt_warn.value > 1 then
- toolcontext.warning(ndoc.location, "invalid-block", "Warning: There is a block of code that is not valid Nit, thus not considered a nitunit")
- if ast isa AError then toolcontext.warning(ast.location, "syntax-error", ast.message)
- ndoc = null # To avoid multiple warning in the same node
- end
- return
- end
-
- # Search `assert` in the AST
- var v = new SearchAssertVisitor
- v.enter_visit(ast)
- if not v.foundit then
- if ndoc != null and n.tag == "pre" and toolcontext.opt_warn.value > 1 then
- toolcontext.warning(ndoc.location, "invalid-block", "Warning: There is a block of Nit code without `assert`, thus not considered a nitunit")
- ndoc = null # To avoid multiple warning in the same node
- end
+ var message = ""
+ if ast isa AError then message = " At {ast.location}: {ast.message}."
+ toolcontext.warning(ndoc.location, "invalid-block", "Error: There is a block of code that is not valid Nit, thus not considered a nitunit. To suppress this warning, enclose the block with a fence tagged `nitish` or `raw` (see `man nitdoc`).{message}")
+ failures.add("{ndoc.location}: Invalid block of code.{message}")
return
end
fun extract(ndoc: ADoc, tc: HTMLTag)
do
blocks.clear
+ failures.clear
self.ndoc = ndoc
work(ndoc.to_mdoc)
+
toolcontext.check_errors
+ if not failures.is_empty then
+ for msg in failures do
+ var ne = new HTMLTag("failure")
+ ne.attr("message", msg)
+ tc.add ne
+ toolcontext.modelbuilder.failed_entities += 1
+ end
+ if blocks.is_empty then testsuite.add(tc)
+ end
+
if blocks.is_empty then return
for block in blocks do test_block(ndoc, tc, block)
if not toolcontext.test_dir.file_exists then
toolcontext.test_dir.mkdir
end
+ write_to_nit
+ compile
toolcontext.info("Execute test-suite {mmodule.name}", 1)
var before_module = self.before_module
- if not before_module == null then run_case(before_module)
- for case in test_cases do run_case(case)
+ if not before_module == null then before_module.run
+ for case in test_cases do case.run
var after_module = self.after_module
- if not after_module == null then run_case(after_module)
+ if not after_module == null then after_module.run
end
- # Execute a test case
- fun run_case(test_case: TestCase) do
- test_case.write_to_nit
- test_case.compile
- test_case.run
+ # Write the test unit for `self` in a nit compilable file.
+ fun write_to_nit do
+ var file = new Template
+ file.addn "intrude import test_suite"
+ file.addn "import {mmodule.name}\n"
+ file.addn "var name = args.first"
+ for case in test_cases do
+ case.write_to_nit(file)
+ end
+ file.write_to_file("{test_file}.nit")
end
# Return the test suite in XML format compatible with Jenkins.
fun to_xml: HTMLTag do
var n = new HTMLTag("testsuite")
n.attr("package", mmodule.name)
- for test in test_cases do n.add test.to_xml
+ if failure != null then
+ var f = new HTMLTag("failure")
+ f.attr("message", failure.to_s)
+ n.add f
+ else
+ for test in test_cases do n.add test.to_xml
+ end
return n
end
-end
-
-# A test case is a unit test considering only a `MMethodDef`.
-class TestCase
-
- # Test suite wich `self` belongs to.
- var test_suite: TestSuite
-
- # Test method to be compiled and tested.
- var test_method: MMethodDef
-
- # `ToolContext` to use to display messages and find `nitg` bin.
- var toolcontext: ToolContext
-
- # `MMethodDef` to call before the test case.
- var before_test: nullable MMethodDef = null
-
- # `MMethodDef` to call after the test case.
- var after_test: nullable MMethodDef = null
# Generated test file name.
fun test_file: String do
- var dir = toolcontext.test_dir
- var mod = test_method.mclassdef.mmodule.name
- var cls = test_method.mclassdef.name
- var name = test_method.name
- return "{dir}/{mod}_{cls}_{name}"
- end
-
- # Generate the test unit in a nit file.
- fun write_to_nit do
- var name = test_method.name
- var file = new Template
- file.addn "intrude import test_suite"
- file.addn "import {test_method.mclassdef.mmodule.name}\n"
- if test_method.mproperty.is_toplevel then
- file.addn name
- else
- file.addn "var subject = new {test_method.mclassdef.name}.nitunit"
- if before_test != null then file.addn "subject.{before_test.name}"
- file.addn "subject.{name}"
- if after_test != null then file.addn "subject.{after_test.name}"
- end
- file.write_to_file("{test_file}.nit")
+ return toolcontext.test_dir / "gen_{mmodule.name.escape_to_c}"
end
- # Compile all test cases in once.
+ # Compile all `test_cases` cases in one file.
fun compile do
# find nitg
var nit_dir = toolcontext.nit_dir
end
# compile test suite
var file = test_file
- var include_dir = test_method.mclassdef.mmodule.location.file.filename.dirname
+ var include_dir = mmodule.location.file.filename.dirname
var cmd = "{nitg} --no-color '{file}.nit' -I {include_dir} -o '{file}.bin' > '{file}.out' 2>&1 </dev/null"
var res = sys.system(cmd)
var f = new IFStream.open("{file}.out")
var msg = f.read_all
f.close
# set test case result
- var loc = test_method.location
+ var loc = mmodule.location
if res != 0 then
failure = msg
- toolcontext.warning(loc, "failure", "FAILURE: {test_method.name} (in file {file}.nit): {msg}")
+ toolcontext.warning(loc, "failure", "FAILURE: {mmodule.name} (in file {file}.nit): {msg}")
toolcontext.modelbuilder.failed_tests += 1
end
toolcontext.check_errors
end
+ # Error occured during test-suite compilation.
+ var failure: nullable String = null
+end
+
+# A test case is a unit test considering only a `MMethodDef`.
+class TestCase
+
+ # Test suite wich `self` belongs to.
+ var test_suite: TestSuite
+
+ # Test method to be compiled and tested.
+ var test_method: MMethodDef
+
+ # `ToolContext` to use to display messages and find `nitg` bin.
+ var toolcontext: ToolContext
+
+ # `MMethodDef` to call before the test case.
+ var before_test: nullable MMethodDef = null
+
+ # `MMethodDef` to call after the test case.
+ var after_test: nullable MMethodDef = null
+
+ # Generate the test unit for `self` in `file`.
+ fun write_to_nit(file: Template) do
+ var name = test_method.name
+ file.addn "if name == \"{name}\" then"
+ if test_method.mproperty.is_toplevel then
+ file.addn "\t{name}"
+ else
+ file.addn "\tvar subject = new {test_method.mclassdef.name}.nitunit"
+ if before_test != null then file.addn "\tsubject.{before_test.name}"
+ file.addn "\tsubject.{name}"
+ if after_test != null then file.addn "\tsubject.{after_test.name}"
+ end
+ file.addn "end"
+ end
+
# Execute the test case.
fun run do
toolcontext.info("Execute test-case {test_method.name}", 1)
was_exec = true
if toolcontext.opt_noact.value then return
# execute
- var file = test_file
- var res = sys.system("{file.to_program_name}.bin > '{file}.out1' 2>&1 </dev/null")
- var f = new IFStream.open("{file}.out1")
+ var method_name = test_method.name
+ var test_file = test_suite.test_file
+ var res_name = "{test_file}_{method_name.escape_to_c}"
+ var res = sys.system("{test_file}.bin {method_name} > '{res_name}.out1' 2>&1 </dev/null")
+ var f = new IFStream.open("{res_name}.out1")
var msg = f.read_all
f.close
# set test case result
var loc = test_method.location
if res != 0 then
error = msg
- toolcontext.warning(loc, "failure", "ERROR: {test_method.name} (in file {file}.nit): {msg}")
+ toolcontext.warning(loc, "failure",
+ "ERROR: {method_name} (in file {test_file}.nit): {msg}")
toolcontext.modelbuilder.failed_tests += 1
end
toolcontext.check_errors
end
- # Error occured during execution.
+ # Error occured during test-case execution.
var error: nullable String = null
- # Error occured during compilation.
- var failure: nullable String = null
-
# Was the test case executed at least one?
var was_exec = false
n.attr("message", error.to_s)
tc.add n
end
- if failure != null then
- n = new HTMLTag("failure")
- n.attr("message", failure.to_s)
- tc.add n
- end
end
return tc
end
end
redef class ModelBuilder
+ # Number of test classes generated.
var total_classes = 0
+
+ # Number of tests generated.
var total_tests = 0
+
+ # Number of failed tests.
var failed_tests = 0
# Run NitUnit test file for mmodule (if exists).
test_file = "{include_dir}/{test_file}"
end
if not test_file.file_exists then
- toolcontext.info("Skip test for {mmodule}, no file {test_file} found", 1)
+ toolcontext.info("Skip test for {mmodule}, no file {test_file} found", 2)
return ts
end
var tester = new NitUnitTester(self)
var res = tester.test_module_unit(test_file)
if res == null then
- toolcontext.info("Skip test for {mmodule}, no test suite found", 1)
+ toolcontext.info("Skip test for {mmodule}, no test suite found", 2)
return ts
end
return res.to_xml
private var messages = new Array[Message]
private var message_sorter: Comparator = default_comparator
- # Output all current stacked messages.
- # If some errors occurred, exits the program.
- fun check_errors
+ # Does an error prevent the program to stop at `check_errors`?
+ #
+ # Default to false.
+ # Set this value to `true` if you need to keep the program going in case of error.
+ var keep_going = false is writable
+
+ # Output all current stacked messages and display total error informations
+ #
+ # Return true if no errors occurred.
+ #
+ # If some errors occurred, the behavior depends on the value of `keep_going`.
+ # If `keep_going` is false, then the program exits.
+ # Else, the error count and the warning count are reset and false is returned.
+ fun check_errors: Bool
do
if messages.length > 0 then
message_sorter.sort(messages)
if error_count > 0 then
errors_info
- exit(1)
+ if not keep_going then exit(1)
+ return false
end
+ return true
end
- # Display total error informations
+ # Display (and reset) total error informations
fun errors_info
do
if error_count == 0 and warning_count == 0 then return
if opt_no_color.value then return
sys.stderr.write "Errors: {error_count}. Warnings: {warning_count}.\n"
+ error_count = 0
+ warning_count = 0
end
# Display an error
redef class AArrayExpr
# `[x,y]` is replaced with
#
- # var t = new Array[X].with_capacity(2)
- # t.add(x)
- # t.add(y)
- # t
+ # ~~~nitish
+ # var t = new Array[X].with_capacity(2)
+ # t.add(x)
+ # t.add(y)
+ # t
+ # ~~~
redef fun accept_transform_visitor(v)
do
var nblock = v.builder.make_block
redef class ASendReassignFormExpr
# `x.foo(y)+=z` is replaced with
#
- # x.foo(y) = x.foo(y) + z
+ # ~~~nitish
+ # x.foo(y) = x.foo(y) + z
+ # ~~~
#
# witch is, in reality:
#
- # x."foo="(y, x.foo(y)."+"(z))
+ # ~~~nitish
+ # x."foo="(y, x.foo(y)."+"(z))
+ # ~~~
redef fun accept_transform_visitor(v)
do
var nblock = v.builder.make_block
# Perfect hashing and perfect numbering
var ph: Perfecthashing = new Perfecthashing
- # Handles memory and garbage collection
+ # Handles memory allocated in C
var memory_manager: MemoryManager = new MemoryManager
# The unique instance of the `MInit` value
- var initialization_value: Instance
+ var initialization_value: Instance is noinit
- init(modelbuilder: ModelBuilder, mainmodule: MModule, arguments: Array[String])
+ init
do
var init_type = new MInitType(mainmodule.model)
initialization_value = new MutableInstance(init_type)
super
end
- # Subtyping test for the virtual machine
+ # Runtime subtyping test
redef fun is_subtype(sub, sup: MType): Bool
do
+ if sub == sup then return true
+
var anchor = self.frame.arguments.first.mtype.as(MClassType)
+
+ # `sub` or `sup` are formal or virtual types, resolve them to concrete types
+ if sub isa MParameterType or sub isa MVirtualType then
+ sub = sub.resolve_for(anchor.mclass.mclass_type, anchor, mainmodule, false)
+ end
+ if sup isa MParameterType or sup isa MVirtualType then
+ sup = sup.resolve_for(anchor.mclass.mclass_type, anchor, mainmodule, false)
+ end
+
var sup_accept_null = false
if sup isa MNullableType then
sup_accept_null = true
end
# Now the case of direct null and nullable is over
- # An unfixed formal type can only accept itself
- if sup isa MParameterType or sup isa MVirtualType then
- return sub == sup
- end
-
if sub isa MParameterType or sub isa MVirtualType then
sub = sub.anchor_to(mainmodule, anchor)
# Manage the second layer of null/nullable
assert sup isa MClassType
- # Create the sup vtable if not create
+ # `sub` and `sup` can be discovered inside a Generic type during the subtyping test
if not sup.mclass.loaded then create_class(sup.mclass)
-
- # Sub can be discovered inside a Generic type during the subtyping test
if not sub.mclass.loaded then create_class(sub.mclass)
- if sup isa MGenericType then
- var sub2 = sub.supertype_to(mainmodule, anchor, sup.mclass)
- assert sub2.mclass == sup.mclass
-
- for i in [0..sup.mclass.arity[ do
- var sub_arg = sub2.arguments[i]
- var sup_arg = sup.arguments[i]
- var res = is_subtype(sub_arg, sup_arg)
-
- if res == false then return false
- end
- return true
- end
-
+ # For now, always use perfect hashing for subtyping test
var super_id = sup.mclass.vtable.id
var mask = sub.mclass.vtable.mask
- return inter_is_subtype(super_id, mask, sub.mclass.vtable.internal_vtable)
+ var res = inter_is_subtype_ph(super_id, mask, sub.mclass.vtable.internal_vtable)
+ if res == false then return false
+ # sub and sup can be generic types, each argument of generics has to be tested
+
+ if not sup isa MGenericType then return true
+ var sub2 = sub.supertype_to(mainmodule, anchor, sup.mclass)
+
+ # Test each argument of a generic by recursive calls
+ for i in [0..sup.mclass.arity[ do
+ var sub_arg = sub2.arguments[i]
+ var sup_arg = sup.arguments[i]
+ var res2 = is_subtype(sub_arg, sup_arg)
+ if res2 == false then return false
+ end
+ return true
end
# Subtyping test with perfect hashing
- private fun inter_is_subtype(id: Int, mask:Int, vtable: Pointer): Bool `{
+ private fun inter_is_subtype_ph(id: Int, mask:Int, vtable: Pointer): Bool `{
// hv is the position in hashtable
int hv = id & mask;
return *offset == id;
`}
+ # Subtyping test with Cohen test (direct access)
+ private fun inter_is_subtype_sst(id: Int, position: Int, vtable: Pointer): Bool `{
+ // Direct access to the position given in parameter
+ int tableid = (long unsigned int)((long int *)vtable)[position];
+
+ return id == tableid;
+ `}
+
# Redef init_instance to simulate the loading of a class
redef fun init_instance(recv: Instance)
do
var ret = send_commons(mproperty, args, mtype)
if ret != null then return ret
- var propdef = method_dispatch(mproperty, recv.vtable.as(not null))
+ var propdef = method_dispatch(mproperty, recv.vtable.as(not null), recv)
return self.call(propdef, args)
end
# Method dispatch, for a given global method `mproperty`
# returns the most specific local method in the class corresponding to `vtable`
- private fun method_dispatch(mproperty: MMethod, vtable: VTable): MMethodDef
+ private fun method_dispatch(mproperty: MMethod, vtable: VTable, recv: Instance): MMethodDef
do
- return method_dispatch_ph(vtable.internal_vtable, vtable.mask,
+ if mproperty.intro_mclassdef.mclass.positions_methods[recv.mtype.as(MClassType).mclass] != -1 then
+ return method_dispatch_sst(vtable.internal_vtable, mproperty.absolute_offset)
+ else
+ return method_dispatch_ph(vtable.internal_vtable, vtable.mask,
mproperty.intro_mclassdef.mclass.vtable.id, mproperty.offset)
+ end
end
# Execute a method dispatch with perfect hashing
return propdef;
`}
+ # Execute a method dispatch with direct access and return the appropriate `MMethodDef`
+ # `vtable` : Pointer to the internal pointer of the class
+ # `absolute_offset` : Absolute offset from the beginning of the virtual table
+ private fun method_dispatch_sst(vtable: Pointer, absolute_offset: Int): MMethodDef `{
+ // pointer+2 is the position where methods are
+ // Add the offset of property and get the method implementation
+ MMethodDef propdef = (MMethodDef)((long int *)vtable)[absolute_offset];
+
+ return propdef;
+ `}
+
# Return the value of the attribute `mproperty` for the object `recv`
redef fun read_attribute(mproperty: MAttribute, recv: Instance): Instance
do
assert recv isa MutableInstance
- # Read the attribute value with perfect hashing
- var id = mproperty.intro_mclassdef.mclass.vtable.id
+ var i: Instance
- var i = read_attribute_ph(recv.internal_attributes, recv.vtable.internal_vtable,
+ if mproperty.intro_mclassdef.mclass.positions_attributes[recv.mtype.as(MClassType).mclass] != -1 then
+ # if this attribute class has an unique position for this receiver, then use direct access
+ i = read_attribute_sst(recv.internal_attributes, mproperty.absolute_offset)
+ else
+ # Otherwise, read the attribute value with perfect hashing
+ var id = mproperty.intro_mclassdef.mclass.vtable.id
+
+ i = read_attribute_ph(recv.internal_attributes, recv.vtable.internal_vtable,
recv.vtable.mask, id, mproperty.offset)
+ end
# If we get a `MInit` value, throw an error
if i == initialization_value then
end
# Return the attribute value in `instance` with a sequence of perfect_hashing
- # `instance` is the attributes array of the receiver
- # `vtable` is the pointer to the virtual table of the class (of the receiver)
- # `mask` is the perfect hashing mask of the class
- # `id` is the identifier of the class
- # `offset` is the relative offset of this attribute
+ # * `instance` is the attributes array of the receiver
+ # * `vtable` is the pointer to the virtual table of the class (of the receiver)
+ # * `mask` is the perfect hashing mask of the class
+ # * `id` is the identifier of the class
+ # * `offset` is the relative offset of this attribute
private fun read_attribute_ph(instance: Pointer, vtable: Pointer, mask: Int, id: Int, offset: Int): Instance `{
// Perfect hashing position
int hv = mask & id;
return res;
`}
+ # Return the attribute value in `instance` with a direct access (SST)
+ # * `instance` is the attributes array of the receiver
+ # * `offset` is the absolute offset of this attribute
+ private fun read_attribute_sst(instance: Pointer, offset: Int): Instance `{
+ /* We can make a direct access to the attribute value
+ because this attribute is always at the same position
+ for the class of this receiver */
+ Instance res = ((Instance *)instance)[offset];
+
+ return res;
+ `}
+
# Replace in `recv` the value of the attribute `mproperty` by `value`
redef fun write_attribute(mproperty: MAttribute, recv: Instance, value: Instance)
do
assert recv isa MutableInstance
- var id = mproperty.intro_mclassdef.mclass.vtable.id
-
# Replace the old value of mproperty in recv
- write_attribute_ph(recv.internal_attributes, recv.vtable.internal_vtable,
+ if mproperty.intro_mclassdef.mclass.positions_attributes[recv.mtype.as(MClassType).mclass] != -1 then
+ # if this attribute class has an unique position for this receiver, then use direct access
+ write_attribute_sst(recv.internal_attributes, mproperty.absolute_offset, value)
+ else
+ # Otherwise, use perfect hashing to replace the old value
+ var id = mproperty.intro_mclassdef.mclass.vtable.id
+
+ write_attribute_ph(recv.internal_attributes, recv.vtable.internal_vtable,
recv.vtable.mask, id, mproperty.offset, value)
+ end
end
# Replace the value of an attribute in an instance
- # `instance` is the attributes array of the receiver
- # `vtable` is the pointer to the virtual table of the class (of the receiver)
- # `mask` is the perfect hashing mask of the class
- # `id` is the identifier of the class
- # `offset` is the relative offset of this attribute
- # `value` is the new value for this attribute
+ # * `instance` is the attributes array of the receiver
+ # * `vtable` is the pointer to the virtual table of the class (of the receiver)
+ # * `mask` is the perfect hashing mask of the class
+ # * `id` is the identifier of the class
+ # * `offset` is the relative offset of this attribute
+ # * `value` is the new value for this attribute
private fun write_attribute_ph(instance: Pointer, vtable: Pointer, mask: Int, id: Int, offset: Int, value: Instance) `{
// Perfect hashing position
int hv = mask & id;
Instance_incr_ref(value);
`}
+ # Replace the value of an attribute in an instance with direct access
+ # * `instance` is the attributes array of the receiver
+ # * `offset` is the absolute offset of this attribute
+ # * `value` is the new value for this attribute
+ private fun write_attribute_sst(instance: Pointer, offset: Int, value: Instance) `{
+ // Direct access to the position with the absolute offset
+ ((Instance *)instance)[offset] = value;
+ Instance_incr_ref(value);
+ `}
+
# Is the attribute `mproperty` initialized in the instance `recv`?
redef fun isset_attribute(mproperty: MAttribute, recv: Instance): Bool
do
# True when the class is effectively loaded by the vm, false otherwise
var loaded: Bool = false
+ # Color for Cohen subtyping test : the absolute position of the id
+ # of this class in virtual tables
+ var color: Int
+
# For each loaded subclass, keep the position of the group of attributes
# introduced by self class in the object
var positions_attributes: HashMap[MClass, Int] = new HashMap[MClass, Int]
var nb_methods = new Array[Int]
var nb_attributes = new Array[Int]
- # Absolute offset of the beginning of the attributes table
+ # Absolute offset of attribute from the beginning of the attributes table
var offset_attributes = 0
- # Absolute offset of the beginning of the methods table
- var offset_methods = 0
+ # Absolute offset of method from the beginning of the methods table,
+ # is initialize to 3 because the first position is empty in the virtual table
+ # and the second and third are respectively class id and delta
+ var offset_methods = 3
+
+ # The previous element in `superclasses`
+ var previous_parent: nullable MClass = null
+ if superclasses.length > 0 then previous_parent = superclasses[0]
for parent in superclasses do
if not parent.loaded then parent.make_vt(v)
for p in parent.intro_mproperties(none_visibility) do
if p isa MMethod then methods += 1
- if p isa MAttribute then
- attributes += 1
- end
+ if p isa MAttribute then attributes += 1
end
ids.push(parent.vtable.id)
nb_methods.push(methods)
nb_attributes.push(attributes)
- # Update `positions_attributes` and `positions_methods` in `parent`
- update_positions(offset_attributes, offset_methods, parent)
+ # Update `positions_attributes` and `positions_methods` in `parent`.
+ # If the position is invariant for this parent, store this position
+ # else store a special value (-1)
+ var pos_attr = -1
+ var pos_meth = -1
+
+ if previous_parent.as(not null).positions_attributes[parent] == offset_attributes then pos_attr = offset_attributes
+ if previous_parent.as(not null).positions_methods[parent] == offset_methods then pos_meth = offset_methods
+
+ parent.update_positions(pos_attr, pos_meth, self)
offset_attributes += attributes
offset_methods += methods
+ offset_methods += 2 # Because each block starts with an id and the delta
end
# When all super-classes have their identifiers and vtables, allocate current one
allocate_vtable(v, ids, nb_methods, nb_attributes, offset_attributes, offset_methods)
loaded = true
+ # Set the absolute position of the identifier of this class in the virtual table
+ color = offset_methods - 2
+
# The virtual table now needs to be filled with pointer to methods
superclasses.add(self)
for cl in superclasses do
end
# Allocate a single vtable
- # `ids : Array of superclasses identifiers
- # `nb_methods : Array which contain the number of introduced methods for each class in ids
- # `nb_attributes : Array which contain the number of introduced attributes for each class in ids
- # `offset_attributes : Offset from the beginning of the table of the group of attributes
- # `offset_methods : Offset from the beginning of the table of the group of methods
+ # * `ids : Array of superclasses identifiers
+ # * `nb_methods : Array which contain the number of introduced methods for each class in ids
+ # * `nb_attributes : Array which contain the number of introduced attributes for each class in ids
+ # * `offset_attributes : Offset from the beginning of the table of the group of attributes
+ # * `offset_methods : Offset from the beginning of the table of the group of methods
private fun allocate_vtable(v: VirtualMachine, ids: Array[Int], nb_methods: Array[Int], nb_attributes: Array[Int],
offset_attributes: Int, offset_methods: Int)
do
if p isa MMethod then
self_methods += 1
p.offset = relative_offset_meth
+ p.absolute_offset = offset_methods + relative_offset_meth
relative_offset_meth += 1
end
if p isa MAttribute then
nb_introduced_attributes += 1
p.offset = relative_offset_attr
+ p.absolute_offset = offset_attributes + relative_offset_attr
relative_offset_attr += 1
end
end
nb_attributes_total.push(nb_introduced_attributes)
# Save the offsets of self class
- offset_attributes += nb_introduced_attributes
- offset_methods += self_methods
update_positions(offset_attributes, offset_methods, self)
# Since we have the number of attributes for each class, calculate the delta
- var d = calculate_delta(nb_attributes_total)
- vtable.internal_vtable = v.memory_manager.init_vtable(ids_total, nb_methods_total, d, vtable.mask)
+ var deltas = calculate_delta(nb_attributes_total)
+ vtable.internal_vtable = v.memory_manager.init_vtable(ids_total, nb_methods_total, deltas, vtable.mask)
end
# Fill the vtable with methods of `self` class
- # `v` : Current instance of the VirtualMachine
- # `table` : the table of self class, will be filled with its methods
+ # * `v` : Current instance of the VirtualMachine
+ # * `table` : the table of self class, will be filled with its methods
private fun fill_vtable(v:VirtualMachine, table: VTable, cl: MClass)
do
var methods = new Array[MMethodDef]
# Computes delta for each class
# A delta represents the offset for this group of attributes in the object
- # `nb_attributes` : number of attributes for each class (classes are linearized from Object to current)
- # return deltas for each class
+ # *`nb_attributes` : number of attributes for each class (classes are linearized from Object to current)
+ # * return deltas for each class
private fun calculate_delta(nb_attributes: Array[Int]): Array[Int]
do
var deltas = new Array[Int]
private fun superclasses_ordering(v: VirtualMachine): Array[MClass]
do
var superclasses = new Array[MClass]
- superclasses.add_all(ancestors)
+
+ # Add all superclasses of `self`
+ superclasses.add_all(self.in_hierarchy(v.mainmodule).greaters)
var res = new Array[MClass]
if superclasses.length > 1 then
end
# A kind of Depth-First-Search for superclasses ordering
- # `v` : the current executed instance of VirtualMachine
- # `res` : Result Array, ie current superclasses ordering
+ # *`v` : the current executed instance of VirtualMachine
+ # * `res` : Result Array, ie current superclasses ordering
private fun dfs(v: VirtualMachine, res: Array[MClass]): Array[MClass]
do
# Add this class at the beginning
return res
end
- # Update positions of self class in `parent`
- # `attributes_offset`: absolute offset of introduced attributes
- # `methods_offset`: absolute offset of introduced methods
- private fun update_positions(attributes_offsets: Int, methods_offset:Int, parent: MClass)
+ # Update positions of the class `cl`
+ # * `attributes_offset`: absolute offset of introduced attributes
+ # * `methods_offset`: absolute offset of introduced methods
+ private fun update_positions(attributes_offsets: Int, methods_offset:Int, cl: MClass)
do
- parent.positions_attributes[self] = attributes_offsets
- parent.positions_methods[self] = methods_offset
+ positions_attributes[cl] = attributes_offsets
+ positions_methods[cl] = methods_offset
end
end
redef class MAttribute
- # Represents the relative offset of this attribute in the runtime instance
+ # Relative offset of this attribute in the runtime instance
+ # (beginning of the block of its introducing class)
var offset: Int
+
+ # Absolute offset of this attribute in the runtime instance (beginning of the attribute table)
+ var absolute_offset: Int
end
redef class MMethod
- # Represents the relative offset of this attribute in the runtime instance
+ # Relative offset of this method in the virtual table (from the beginning of the block)
var offset: Int
+
+ # Absolute offset of this method in the virtual table (from the beginning of the vtable)
+ var absolute_offset: Int
end
# Redef MutableInstance to improve implementation of attributes in objects
# Redef to associate an `Instance` to its `VTable`
redef class Instance
+
+ # Associate a runtime instance to its virtual table which contains methods, types etc.
var vtable: nullable VTable
end
super MType
redef var model: Model
- protected init(model: Model)
- do
- self.model = model
- end
redef fun to_s do return "InitType"
redef fun as_nullable do return self
`}
# Put implementation of methods of a class in `vtable`
- # `vtable` : Pointer to the C-virtual table
- # `mask` : perfect-hashing mask of the class corresponding to the vtable
- # `id` : id of the target class
- # `methods` : array of MMethodDef of the target class
+ # * `vtable` : Pointer to the C-virtual table
+ # * `mask` : perfect-hashing mask of the class corresponding to the vtable
+ # * `id` : id of the target class
+ # * `methods` : array of MMethodDef of the target class
fun put_methods(vtable: Pointer, mask: Int, id: Int, methods: Array[MMethodDef])
import Array[MMethodDef].length, Array[MMethodDef].[] `{
--- /dev/null
+cocoa_extern_types
+cocoa_message_box
+hello_cocoa
-PROGS=*.nit ../examples/*.nit ../examples/leapfrog/leapfrog.nit ../examples/shoot/shoot_logic.nit ../contrib/pep8analysis/src/pep8analysis ../lib/*.nit ../src/nitdoc.nit ../src/test_parser.nit ../src/nit.nit ../src/nitmetrics.nit ../src/nitg.nit
+PROGS=*.nit ../examples/*.nit ../examples/leapfrog/leapfrog.nit ../examples/shoot/shoot_logic.nit ../contrib/pep8analysis/src/pep8analysis ../contrib/nitiwiki/src/nitiwiki ../lib/*.nit ../src/nitdoc.nit ../src/test_parser.nit ../src/nit.nit ../src/nitmetrics.nit ../src/nitg.nit
all: niti nitg-g nitg-s
The `$engine.skip` files (where `$engine` is an engine name, see below) describe tests that are skipped completely on a given engine.
Usually it used with then engine `niti` because tests are too long.
-The `cc.skip` file describes tests that are analysed but no executable is generated.
-Usually it is because expected CC errors or missing C libraries.
+The `cc.skip` file describes tests that are analyzed but no executable is generated.
+Usually it is because of expected CC errors or missing C libraries.
The `exec.skip` file describes tests that compiled but not executed.
Usually it is because the programs are interactive or run some kind of server.
+The `$os.skip` file describes tests that are to be skipped completely on the given OS.
+Usually it is because of OS specific libraries.
+
These `*.skip` files contain a list of patterns that will be used against test names.
A single substring can thus be used to skip a full family of tests.
--- /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.
+
+import end
+
+interface Object end
+
+enum Bool end
+
+class A[E: Object]
+ var o: Object
+
+ var e: E
+
+ type VE: E
+ var ve: VE
+
+ type VVE: VE
+ var vve: VVE
+
+ type VGE: G[E]
+ var vge: VGE
+
+ type VVGE: VGE
+ var vvge: VVGE
+
+ type VGVE: G[VE]
+ var vgve: VGVE
+
+ type VGVVE: G[VVE]
+ var vgvve: VGVVE
+
+ fun foo
+ do
+ # In order to check type relations, this test looks for the warnings about useless cast
+ # The following should produce a warning
+ assert o isa Object
+
+ assert e isa E
+ assert e isa Object
+
+ assert ve isa VE
+ assert ve isa E
+ assert ve isa Object
+
+ assert vve isa VVE
+ assert vve isa VE
+ assert vve isa E
+ assert vve isa Object
+
+ assert vge isa VGE
+ assert vge isa G[E]
+ assert vge isa G[Object]
+ assert vge isa Object
+
+ assert vvge isa VVGE
+ assert vvge isa VGE
+ assert vvge isa G[E]
+ assert vvge isa G[Object]
+ assert vvge isa Object
+
+ assert vgve isa VGVE
+ assert vgve isa G[VE]
+ assert vgve isa G[E]
+ assert vgve isa G[Object]
+ assert vgve isa Object
+
+ assert vgvve isa VGVVE
+ assert vgvve isa G[VVE]
+ assert vgvve isa G[VE]
+ assert vgvve isa G[E]
+ assert vgvve isa G[Object]
+ assert vgvve isa Object
+
+ # The following should not
+ assert o isa VGVVE
+ assert o isa G[VVE]
+ assert o isa VVGE
+ assert o isa VGVE
+ assert o isa G[VE]
+ assert o isa VGE
+ assert o isa G[E]
+ assert o isa G[Object]
+ assert o isa VVE
+ assert o isa VE
+ assert o isa E
+
+ assert e isa VGVVE
+ assert e isa G[VVE]
+ assert e isa VVGE
+ assert e isa VGVE
+ assert e isa G[VE]
+ assert e isa VGE
+ assert e isa G[E]
+ assert e isa G[Object]
+ assert e isa VVE
+ assert e isa VE
+
+ assert ve isa VGVVE
+ assert ve isa G[VVE]
+ assert ve isa VVGE
+ assert ve isa VGVE
+ assert ve isa G[VE]
+ assert ve isa VGE
+ assert ve isa G[E]
+ assert ve isa G[Object]
+ assert ve isa VVE
+
+ assert vve isa VGVVE
+ assert vve isa G[VVE]
+ assert vve isa VVGE
+ assert vve isa VGVE
+ assert vve isa G[VE]
+ assert vve isa VGE
+ assert vve isa G[E]
+ assert vve isa G[Object]
+
+ assert vge isa VGVVE
+ assert vge isa G[VVE]
+ assert vge isa VVGE
+ assert vge isa VGVE
+ assert vge isa G[VE]
+ assert vge isa VVE
+ assert vge isa VE
+ assert vge isa E
+
+ assert vvge isa VGVVE
+ assert vvge isa G[VVE]
+ assert vvge isa VGVE
+ assert vvge isa G[VE]
+ assert vvge isa VVE
+ assert vvge isa VE
+ assert vvge isa E
+
+ assert vgve isa VGVVE
+ assert vgve isa G[VVE]
+ assert vgve isa VGE
+ assert vgve isa VVGE
+ assert vgve isa VVE
+ assert vgve isa VE
+ assert vgve isa E
+
+ assert vgvve isa VGE
+ assert vgvve isa VVGE
+ assert vgvve isa VGVE
+ assert vgvve isa VVE
+ assert vgvve isa VE
+ assert vgvve isa E
+ end
+end
+
+class G[E]
+end
--- /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.
+
+import kernel
+
+class X
+ fun foo: SELF do return self
+ fun bar(o: SELF) do o.output_class_name
+end
+
+class Y
+ super X
+
+#alt1# redef fun foo do return new X
+#alt2# redef fun foo do return new Y
+end
+
+class A[E]
+ fun foo: Object do return new G[SELF]
+end
+
+class B[F]
+ super A[F]
+end
+
+class G[E:A[nullable Object]]
+end
+
+var x = new X
+x.output_class_name
+x.foo.output_class_name
+x.bar x
+
+var y = new Y
+y.output_class_name
+y.foo.output_class_name
+x.bar y
+y.bar y
+#alt3# y.bar x
+
+var a = new A[Int]
+a.output_class_name
+a.foo.output_class_name
+
+var b = new B[Bool]
+b.output_class_name
+b.foo.output_class_name
../examples/mpi/src/*.nit \
../lib/*/examples/*.nit \
../contrib/friendz/src/solver_cmd.nit \
+ ../contrib/neo_doxygen/src/tests/neo_doxygen_*.nit \
../contrib/pep8analysis/src/pep8analysis.nit \
+ ../contrib/nitiwiki/src/nitiwiki.nit \
*.nit
--- /dev/null
+'empty project with default settings' ../contrib/neo_doxygen/tests/empty-project/xml
+--src-lang any -- empty-project ../contrib/neo_doxygen/tests/empty-project/xml
+--src-lang java empty-project ../contrib/neo_doxygen/tests/empty-project/xml
+--src-lang any -- foo ../contrib/neo_doxygen/tests/java-project/xml
+--src-lang java -- foo ../contrib/neo_doxygen/tests/java-project/xml
+--src-lang java -- root-namespace ../contrib/neo_doxygen/tests/root-namespace/xml
+--src-lang java -- inner-class ../contrib/neo_doxygen/tests/inner-class/xml
nitg
nitdoc
+nitlight
+neo_doxygen_dump
+neo_doxygen_file_compound
+neo_doxygen_graph_empty_project
+neo_doxygen_member_resolve_introducer
nitg_args5
nitg_args6
nitg_args8
-test_markdown_args1
+nitunit_args
+test_docdown_args
pep8analysis
emscripten
nitserial_args
nitunit_args
nitpretty_args
+hamming_number
+hailstone
--- /dev/null
+nitiwiki --config ../contrib/nitiwiki/tests/wiki1/config2.ini --clean --status
+nitiwiki --config ../contrib/nitiwiki/tests/wiki1/config2.ini --clean --render -v
test_nitunit.nit --gen-suite --only-show
test_nitunit.nit --gen-suite --only-show --private
test_nitunit2.nit -o $WRITE
+test_doc2.nit --no-color -o $WRITE
-base_as_notnull2.nit:30,12--25: Warning: expression is already not null, since it is a `E: Object`.
-base_as_notnull2.nit:50,12--25: Warning: expression is already not null, since it is a `E: Object`.
+base_as_notnull2.nit:30,12--25: Warning: expression is already not null, since it is a `Object`.
+base_as_notnull2.nit:50,12--25: Warning: expression is already not null, since it is a `F: Object`.
1
1
2
-alt/base_as_notnull2_alt1.nit:30,12--25: Warning: expression is already not null, since it is a `E: Object`.
-alt/base_as_notnull2_alt1.nit:50,12--25: Warning: expression is already not null, since it is a `E: Object`.
+alt/base_as_notnull2_alt1.nit:30,12--25: Warning: expression is already not null, since it is a `Object`.
+alt/base_as_notnull2_alt1.nit:50,12--25: Warning: expression is already not null, since it is a `F: Object`.
alt/base_as_notnull2_alt1.nit:58,7--10: Type error: expected Object, got null
-alt/base_as_notnull2_alt2.nit:30,12--25: Warning: expression is already not null, since it is a `E: Object`.
-alt/base_as_notnull2_alt2.nit:50,12--25: Warning: expression is already not null, since it is a `E: Object`.
+alt/base_as_notnull2_alt2.nit:30,12--25: Warning: expression is already not null, since it is a `Object`.
+alt/base_as_notnull2_alt2.nit:50,12--25: Warning: expression is already not null, since it is a `F: Object`.
Runtime error: Cast failed (alt/base_as_notnull2_alt2.nit:40)
1
1
-alt/base_as_notnull2_alt3.nit:30,12--25: Warning: expression is already not null, since it is a `E: Object`.
-alt/base_as_notnull2_alt3.nit:50,12--25: Warning: expression is already not null, since it is a `E: Object`.
+alt/base_as_notnull2_alt3.nit:30,12--25: Warning: expression is already not null, since it is a `Object`.
+alt/base_as_notnull2_alt3.nit:50,12--25: Warning: expression is already not null, since it is a `F: Object`.
alt/base_as_notnull2_alt3.nit:64,7--10: Type error: expected Int, got null
--- /dev/null
+base_formal_subtype.nit:48,10--21: Warning: Expression is already a Object.
+base_formal_subtype.nit:50,10--16: Warning: Expression is already a E.
+base_formal_subtype.nit:51,10--21: Warning: Expression is already a Object since it is a E.
+base_formal_subtype.nit:53,10--18: Warning: Expression is already a VE.
+base_formal_subtype.nit:54,10--17: Warning: Expression is already a E since it is a VE.
+base_formal_subtype.nit:55,10--22: Warning: Expression is already a Object since it is a VE.
+base_formal_subtype.nit:57,10--20: Warning: Expression is already a VVE.
+base_formal_subtype.nit:58,10--19: Warning: Expression is already a VE since it is a VVE.
+base_formal_subtype.nit:59,10--18: Warning: Expression is already a E since it is a VVE.
+base_formal_subtype.nit:60,10--23: Warning: Expression is already a Object since it is a VVE.
+base_formal_subtype.nit:62,10--20: Warning: Expression is already a VGE.
+base_formal_subtype.nit:63,10--20: Warning: Expression is already a G[E] since it is a VGE.
+base_formal_subtype.nit:64,10--25: Warning: Expression is already a G[Object] since it is a VGE.
+base_formal_subtype.nit:65,10--23: Warning: Expression is already a Object since it is a VGE.
+base_formal_subtype.nit:67,10--22: Warning: Expression is already a VVGE.
+base_formal_subtype.nit:68,10--21: Warning: Expression is already a VGE since it is a VVGE.
+base_formal_subtype.nit:69,10--21: Warning: Expression is already a G[E] since it is a VVGE.
+base_formal_subtype.nit:70,10--26: Warning: Expression is already a G[Object] since it is a VVGE.
+base_formal_subtype.nit:71,10--24: Warning: Expression is already a Object since it is a VVGE.
+base_formal_subtype.nit:73,10--22: Warning: Expression is already a VGVE.
+base_formal_subtype.nit:74,10--22: Warning: Expression is already a G[VE] since it is a VGVE.
+base_formal_subtype.nit:75,10--21: Warning: Expression is already a G[E] since it is a VGVE.
+base_formal_subtype.nit:76,10--26: Warning: Expression is already a G[Object] since it is a VGVE.
+base_formal_subtype.nit:77,10--24: Warning: Expression is already a Object since it is a VGVE.
+base_formal_subtype.nit:79,10--24: Warning: Expression is already a VGVVE.
+base_formal_subtype.nit:80,10--24: Warning: Expression is already a G[VVE] since it is a VGVVE.
+base_formal_subtype.nit:81,10--23: Warning: Expression is already a G[VE] since it is a VGVVE.
+base_formal_subtype.nit:82,10--22: Warning: Expression is already a G[E] since it is a VGVVE.
+base_formal_subtype.nit:83,10--27: Warning: Expression is already a G[Object] since it is a VGVVE.
+base_formal_subtype.nit:84,10--25: Warning: Expression is already a Object since it is a VGVVE.
-Runtime error: Cast failed. Expected `E`, got `B` (alt/base_gen_variance2_alt1.nit:27)
+Runtime error: Cast failed. Expected `F`, got `B` (alt/base_gen_variance2_alt1.nit:27)
3
-Runtime error: Cast failed. Expected `E`, got `D` (alt/base_gen_variance2_alt2.nit:27)
+Runtime error: Cast failed. Expected `F`, got `D` (alt/base_gen_variance2_alt2.nit:27)
3
-Runtime error: Cast failed. Expected `E`, got `D` (alt/base_gen_variance3_alt1.nit:27)
+Runtime error: Cast failed. Expected `B`, got `D` (alt/base_gen_variance3_alt1.nit:27)
2
-Runtime error: Cast failed. Expected `E`, got `Char` (alt/base_gen_variance_int_alt1.nit:27)
+Runtime error: Cast failed. Expected `Int`, got `Char` (alt/base_gen_variance_int_alt1.nit:27)
2
--- /dev/null
+X
+X
+X
+Y
+Y
+Y
+Y
+A[Int]
+G[A[Int]]
+B[Bool]
+G[B[Bool]]
--- /dev/null
+alt/base_self_type_alt1.nit:25,25--29: Type error: expected SELF, got X
--- /dev/null
+X
+X
+X
+Y
+Y
+Y
+Y
+A[Int]
+G[A[Int]]
+B[Bool]
+G[B[Bool]]
--- /dev/null
+alt/base_self_type_alt3.nit:50,7: Type error: expected Y, got X
-../lib/standard/kernel.nit:79,1--95,3: Fatal error: kernel#Sys does not specialize module_0#Object. Possible duplication of the root class `Object`?
+../lib/standard/kernel.nit:101,1--117,3: Error: kernel#Sys does not specialize module_0#Object. Possible duplication of the root class `Object`?
alt/error_redef_alt3.nit:28,12--13: Error: No property B::f1 is inherited. Remove the redef keyword to define a new property.
+alt/error_redef_alt3.nit:28,15: Error: Untyped parameter `i'.
alt/error_redef_alt6.nit:31,12--13: Error: No property B::f1 is inherited. Remove the redef keyword to define a new property.
+alt/error_redef_alt6.nit:31,15: Error: Untyped parameter `i'.
alt/error_redef_alt9.nit:34,12--13: Error: No property B::f1 is inherited. Remove the redef keyword to define a new property.
+alt/error_redef_alt9.nit:34,15: Error: Untyped parameter `i'.
--- /dev/null
+Sequence for 27 has 112 begin with: 27, 82, 41, 124 and end with: 8, 4, 2, 1
+The number with longest sequence is 77031 with length of 351
--- /dev/null
+1: 1
+2: 2
+3: 3
+4: 4
+5: 5
+6: 6
+7: 8
+8: 9
+9: 10
+10: 12
+11: 15
+12: 16
+13: 18
+14: 20
+15: 24
+16: 25
+17: 27
+18: 30
+19: 32
+20: 36
+1691: 2125764000
--- /dev/null
+Goodbye, World!
-<!DOCTYPE html><html><head><meta charset="utf-8"/><title>Nit</title><link rel="icon" href="http://nitlanguage.org/favicon.ico" type="image/x-icon"/><link rel="stylesheet" href="http://nitlanguage.org/style.css" type="text/css"/><link rel="stylesheet" href="http://nitlanguage.org/local.css" type="text/css"/></head><body><article class="page"><section class="pageheader"><a id='toptitle_first' class='toptitle'>the</a><a id='toptitle_second' class='toptitle' href=''>Nit</a><a id='toptitle_third' class='toptitle' href=''>Programming Language</a><header class="header"><div class="topsubtitle"><p>A Fun Language for Serious Programming</p></div></header></section><div id="pagebody"><section id="content"><h1># What is Nit?</h1><p>Nit is an object-oriented programming language. The goal of Nit is to propose a robust statically typed programming language where structure is not a pain.</p><p>So, what does the famous hello world program look like, in Nit?</p><pre><tt><span class='normal'>print </span><span class='string'>'Hello, World!'</span></tt></pre><h1># Feature Highlights</h1><h2>Usability</h2><p>Nit's goal is to be usable by real programmers for real projects</p><ul><li><a href="http://en.wikipedia.org/wiki/KISS_principle">KISS principle</a></li><li>Script-like language without verbosity nor cryptic statements</li><li>Painless static types: static typing should help programmers</li><li>Efficient development, efficient execution, efficient evolution.</li></ul><h2>Robustness</h2><p>Nit will help you to write bug-free programs</p><ul><li>Strong static typing</li><li>No more NullPointerException</li></ul><h2>Object-Oriented</h2><p>Nit's guideline is to follow the most powerful OO principles</p><ul><li><a href="./everything_is_an_object/">Everything is an object</a></li><li><a href="./multiple_inheritance/">Multiple inheritance</a></li><li><a href="./refinement/">Open classes</a></li><li><a href="./virtual_types/">Virtual types</a></li></ul><h1># Getting Started</h1><p>Get Nit from its Git repository:</p><pre><code>$ git clone http://nitlanguage.org/nit.git</code></pre><p>Build the compiler (may be long):</p><pre><code>$ cd nit
+<!DOCTYPE html><html><head><meta charset="utf-8"/><title>Nit</title><link rel="icon" href="http://nitlanguage.org/favicon.ico" type="image/x-icon"/><link rel="stylesheet" href="http://nitlanguage.org/style.css" type="text/css"/><link rel="stylesheet" href="http://nitlanguage.org/local.css" type="text/css"/></head><body><article class="page"><section class="pageheader"><a id='toptitle_first' class='toptitle'>the</a><a id='toptitle_second' class='toptitle' href=''>Nit</a><a id='toptitle_third' class='toptitle' href=''>Programming Language</a><header class="header"><div class="topsubtitle"><p>A Fun Language for Serious Programming</p></div></header></section><div id="pagebody"><section id="content"><h1># What is Nit?</h1><p>Nit is an object-oriented programming language. The goal of Nit is to propose a robust statically typed programming language where structure is not a pain.</p><p>So, what does the famous hello world program look like, in Nit?</p><pre><tt><span class='normal'>print </span><span class='string'>'Hello, World!'</span></tt></pre><h1># Feature Highlights</h1><h2>Usability</h2><p>Nit's goal is to be usable by real programmers for real projects</p><ul><li><a href="http://en.wikipedia.org/wiki/KISS_principle">KISS principle</a></li><li>Script-like language without verbosity nor cryptic statements</li><li>Painless static types: static typing should help programmers</li><li>Efficient development, efficient execution, efficient evolution.</li></ul><h2>Robustness</h2><p>Nit will help you to write bug-free programs</p><ul><li>Strong static typing</li><li>No more NullPointerException</li></ul><h2>Object-Oriented</h2><p>Nit's guideline is to follow the most powerful OO principles</p><ul><li><a href="./everything_is_an_object/">Everything is an object</a></li><li><a href="./multiple_inheritance/">Multiple inheritance</a></li><li><a href="./refinement/">Open classes</a></li><li><a href="./virtual_types/">Virtual types</a></li></ul><h1># Getting Started</h1><p>Get Nit from its Git repository:</p><pre><code>$ git clone http://nitlanguage.org/nit.git</code></pre><p>Build the compiler (may be long):</p><pre><code>$ cd nit
$ make</code></pre><p>Compile a program:</p><pre><code>$ bin/nitc examples/hello_world.nit</code></pre><p>Execute the program:</p><pre><code>$ ./hello_world</code></pre></section></div></article></body></html>
\ No newline at end of file
--- /dev/null
+\e[1mNAME\e[m
+ %PROGRAM_NAME% — Doxygen XML to Neo4j.
+
+\e[1mSYNOPSIS\e[m
+ %PROGRAM_NAME% [--dest <url>] [--src-lang <lang>]
+ [--] <project_name> <doxml_dir>
+ %PROGRAM_NAME% [-h|--help]
+
+\e[1mDESCRIPTION\e[m
+ Convert a Doxygen XML output into a model in Neo4j that is readable by the
+ `nx` tool.
+
+\e[1mARGUMENTS\e[m
+ <project_name> The internal name of the project. Must the same name as the
+ one specified to the `nx` tool. Must not begin by an upper
+ case letter.
+
+ <doxml_dir> The directory where the XML documents generated by Doxygen are
+ located.
+
+\e[1mOPTIONS\e[m
+
+ --dest The URL of the destination graph. `http://localhost:7474` by
+ default.
+
+ -h, --help Show the help (this page).
+
+ --src-lang The programming language to assume when processing chunk in the
+ declarations left as-is by Doxygen. Use `any` (the default) to
+ disable any language-specific processing. <any, java>
+
--- /dev/null
+Reading ../contrib/neo_doxygen/tests/empty-project/xml... Done.
+0 file read.
+Linking nodes...\e[s \e[u\e[J Done.
+Saving 2 nodes...
+---===DONE===---
+Saving 2 edges...
+Edge
+=type=4:ROOT
+=properties=JsonObject(0):
+{}
+----
+=from=Node
+=labels=Array(3):
+35:empty project with default settings
+7:MEntity
+8:MProject
+=properties=JsonObject(1):
+{"name":"empty project with default settings"}
+----
+=to=Entity#0:
+=labels=Array(3):
+35:empty project with default settings
+7:MEntity
+6:MGroup
+=properties=JsonObject(2):
+{"full_name":"","name":"empty project with default settings"}
+
+
+Edge
+=type=7:PROJECT
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+35:empty project with default settings
+7:MEntity
+6:MGroup
+=properties=JsonObject(2):
+{"full_name":"","name":"empty project with default settings"}
+----
+=to=Node
+=labels=Array(3):
+35:empty project with default settings
+7:MEntity
+8:MProject
+=properties=JsonObject(1):
+{"name":"empty project with default settings"}
+
+
+---===DONE===---
--- /dev/null
+Reading ../contrib/neo_doxygen/tests/empty-project/xml... Done.
+0 file read.
+Linking nodes...\e[s \e[u\e[J Done.
+Saving 2 nodes...
+---===DONE===---
+Saving 2 edges...
+Edge
+=type=4:ROOT
+=properties=JsonObject(0):
+{}
+----
+=from=Node
+=labels=Array(3):
+13:empty-project
+7:MEntity
+8:MProject
+=properties=JsonObject(1):
+{"name":"empty-project"}
+----
+=to=Entity#0:
+=labels=Array(3):
+13:empty-project
+7:MEntity
+6:MGroup
+=properties=JsonObject(2):
+{"full_name":"","name":"empty-project"}
+
+
+Edge
+=type=7:PROJECT
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+13:empty-project
+7:MEntity
+6:MGroup
+=properties=JsonObject(2):
+{"full_name":"","name":"empty-project"}
+----
+=to=Node
+=labels=Array(3):
+13:empty-project
+7:MEntity
+8:MProject
+=properties=JsonObject(1):
+{"name":"empty-project"}
+
+
+---===DONE===---
--- /dev/null
+Reading ../contrib/neo_doxygen/tests/empty-project/xml... Done.
+0 file read.
+Linking nodes...\e[s \e[u\e[J Done.
+Saving 2 nodes...
+---===DONE===---
+Saving 2 edges...
+Edge
+=type=4:ROOT
+=properties=JsonObject(0):
+{}
+----
+=from=Node
+=labels=Array(3):
+13:empty-project
+7:MEntity
+8:MProject
+=properties=JsonObject(1):
+{"name":"empty-project"}
+----
+=to=Entity#0:
+=labels=Array(3):
+13:empty-project
+7:MEntity
+6:MGroup
+=properties=JsonObject(2):
+{"full_name":"","name":"empty-project"}
+
+
+Edge
+=type=7:PROJECT
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+13:empty-project
+7:MEntity
+6:MGroup
+=properties=JsonObject(2):
+{"full_name":"","name":"empty-project"}
+----
+=to=Node
+=labels=Array(3):
+13:empty-project
+7:MEntity
+8:MProject
+=properties=JsonObject(1):
+{"name":"empty-project"}
+
+
+---===DONE===---
--- /dev/null
+Reading ../contrib/neo_doxygen/tests/java-project/xml... Done.
+15 files read.
+Linking nodes...\e[s \e[u\e[J Done.
+Saving 58 nodes...
+---===DONE===---
+Saving 85 edges...
+Edge
+=type=4:ROOT
+=properties=JsonObject(0):
+{}
+----
+=from=Node
+=labels=Array(3):
+3:foo
+7:MEntity
+8:MProject
+=properties=JsonObject(1):
+{"name":"foo"}
+----
+=to=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MGroup
+=properties=JsonObject(2):
+{"full_name":"","name":"foo"}
+
+
+Edge
+=type=7:PROJECT
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MGroup
+=properties=JsonObject(2):
+{"full_name":"","name":"foo"}
+----
+=to=Node
+=labels=Array(3):
+3:foo
+7:MEntity
+8:MProject
+=properties=JsonObject(1):
+{"name":"foo"}
+
+
+Edge
+=type=8:DECLARES
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#30:namespaceorg_1_1example_1_1foo
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MGroup
+=properties=JsonObject(5):
+{"kind":"namespace","visibility":"","full_name":"org::example::foo","name":"foo","location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/A.java:16,1--1,1"}
+----
+=to=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+7:MModule
+=properties=JsonObject(3):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/A.java:1,1--1,1","name":"A","full_name":"org::example::foo::A"}
+
+
+Edge
+=type=10:INTRODUCES
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+7:MModule
+=properties=JsonObject(3):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/A.java:1,1--1,1","name":"A","full_name":"org::example::foo::A"}
+----
+=to=Entity#32:classorg_1_1example_1_1foo_1_1_a
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MClass
+=properties=JsonObject(5):
+{"kind":"abstract class","visibility":"public","full_name":"org::example::foo::A","name":"A","location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/A.java:18,1--23,1"}
+
+
+Edge
+=type=7:DEFINES
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+7:MModule
+=properties=JsonObject(3):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/A.java:1,1--1,1","name":"A","full_name":"org::example::foo::A"}
+----
+=to=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+9:MClassDef
+=properties=JsonObject(4):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/A.java:18,1--23,1","is_intro":true,"name":"A","full_name":"org::example::foo::A"}
+
+
+Edge
+=type=8:DECLARES
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#30:namespaceorg_1_1example_1_1foo
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MGroup
+=properties=JsonObject(5):
+{"kind":"namespace","visibility":"","full_name":"org::example::foo","name":"foo","location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/A.java:16,1--1,1"}
+----
+=to=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+7:MModule
+=properties=JsonObject(3):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/B.java:1,1--1,1","name":"B","full_name":"org::example::foo::B"}
+
+
+Edge
+=type=10:INTRODUCES
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+7:MModule
+=properties=JsonObject(3):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/B.java:1,1--1,1","name":"B","full_name":"org::example::foo::B"}
+----
+=to=Entity#32:classorg_1_1example_1_1foo_1_1_b
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MClass
+=properties=JsonObject(5):
+{"kind":"class","visibility":"public","full_name":"org::example::foo::B","name":"B","location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/B.java:18,1--29,1"}
+
+
+Edge
+=type=7:DEFINES
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+7:MModule
+=properties=JsonObject(3):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/B.java:1,1--1,1","name":"B","full_name":"org::example::foo::B"}
+----
+=to=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+9:MClassDef
+=properties=JsonObject(4):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/B.java:18,1--29,1","is_intro":true,"name":"B","full_name":"org::example::foo::B"}
+
+
+Edge
+=type=8:DECLARES
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#30:namespaceorg_1_1example_1_1foo
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MGroup
+=properties=JsonObject(5):
+{"kind":"namespace","visibility":"","full_name":"org::example::foo","name":"foo","location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/A.java:16,1--1,1"}
+----
+=to=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+7:MModule
+=properties=JsonObject(3):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/C.java:1,1--1,1","name":"C","full_name":"org::example::foo::C"}
+
+
+Edge
+=type=10:INTRODUCES
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+7:MModule
+=properties=JsonObject(3):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/C.java:1,1--1,1","name":"C","full_name":"org::example::foo::C"}
+----
+=to=Entity#36:interfaceorg_1_1example_1_1foo_1_1_c
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MClass
+=properties=JsonObject(6):
+{"kind":"interface","visibility":"public","full_name":"org::example::foo::C","name":"C","location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/C.java:21,1--31,1","mdoc":["An interface"]}
+
+
+Edge
+=type=7:DEFINES
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+7:MModule
+=properties=JsonObject(3):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/C.java:1,1--1,1","name":"C","full_name":"org::example::foo::C"}
+----
+=to=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+9:MClassDef
+=properties=JsonObject(5):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/C.java:21,1--31,1","is_intro":true,"name":"C","full_name":"org::example::foo::C","mdoc":["An interface"]}
+
+
+Edge
+=type=8:DECLARES
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#30:namespaceorg_1_1example_1_1foo
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MGroup
+=properties=JsonObject(5):
+{"kind":"namespace","visibility":"","full_name":"org::example::foo","name":"foo","location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/A.java:16,1--1,1"}
+----
+=to=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+7:MModule
+=properties=JsonObject(3):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/EmptyClass.java:1,1--1,1","name":"EmptyClass","full_name":"org::example::foo::EmptyClass"}
+
+
+Edge
+=type=10:INTRODUCES
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+7:MModule
+=properties=JsonObject(3):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/EmptyClass.java:1,1--1,1","name":"EmptyClass","full_name":"org::example::foo::EmptyClass"}
+----
+=to=Entity#42:classorg_1_1example_1_1foo_1_1_empty_class
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MClass
+=properties=JsonObject(6):
+{"kind":"class","visibility":"package","full_name":"org::example::foo::EmptyClass","name":"EmptyClass","location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/EmptyClass.java:21,1--21,1","mdoc":["This class is empty and is only visible in this package."]}
+
+
+Edge
+=type=7:DEFINES
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+7:MModule
+=properties=JsonObject(3):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/EmptyClass.java:1,1--1,1","name":"EmptyClass","full_name":"org::example::foo::EmptyClass"}
+----
+=to=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+9:MClassDef
+=properties=JsonObject(5):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/EmptyClass.java:21,1--21,1","is_intro":true,"name":"EmptyClass","full_name":"org::example::foo::EmptyClass","mdoc":["This class is empty and is only visible in this package."]}
+
+
+Edge
+=type=4:TYPE
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+10:MParameter
+=properties=JsonObject(3):
+{"is_vararg":false,"rank":0,"name":"x"}
+----
+=to=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+5:MType
+8:MRawType
+=properties=JsonObject(1):
+{"text":["int"]}
+
+
+Edge
+=type=4:TYPE
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+10:MParameter
+=properties=JsonObject(3):
+{"is_vararg":false,"rank":1,"name":"y"}
+----
+=to=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+5:MType
+8:MRawType
+=properties=JsonObject(1):
+{"text":["EmptyClass"]}
+
+
+Edge
+=type=7:DEFINES
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#67:classorg_1_1example_1_1foo_1_1_a_1add415ae4129969055d678c7e7e048852
+=labels=Array(4):
+3:foo
+7:MEntity
+8:MPropDef
+10:MMethodDef
+=properties=JsonObject(9):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/A.java:22,1--1,1","is_intern":false,"is_extern":false,"is_abstract":false,"visibility":"public","name":"bar","mdoc":["Does something..."],"is_intro":true,"full_name":"org::example::foo::A::bar"}
+----
+=to=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+9:MProperty
+7:MMethod
+=properties=JsonObject(4):
+{"visibility":"public","is_init":false,"name":"bar","full_name":"org::example::foo::A::bar"}
+
+
+Edge
+=type=9:SIGNATURE
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#67:classorg_1_1example_1_1foo_1_1_a_1add415ae4129969055d678c7e7e048852
+=labels=Array(4):
+3:foo
+7:MEntity
+8:MPropDef
+10:MMethodDef
+=properties=JsonObject(9):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/A.java:22,1--1,1","is_intern":false,"is_extern":false,"is_abstract":false,"visibility":"public","name":"bar","mdoc":["Does something..."],"is_intro":true,"full_name":"org::example::foo::A::bar"}
+----
+=to=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+5:MType
+10:MSignature
+=properties=JsonObject(1):
+{"parameter_names":["x","y"]}
+
+
+Edge
+=type=9:PARAMETER
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+5:MType
+10:MSignature
+=properties=JsonObject(1):
+{"parameter_names":["x","y"]}
+----
+=to=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+10:MParameter
+=properties=JsonObject(3):
+{"is_vararg":false,"rank":0,"name":"x"}
+
+
+Edge
+=type=9:PARAMETER
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+5:MType
+10:MSignature
+=properties=JsonObject(1):
+{"parameter_names":["x","y"]}
+----
+=to=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+10:MParameter
+=properties=JsonObject(3):
+{"is_vararg":false,"rank":1,"name":"y"}
+
+
+Edge
+=type=10:RETURNTYPE
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+5:MType
+10:MSignature
+=properties=JsonObject(1):
+{"parameter_names":["x","y"]}
+----
+=to=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+5:MType
+8:MRawType
+=properties=JsonObject(1):
+{"text":["abstract boolean"]}
+
+
+Edge
+=type=4:TYPE
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+10:MParameter
+=properties=JsonObject(3):
+{"is_vararg":false,"rank":0,"name":"x"}
+----
+=to=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+5:MType
+8:MRawType
+=properties=JsonObject(1):
+{"text":["int"]}
+
+
+Edge
+=type=4:TYPE
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+10:MParameter
+=properties=JsonObject(3):
+{"is_vararg":false,"rank":1,"name":"y"}
+----
+=to=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+5:MType
+8:MRawType
+=properties=JsonObject(1):
+{"text":["EmptyClass"]}
+
+
+Edge
+=type=9:CLASSTYPE
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#32:classorg_1_1example_1_1foo_1_1_a
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MClass
+=properties=JsonObject(5):
+{"kind":"abstract class","visibility":"public","full_name":"org::example::foo::A","name":"A","location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/A.java:18,1--23,1"}
+----
+=to=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+5:MType
+10:MClassType
+=properties=JsonObject(2):
+{"name":"A","full_name":"org::example::foo::A"}
+
+
+Edge
+=type=5:CLASS
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+5:MType
+10:MClassType
+=properties=JsonObject(2):
+{"name":"A","full_name":"org::example::foo::A"}
+----
+=to=Entity#32:classorg_1_1example_1_1foo_1_1_a
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MClass
+=properties=JsonObject(5):
+{"kind":"abstract class","visibility":"public","full_name":"org::example::foo::A","name":"A","location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/A.java:18,1--23,1"}
+
+
+Edge
+=type=9:BOUNDTYPE
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+9:MClassDef
+=properties=JsonObject(4):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/A.java:18,1--23,1","is_intro":true,"name":"A","full_name":"org::example::foo::A"}
+----
+=to=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+5:MType
+10:MClassType
+=properties=JsonObject(2):
+{"name":"A","full_name":"org::example::foo::A"}
+
+
+Edge
+=type=6:MCLASS
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+9:MClassDef
+=properties=JsonObject(4):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/A.java:18,1--23,1","is_intro":true,"name":"A","full_name":"org::example::foo::A"}
+----
+=to=Entity#32:classorg_1_1example_1_1foo_1_1_a
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MClass
+=properties=JsonObject(5):
+{"kind":"abstract class","visibility":"public","full_name":"org::example::foo::A","name":"A","location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/A.java:18,1--23,1"}
+
+
+Edge
+=type=10:INTRODUCES
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+9:MClassDef
+=properties=JsonObject(4):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/A.java:18,1--23,1","is_intro":true,"name":"A","full_name":"org::example::foo::A"}
+----
+=to=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+9:MProperty
+7:MMethod
+=properties=JsonObject(4):
+{"visibility":"public","is_init":false,"name":"bar","full_name":"org::example::foo::A::bar"}
+
+
+Edge
+=type=14:INTRO_CLASSDEF
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+9:MProperty
+7:MMethod
+=properties=JsonObject(4):
+{"visibility":"public","is_init":false,"name":"bar","full_name":"org::example::foo::A::bar"}
+----
+=to=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+9:MClassDef
+=properties=JsonObject(4):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/A.java:18,1--23,1","is_intro":true,"name":"A","full_name":"org::example::foo::A"}
+
+
+Edge
+=type=8:DECLARES
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+9:MClassDef
+=properties=JsonObject(4):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/A.java:18,1--23,1","is_intro":true,"name":"A","full_name":"org::example::foo::A"}
+----
+=to=Entity#67:classorg_1_1example_1_1foo_1_1_a_1add415ae4129969055d678c7e7e048852
+=labels=Array(4):
+3:foo
+7:MEntity
+8:MPropDef
+10:MMethodDef
+=properties=JsonObject(9):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/A.java:22,1--1,1","is_intern":false,"is_extern":false,"is_abstract":false,"visibility":"public","name":"bar","mdoc":["Does something..."],"is_intro":true,"full_name":"org::example::foo::A::bar"}
+
+
+Edge
+=type=7:DEFINES
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#67:classorg_1_1example_1_1foo_1_1_b_1ac6b627949b10b9357eefc0cafcae1d87
+=labels=Array(4):
+3:foo
+7:MEntity
+8:MPropDef
+13:MAttributeDef
+=properties=JsonObject(5):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/B.java:19,1---1,1","visibility":"protected","name":"qux","is_intro":true,"full_name":"org::example::foo::B::qux"}
+----
+=to=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+9:MProperty
+10:MAttribute
+=properties=JsonObject(3):
+{"visibility":"protected","name":"qux","full_name":"org::example::foo::B::qux"}
+
+
+Edge
+=type=4:TYPE
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#67:classorg_1_1example_1_1foo_1_1_b_1ac6b627949b10b9357eefc0cafcae1d87
+=labels=Array(4):
+3:foo
+7:MEntity
+8:MPropDef
+13:MAttributeDef
+=properties=JsonObject(5):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/B.java:19,1---1,1","visibility":"protected","name":"qux","is_intro":true,"full_name":"org::example::foo::B::qux"}
+----
+=to=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+5:MType
+8:MRawType
+=properties=JsonObject(1):
+{"text":["String"]}
+
+
+Edge
+=type=4:TYPE
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+10:MParameter
+=properties=JsonObject(3):
+{"is_vararg":false,"rank":0,"name":"x"}
+----
+=to=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+5:MType
+8:MRawType
+=properties=JsonObject(1):
+{"text":["int"]}
+
+
+Edge
+=type=4:TYPE
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+10:MParameter
+=properties=JsonObject(3):
+{"is_vararg":false,"rank":1,"name":"y"}
+----
+=to=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+5:MType
+8:MRawType
+=properties=JsonObject(1):
+{"text":["EmptyClass"]}
+
+
+Edge
+=type=7:DEFINES
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#67:classorg_1_1example_1_1foo_1_1_b_1a11e157943665cc9e3a9be1502ebeb3b5
+=labels=Array(4):
+3:foo
+7:MEntity
+8:MPropDef
+10:MMethodDef
+=properties=JsonObject(8):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/B.java:21,1--23,1","is_intern":false,"is_extern":false,"is_abstract":false,"visibility":"public","name":"bar","is_intro":true,"full_name":"org::example::foo::B::bar"}
+----
+=to=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+9:MProperty
+7:MMethod
+=properties=JsonObject(4):
+{"visibility":"public","is_init":false,"name":"bar","full_name":"org::example::foo::B::bar"}
+
+
+Edge
+=type=9:SIGNATURE
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#67:classorg_1_1example_1_1foo_1_1_b_1a11e157943665cc9e3a9be1502ebeb3b5
+=labels=Array(4):
+3:foo
+7:MEntity
+8:MPropDef
+10:MMethodDef
+=properties=JsonObject(8):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/B.java:21,1--23,1","is_intern":false,"is_extern":false,"is_abstract":false,"visibility":"public","name":"bar","is_intro":true,"full_name":"org::example::foo::B::bar"}
+----
+=to=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+5:MType
+10:MSignature
+=properties=JsonObject(1):
+{"parameter_names":["x","y"]}
+
+
+Edge
+=type=9:PARAMETER
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+5:MType
+10:MSignature
+=properties=JsonObject(1):
+{"parameter_names":["x","y"]}
+----
+=to=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+10:MParameter
+=properties=JsonObject(3):
+{"is_vararg":false,"rank":0,"name":"x"}
+
+
+Edge
+=type=9:PARAMETER
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+5:MType
+10:MSignature
+=properties=JsonObject(1):
+{"parameter_names":["x","y"]}
+----
+=to=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+10:MParameter
+=properties=JsonObject(3):
+{"is_vararg":false,"rank":1,"name":"y"}
+
+
+Edge
+=type=10:RETURNTYPE
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+5:MType
+10:MSignature
+=properties=JsonObject(1):
+{"parameter_names":["x","y"]}
+----
+=to=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+5:MType
+8:MRawType
+=properties=JsonObject(1):
+{"text":["boolean"]}
+
+
+Edge
+=type=4:TYPE
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+10:MParameter
+=properties=JsonObject(3):
+{"is_vararg":false,"rank":0,"name":"x"}
+----
+=to=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+5:MType
+8:MRawType
+=properties=JsonObject(1):
+{"text":["int"]}
+
+
+Edge
+=type=4:TYPE
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+10:MParameter
+=properties=JsonObject(3):
+{"is_vararg":false,"rank":1,"name":"y"}
+----
+=to=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+5:MType
+8:MRawType
+=properties=JsonObject(1):
+{"text":["EmptyClass"]}
+
+
+Edge
+=type=7:DEFINES
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#67:classorg_1_1example_1_1foo_1_1_b_1a733f4e076f29c7d0c41ed258199ea1d9
+=labels=Array(4):
+3:foo
+7:MEntity
+8:MPropDef
+10:MMethodDef
+=properties=JsonObject(9):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/B.java:28,1--28,1","is_intern":false,"is_extern":false,"is_abstract":false,"visibility":"public","name":"baz","mdoc":["Some overriden documentation."],"is_intro":false,"full_name":"org::example::foo::B::baz"}
+----
+=to=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+9:MProperty
+7:MMethod
+=properties=JsonObject(4):
+{"visibility":"public","is_init":false,"name":"baz","full_name":"org::example::foo::C::baz"}
+
+
+Edge
+=type=9:SIGNATURE
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#67:classorg_1_1example_1_1foo_1_1_b_1a733f4e076f29c7d0c41ed258199ea1d9
+=labels=Array(4):
+3:foo
+7:MEntity
+8:MPropDef
+10:MMethodDef
+=properties=JsonObject(9):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/B.java:28,1--28,1","is_intern":false,"is_extern":false,"is_abstract":false,"visibility":"public","name":"baz","mdoc":["Some overriden documentation."],"is_intro":false,"full_name":"org::example::foo::B::baz"}
+----
+=to=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+5:MType
+10:MSignature
+=properties=JsonObject(0):
+{}
+
+
+Edge
+=type=10:RETURNTYPE
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+5:MType
+10:MSignature
+=properties=JsonObject(0):
+{}
+----
+=to=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+5:MType
+8:MRawType
+=properties=JsonObject(1):
+{"text":["void"]}
+
+
+Edge
+=type=9:CLASSTYPE
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#32:classorg_1_1example_1_1foo_1_1_b
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MClass
+=properties=JsonObject(5):
+{"kind":"class","visibility":"public","full_name":"org::example::foo::B","name":"B","location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/B.java:18,1--29,1"}
+----
+=to=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+5:MType
+10:MClassType
+=properties=JsonObject(2):
+{"name":"B","full_name":"org::example::foo::B"}
+
+
+Edge
+=type=5:CLASS
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+5:MType
+10:MClassType
+=properties=JsonObject(2):
+{"name":"B","full_name":"org::example::foo::B"}
+----
+=to=Entity#32:classorg_1_1example_1_1foo_1_1_b
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MClass
+=properties=JsonObject(5):
+{"kind":"class","visibility":"public","full_name":"org::example::foo::B","name":"B","location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/B.java:18,1--29,1"}
+
+
+Edge
+=type=9:BOUNDTYPE
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+9:MClassDef
+=properties=JsonObject(4):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/B.java:18,1--29,1","is_intro":true,"name":"B","full_name":"org::example::foo::B"}
+----
+=to=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+5:MType
+10:MClassType
+=properties=JsonObject(2):
+{"name":"B","full_name":"org::example::foo::B"}
+
+
+Edge
+=type=6:MCLASS
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+9:MClassDef
+=properties=JsonObject(4):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/B.java:18,1--29,1","is_intro":true,"name":"B","full_name":"org::example::foo::B"}
+----
+=to=Entity#32:classorg_1_1example_1_1foo_1_1_b
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MClass
+=properties=JsonObject(5):
+{"kind":"class","visibility":"public","full_name":"org::example::foo::B","name":"B","location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/B.java:18,1--29,1"}
+
+
+Edge
+=type=8:INHERITS
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+9:MClassDef
+=properties=JsonObject(4):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/B.java:18,1--29,1","is_intro":true,"name":"B","full_name":"org::example::foo::B"}
+----
+=to=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+5:MType
+10:MClassType
+=properties=JsonObject(2):
+{"name":"A","full_name":"org::example::foo::A"}
+
+
+Edge
+=type=8:INHERITS
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+9:MClassDef
+=properties=JsonObject(4):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/B.java:18,1--29,1","is_intro":true,"name":"B","full_name":"org::example::foo::B"}
+----
+=to=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+5:MType
+10:MClassType
+=properties=JsonObject(2):
+{"name":"C","full_name":"org::example::foo::C"}
+
+
+Edge
+=type=10:INTRODUCES
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+9:MClassDef
+=properties=JsonObject(4):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/B.java:18,1--29,1","is_intro":true,"name":"B","full_name":"org::example::foo::B"}
+----
+=to=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+9:MProperty
+10:MAttribute
+=properties=JsonObject(3):
+{"visibility":"protected","name":"qux","full_name":"org::example::foo::B::qux"}
+
+
+Edge
+=type=14:INTRO_CLASSDEF
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+9:MProperty
+10:MAttribute
+=properties=JsonObject(3):
+{"visibility":"protected","name":"qux","full_name":"org::example::foo::B::qux"}
+----
+=to=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+9:MClassDef
+=properties=JsonObject(4):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/B.java:18,1--29,1","is_intro":true,"name":"B","full_name":"org::example::foo::B"}
+
+
+Edge
+=type=8:DECLARES
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+9:MClassDef
+=properties=JsonObject(4):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/B.java:18,1--29,1","is_intro":true,"name":"B","full_name":"org::example::foo::B"}
+----
+=to=Entity#67:classorg_1_1example_1_1foo_1_1_b_1ac6b627949b10b9357eefc0cafcae1d87
+=labels=Array(4):
+3:foo
+7:MEntity
+8:MPropDef
+13:MAttributeDef
+=properties=JsonObject(5):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/B.java:19,1---1,1","visibility":"protected","name":"qux","is_intro":true,"full_name":"org::example::foo::B::qux"}
+
+
+Edge
+=type=10:INTRODUCES
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+9:MClassDef
+=properties=JsonObject(4):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/B.java:18,1--29,1","is_intro":true,"name":"B","full_name":"org::example::foo::B"}
+----
+=to=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+9:MProperty
+7:MMethod
+=properties=JsonObject(4):
+{"visibility":"public","is_init":false,"name":"bar","full_name":"org::example::foo::B::bar"}
+
+
+Edge
+=type=14:INTRO_CLASSDEF
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+9:MProperty
+7:MMethod
+=properties=JsonObject(4):
+{"visibility":"public","is_init":false,"name":"bar","full_name":"org::example::foo::B::bar"}
+----
+=to=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+9:MClassDef
+=properties=JsonObject(4):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/B.java:18,1--29,1","is_intro":true,"name":"B","full_name":"org::example::foo::B"}
+
+
+Edge
+=type=8:DECLARES
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+9:MClassDef
+=properties=JsonObject(4):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/B.java:18,1--29,1","is_intro":true,"name":"B","full_name":"org::example::foo::B"}
+----
+=to=Entity#67:classorg_1_1example_1_1foo_1_1_b_1a11e157943665cc9e3a9be1502ebeb3b5
+=labels=Array(4):
+3:foo
+7:MEntity
+8:MPropDef
+10:MMethodDef
+=properties=JsonObject(8):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/B.java:21,1--23,1","is_intern":false,"is_extern":false,"is_abstract":false,"visibility":"public","name":"bar","is_intro":true,"full_name":"org::example::foo::B::bar"}
+
+
+Edge
+=type=8:DECLARES
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+9:MClassDef
+=properties=JsonObject(4):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/B.java:18,1--29,1","is_intro":true,"name":"B","full_name":"org::example::foo::B"}
+----
+=to=Entity#67:classorg_1_1example_1_1foo_1_1_b_1a733f4e076f29c7d0c41ed258199ea1d9
+=labels=Array(4):
+3:foo
+7:MEntity
+8:MPropDef
+10:MMethodDef
+=properties=JsonObject(9):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/B.java:28,1--28,1","is_intern":false,"is_extern":false,"is_abstract":false,"visibility":"public","name":"baz","mdoc":["Some overriden documentation."],"is_intro":false,"full_name":"org::example::foo::B::baz"}
+
+
+Edge
+=type=9:CLASSTYPE
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#42:classorg_1_1example_1_1foo_1_1_empty_class
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MClass
+=properties=JsonObject(6):
+{"kind":"class","visibility":"package","full_name":"org::example::foo::EmptyClass","name":"EmptyClass","location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/EmptyClass.java:21,1--21,1","mdoc":["This class is empty and is only visible in this package."]}
+----
+=to=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+5:MType
+10:MClassType
+=properties=JsonObject(2):
+{"name":"EmptyClass","full_name":"org::example::foo::EmptyClass"}
+
+
+Edge
+=type=5:CLASS
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+5:MType
+10:MClassType
+=properties=JsonObject(2):
+{"name":"EmptyClass","full_name":"org::example::foo::EmptyClass"}
+----
+=to=Entity#42:classorg_1_1example_1_1foo_1_1_empty_class
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MClass
+=properties=JsonObject(6):
+{"kind":"class","visibility":"package","full_name":"org::example::foo::EmptyClass","name":"EmptyClass","location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/EmptyClass.java:21,1--21,1","mdoc":["This class is empty and is only visible in this package."]}
+
+
+Edge
+=type=9:BOUNDTYPE
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+9:MClassDef
+=properties=JsonObject(5):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/EmptyClass.java:21,1--21,1","is_intro":true,"name":"EmptyClass","full_name":"org::example::foo::EmptyClass","mdoc":["This class is empty and is only visible in this package."]}
+----
+=to=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+5:MType
+10:MClassType
+=properties=JsonObject(2):
+{"name":"EmptyClass","full_name":"org::example::foo::EmptyClass"}
+
+
+Edge
+=type=6:MCLASS
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+9:MClassDef
+=properties=JsonObject(5):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/EmptyClass.java:21,1--21,1","is_intro":true,"name":"EmptyClass","full_name":"org::example::foo::EmptyClass","mdoc":["This class is empty and is only visible in this package."]}
+----
+=to=Entity#42:classorg_1_1example_1_1foo_1_1_empty_class
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MClass
+=properties=JsonObject(6):
+{"kind":"class","visibility":"package","full_name":"org::example::foo::EmptyClass","name":"EmptyClass","location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/EmptyClass.java:21,1--21,1","mdoc":["This class is empty and is only visible in this package."]}
+
+
+Edge
+=type=7:DEFINES
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#71:interfaceorg_1_1example_1_1foo_1_1_c_1a4e97061eb40b045e820de05b33c43d21
+=labels=Array(4):
+3:foo
+7:MEntity
+8:MPropDef
+13:MAttributeDef
+=properties=JsonObject(6):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/C.java:25,1---1,1","visibility":"public","name":"THE_ANSWER","mdoc":["\u000e2\u00080\u0009cAnswer to the Ultimate Question of Life, the Universe, and Everything.\u000e2\u00080\u0009c"],"is_intro":true,"full_name":"org::example::foo::C::THE_ANSWER"}
+----
+=to=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+9:MProperty
+10:MAttribute
+=properties=JsonObject(3):
+{"visibility":"public","name":"THE_ANSWER","full_name":"org::example::foo::C::THE_ANSWER"}
+
+
+Edge
+=type=4:TYPE
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#71:interfaceorg_1_1example_1_1foo_1_1_c_1a4e97061eb40b045e820de05b33c43d21
+=labels=Array(4):
+3:foo
+7:MEntity
+8:MPropDef
+13:MAttributeDef
+=properties=JsonObject(6):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/C.java:25,1---1,1","visibility":"public","name":"THE_ANSWER","mdoc":["\u000e2\u00080\u0009cAnswer to the Ultimate Question of Life, the Universe, and Everything.\u000e2\u00080\u0009c"],"is_intro":true,"full_name":"org::example::foo::C::THE_ANSWER"}
+----
+=to=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+5:MType
+8:MRawType
+=properties=JsonObject(1):
+{"text":["final long"]}
+
+
+Edge
+=type=7:DEFINES
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#71:interfaceorg_1_1example_1_1foo_1_1_c_1a28ac7ce349ebb3e4a7747a8dd951582b
+=labels=Array(4):
+3:foo
+7:MEntity
+8:MPropDef
+10:MMethodDef
+=properties=JsonObject(9):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/C.java:30,1--1,1","is_intern":false,"is_extern":false,"is_abstract":false,"visibility":"public","name":"baz","mdoc":["A function with implicit modifiers."],"is_intro":true,"full_name":"org::example::foo::C::baz"}
+----
+=to=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+9:MProperty
+7:MMethod
+=properties=JsonObject(4):
+{"visibility":"public","is_init":false,"name":"baz","full_name":"org::example::foo::C::baz"}
+
+
+Edge
+=type=9:SIGNATURE
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#71:interfaceorg_1_1example_1_1foo_1_1_c_1a28ac7ce349ebb3e4a7747a8dd951582b
+=labels=Array(4):
+3:foo
+7:MEntity
+8:MPropDef
+10:MMethodDef
+=properties=JsonObject(9):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/C.java:30,1--1,1","is_intern":false,"is_extern":false,"is_abstract":false,"visibility":"public","name":"baz","mdoc":["A function with implicit modifiers."],"is_intro":true,"full_name":"org::example::foo::C::baz"}
+----
+=to=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+5:MType
+10:MSignature
+=properties=JsonObject(0):
+{}
+
+
+Edge
+=type=10:RETURNTYPE
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+5:MType
+10:MSignature
+=properties=JsonObject(0):
+{}
+----
+=to=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+5:MType
+8:MRawType
+=properties=JsonObject(1):
+{"text":["void"]}
+
+
+Edge
+=type=9:CLASSTYPE
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#36:interfaceorg_1_1example_1_1foo_1_1_c
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MClass
+=properties=JsonObject(6):
+{"kind":"interface","visibility":"public","full_name":"org::example::foo::C","name":"C","location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/C.java:21,1--31,1","mdoc":["An interface"]}
+----
+=to=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+5:MType
+10:MClassType
+=properties=JsonObject(2):
+{"name":"C","full_name":"org::example::foo::C"}
+
+
+Edge
+=type=5:CLASS
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+5:MType
+10:MClassType
+=properties=JsonObject(2):
+{"name":"C","full_name":"org::example::foo::C"}
+----
+=to=Entity#36:interfaceorg_1_1example_1_1foo_1_1_c
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MClass
+=properties=JsonObject(6):
+{"kind":"interface","visibility":"public","full_name":"org::example::foo::C","name":"C","location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/C.java:21,1--31,1","mdoc":["An interface"]}
+
+
+Edge
+=type=9:BOUNDTYPE
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+9:MClassDef
+=properties=JsonObject(5):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/C.java:21,1--31,1","is_intro":true,"name":"C","full_name":"org::example::foo::C","mdoc":["An interface"]}
+----
+=to=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+5:MType
+10:MClassType
+=properties=JsonObject(2):
+{"name":"C","full_name":"org::example::foo::C"}
+
+
+Edge
+=type=6:MCLASS
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+9:MClassDef
+=properties=JsonObject(5):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/C.java:21,1--31,1","is_intro":true,"name":"C","full_name":"org::example::foo::C","mdoc":["An interface"]}
+----
+=to=Entity#36:interfaceorg_1_1example_1_1foo_1_1_c
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MClass
+=properties=JsonObject(6):
+{"kind":"interface","visibility":"public","full_name":"org::example::foo::C","name":"C","location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/C.java:21,1--31,1","mdoc":["An interface"]}
+
+
+Edge
+=type=10:INTRODUCES
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+9:MClassDef
+=properties=JsonObject(5):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/C.java:21,1--31,1","is_intro":true,"name":"C","full_name":"org::example::foo::C","mdoc":["An interface"]}
+----
+=to=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+9:MProperty
+10:MAttribute
+=properties=JsonObject(3):
+{"visibility":"public","name":"THE_ANSWER","full_name":"org::example::foo::C::THE_ANSWER"}
+
+
+Edge
+=type=14:INTRO_CLASSDEF
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+9:MProperty
+10:MAttribute
+=properties=JsonObject(3):
+{"visibility":"public","name":"THE_ANSWER","full_name":"org::example::foo::C::THE_ANSWER"}
+----
+=to=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+9:MClassDef
+=properties=JsonObject(5):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/C.java:21,1--31,1","is_intro":true,"name":"C","full_name":"org::example::foo::C","mdoc":["An interface"]}
+
+
+Edge
+=type=8:DECLARES
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+9:MClassDef
+=properties=JsonObject(5):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/C.java:21,1--31,1","is_intro":true,"name":"C","full_name":"org::example::foo::C","mdoc":["An interface"]}
+----
+=to=Entity#71:interfaceorg_1_1example_1_1foo_1_1_c_1a4e97061eb40b045e820de05b33c43d21
+=labels=Array(4):
+3:foo
+7:MEntity
+8:MPropDef
+13:MAttributeDef
+=properties=JsonObject(6):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/C.java:25,1---1,1","visibility":"public","name":"THE_ANSWER","mdoc":["\u000e2\u00080\u0009cAnswer to the Ultimate Question of Life, the Universe, and Everything.\u000e2\u00080\u0009c"],"is_intro":true,"full_name":"org::example::foo::C::THE_ANSWER"}
+
+
+Edge
+=type=10:INTRODUCES
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+9:MClassDef
+=properties=JsonObject(5):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/C.java:21,1--31,1","is_intro":true,"name":"C","full_name":"org::example::foo::C","mdoc":["An interface"]}
+----
+=to=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+9:MProperty
+7:MMethod
+=properties=JsonObject(4):
+{"visibility":"public","is_init":false,"name":"baz","full_name":"org::example::foo::C::baz"}
+
+
+Edge
+=type=14:INTRO_CLASSDEF
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+9:MProperty
+7:MMethod
+=properties=JsonObject(4):
+{"visibility":"public","is_init":false,"name":"baz","full_name":"org::example::foo::C::baz"}
+----
+=to=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+9:MClassDef
+=properties=JsonObject(5):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/C.java:21,1--31,1","is_intro":true,"name":"C","full_name":"org::example::foo::C","mdoc":["An interface"]}
+
+
+Edge
+=type=8:DECLARES
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+9:MClassDef
+=properties=JsonObject(5):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/C.java:21,1--31,1","is_intro":true,"name":"C","full_name":"org::example::foo::C","mdoc":["An interface"]}
+----
+=to=Entity#71:interfaceorg_1_1example_1_1foo_1_1_c_1a28ac7ce349ebb3e4a7747a8dd951582b
+=labels=Array(4):
+3:foo
+7:MEntity
+8:MPropDef
+10:MMethodDef
+=properties=JsonObject(9):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/C.java:30,1--1,1","is_intern":false,"is_extern":false,"is_abstract":false,"visibility":"public","name":"baz","mdoc":["A function with implicit modifiers."],"is_intro":true,"full_name":"org::example::foo::C::baz"}
+
+
+Edge
+=type=7:PROJECT
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#12:namespaceorg
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MGroup
+=properties=JsonObject(5):
+{"kind":"namespace","visibility":"","full_name":"org","name":"org","location":"\/dev\/null:1,1--1,1"}
+----
+=to=Node
+=labels=Array(3):
+3:foo
+7:MEntity
+8:MProject
+=properties=JsonObject(1):
+{"name":"foo"}
+
+
+Edge
+=type=6:PARENT
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#12:namespaceorg
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MGroup
+=properties=JsonObject(5):
+{"kind":"namespace","visibility":"","full_name":"org","name":"org","location":"\/dev\/null:1,1--1,1"}
+----
+=to=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MGroup
+=properties=JsonObject(2):
+{"full_name":"","name":"foo"}
+
+
+Edge
+=type=5:NESTS
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MGroup
+=properties=JsonObject(2):
+{"full_name":"","name":"foo"}
+----
+=to=Entity#12:namespaceorg
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MGroup
+=properties=JsonObject(5):
+{"kind":"namespace","visibility":"","full_name":"org","name":"org","location":"\/dev\/null:1,1--1,1"}
+
+
+Edge
+=type=6:PARENT
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#23:namespaceorg_1_1example
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MGroup
+=properties=JsonObject(5):
+{"kind":"namespace","visibility":"","full_name":"org::example","name":"example","location":"\/dev\/null:1,1--1,1"}
+----
+=to=Entity#12:namespaceorg
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MGroup
+=properties=JsonObject(5):
+{"kind":"namespace","visibility":"","full_name":"org","name":"org","location":"\/dev\/null:1,1--1,1"}
+
+
+Edge
+=type=5:NESTS
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#12:namespaceorg
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MGroup
+=properties=JsonObject(5):
+{"kind":"namespace","visibility":"","full_name":"org","name":"org","location":"\/dev\/null:1,1--1,1"}
+----
+=to=Entity#23:namespaceorg_1_1example
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MGroup
+=properties=JsonObject(5):
+{"kind":"namespace","visibility":"","full_name":"org::example","name":"example","location":"\/dev\/null:1,1--1,1"}
+
+
+Edge
+=type=7:PROJECT
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#23:namespaceorg_1_1example
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MGroup
+=properties=JsonObject(5):
+{"kind":"namespace","visibility":"","full_name":"org::example","name":"example","location":"\/dev\/null:1,1--1,1"}
+----
+=to=Node
+=labels=Array(3):
+3:foo
+7:MEntity
+8:MProject
+=properties=JsonObject(1):
+{"name":"foo"}
+
+
+Edge
+=type=6:PARENT
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#30:namespaceorg_1_1example_1_1foo
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MGroup
+=properties=JsonObject(5):
+{"kind":"namespace","visibility":"","full_name":"org::example::foo","name":"foo","location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/A.java:16,1--1,1"}
+----
+=to=Entity#23:namespaceorg_1_1example
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MGroup
+=properties=JsonObject(5):
+{"kind":"namespace","visibility":"","full_name":"org::example","name":"example","location":"\/dev\/null:1,1--1,1"}
+
+
+Edge
+=type=5:NESTS
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#23:namespaceorg_1_1example
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MGroup
+=properties=JsonObject(5):
+{"kind":"namespace","visibility":"","full_name":"org::example","name":"example","location":"\/dev\/null:1,1--1,1"}
+----
+=to=Entity#30:namespaceorg_1_1example_1_1foo
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MGroup
+=properties=JsonObject(5):
+{"kind":"namespace","visibility":"","full_name":"org::example::foo","name":"foo","location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/A.java:16,1--1,1"}
+
+
+Edge
+=type=7:PROJECT
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#30:namespaceorg_1_1example_1_1foo
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MGroup
+=properties=JsonObject(5):
+{"kind":"namespace","visibility":"","full_name":"org::example::foo","name":"foo","location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/A.java:16,1--1,1"}
+----
+=to=Node
+=labels=Array(3):
+3:foo
+7:MEntity
+8:MProject
+=properties=JsonObject(1):
+{"name":"foo"}
+
+
+---===DONE===---
--- /dev/null
+Reading ../contrib/neo_doxygen/tests/java-project/xml... Done.
+15 files read.
+Linking nodes...\e[s \e[u\e[J Done.
+Saving 58 nodes...
+---===DONE===---
+Saving 85 edges...
+Edge
+=type=4:ROOT
+=properties=JsonObject(0):
+{}
+----
+=from=Node
+=labels=Array(3):
+3:foo
+7:MEntity
+8:MProject
+=properties=JsonObject(1):
+{"name":"foo"}
+----
+=to=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MGroup
+=properties=JsonObject(2):
+{"full_name":"","name":"foo"}
+
+
+Edge
+=type=7:PROJECT
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MGroup
+=properties=JsonObject(2):
+{"full_name":"","name":"foo"}
+----
+=to=Node
+=labels=Array(3):
+3:foo
+7:MEntity
+8:MProject
+=properties=JsonObject(1):
+{"name":"foo"}
+
+
+Edge
+=type=8:DECLARES
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#30:namespaceorg_1_1example_1_1foo
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MGroup
+=properties=JsonObject(5):
+{"kind":"namespace","visibility":"","full_name":"org::example::foo","name":"foo","location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/A.java:16,1--1,1"}
+----
+=to=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+7:MModule
+=properties=JsonObject(3):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/A.java:1,1--1,1","name":"A","full_name":"org::example::foo::A"}
+
+
+Edge
+=type=10:INTRODUCES
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+7:MModule
+=properties=JsonObject(3):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/A.java:1,1--1,1","name":"A","full_name":"org::example::foo::A"}
+----
+=to=Entity#32:classorg_1_1example_1_1foo_1_1_a
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MClass
+=properties=JsonObject(5):
+{"kind":"abstract class","visibility":"public","full_name":"org::example::foo::A","name":"A","location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/A.java:18,1--23,1"}
+
+
+Edge
+=type=7:DEFINES
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+7:MModule
+=properties=JsonObject(3):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/A.java:1,1--1,1","name":"A","full_name":"org::example::foo::A"}
+----
+=to=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+9:MClassDef
+=properties=JsonObject(4):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/A.java:18,1--23,1","is_intro":true,"name":"A","full_name":"org::example::foo::A"}
+
+
+Edge
+=type=8:DECLARES
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#30:namespaceorg_1_1example_1_1foo
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MGroup
+=properties=JsonObject(5):
+{"kind":"namespace","visibility":"","full_name":"org::example::foo","name":"foo","location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/A.java:16,1--1,1"}
+----
+=to=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+7:MModule
+=properties=JsonObject(3):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/B.java:1,1--1,1","name":"B","full_name":"org::example::foo::B"}
+
+
+Edge
+=type=10:INTRODUCES
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+7:MModule
+=properties=JsonObject(3):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/B.java:1,1--1,1","name":"B","full_name":"org::example::foo::B"}
+----
+=to=Entity#32:classorg_1_1example_1_1foo_1_1_b
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MClass
+=properties=JsonObject(5):
+{"kind":"class","visibility":"public","full_name":"org::example::foo::B","name":"B","location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/B.java:18,1--29,1"}
+
+
+Edge
+=type=7:DEFINES
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+7:MModule
+=properties=JsonObject(3):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/B.java:1,1--1,1","name":"B","full_name":"org::example::foo::B"}
+----
+=to=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+9:MClassDef
+=properties=JsonObject(4):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/B.java:18,1--29,1","is_intro":true,"name":"B","full_name":"org::example::foo::B"}
+
+
+Edge
+=type=8:DECLARES
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#30:namespaceorg_1_1example_1_1foo
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MGroup
+=properties=JsonObject(5):
+{"kind":"namespace","visibility":"","full_name":"org::example::foo","name":"foo","location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/A.java:16,1--1,1"}
+----
+=to=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+7:MModule
+=properties=JsonObject(3):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/C.java:1,1--1,1","name":"C","full_name":"org::example::foo::C"}
+
+
+Edge
+=type=10:INTRODUCES
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+7:MModule
+=properties=JsonObject(3):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/C.java:1,1--1,1","name":"C","full_name":"org::example::foo::C"}
+----
+=to=Entity#36:interfaceorg_1_1example_1_1foo_1_1_c
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MClass
+=properties=JsonObject(6):
+{"kind":"interface","visibility":"public","full_name":"org::example::foo::C","name":"C","location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/C.java:21,1--31,1","mdoc":["An interface"]}
+
+
+Edge
+=type=7:DEFINES
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+7:MModule
+=properties=JsonObject(3):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/C.java:1,1--1,1","name":"C","full_name":"org::example::foo::C"}
+----
+=to=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+9:MClassDef
+=properties=JsonObject(5):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/C.java:21,1--31,1","is_intro":true,"name":"C","full_name":"org::example::foo::C","mdoc":["An interface"]}
+
+
+Edge
+=type=8:DECLARES
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#30:namespaceorg_1_1example_1_1foo
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MGroup
+=properties=JsonObject(5):
+{"kind":"namespace","visibility":"","full_name":"org::example::foo","name":"foo","location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/A.java:16,1--1,1"}
+----
+=to=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+7:MModule
+=properties=JsonObject(3):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/EmptyClass.java:1,1--1,1","name":"EmptyClass","full_name":"org::example::foo::EmptyClass"}
+
+
+Edge
+=type=10:INTRODUCES
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+7:MModule
+=properties=JsonObject(3):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/EmptyClass.java:1,1--1,1","name":"EmptyClass","full_name":"org::example::foo::EmptyClass"}
+----
+=to=Entity#42:classorg_1_1example_1_1foo_1_1_empty_class
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MClass
+=properties=JsonObject(6):
+{"kind":"class","visibility":"package","full_name":"org::example::foo::EmptyClass","name":"EmptyClass","location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/EmptyClass.java:21,1--21,1","mdoc":["This class is empty and is only visible in this package."]}
+
+
+Edge
+=type=7:DEFINES
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+7:MModule
+=properties=JsonObject(3):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/EmptyClass.java:1,1--1,1","name":"EmptyClass","full_name":"org::example::foo::EmptyClass"}
+----
+=to=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+9:MClassDef
+=properties=JsonObject(5):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/EmptyClass.java:21,1--21,1","is_intro":true,"name":"EmptyClass","full_name":"org::example::foo::EmptyClass","mdoc":["This class is empty and is only visible in this package."]}
+
+
+Edge
+=type=4:TYPE
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+10:MParameter
+=properties=JsonObject(3):
+{"is_vararg":false,"rank":0,"name":"x"}
+----
+=to=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+5:MType
+8:MRawType
+=properties=JsonObject(1):
+{"text":["int"]}
+
+
+Edge
+=type=4:TYPE
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+10:MParameter
+=properties=JsonObject(3):
+{"is_vararg":false,"rank":1,"name":"y"}
+----
+=to=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+5:MType
+8:MRawType
+=properties=JsonObject(1):
+{"text":["EmptyClass"]}
+
+
+Edge
+=type=7:DEFINES
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#67:classorg_1_1example_1_1foo_1_1_a_1add415ae4129969055d678c7e7e048852
+=labels=Array(4):
+3:foo
+7:MEntity
+8:MPropDef
+10:MMethodDef
+=properties=JsonObject(9):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/A.java:22,1--1,1","is_intern":false,"is_extern":false,"is_abstract":true,"visibility":"public","name":"bar","mdoc":["Does something..."],"is_intro":true,"full_name":"org::example::foo::A::bar"}
+----
+=to=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+9:MProperty
+7:MMethod
+=properties=JsonObject(4):
+{"visibility":"public","is_init":false,"name":"bar","full_name":"org::example::foo::A::bar"}
+
+
+Edge
+=type=9:SIGNATURE
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#67:classorg_1_1example_1_1foo_1_1_a_1add415ae4129969055d678c7e7e048852
+=labels=Array(4):
+3:foo
+7:MEntity
+8:MPropDef
+10:MMethodDef
+=properties=JsonObject(9):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/A.java:22,1--1,1","is_intern":false,"is_extern":false,"is_abstract":true,"visibility":"public","name":"bar","mdoc":["Does something..."],"is_intro":true,"full_name":"org::example::foo::A::bar"}
+----
+=to=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+5:MType
+10:MSignature
+=properties=JsonObject(1):
+{"parameter_names":["x","y"]}
+
+
+Edge
+=type=9:PARAMETER
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+5:MType
+10:MSignature
+=properties=JsonObject(1):
+{"parameter_names":["x","y"]}
+----
+=to=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+10:MParameter
+=properties=JsonObject(3):
+{"is_vararg":false,"rank":0,"name":"x"}
+
+
+Edge
+=type=9:PARAMETER
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+5:MType
+10:MSignature
+=properties=JsonObject(1):
+{"parameter_names":["x","y"]}
+----
+=to=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+10:MParameter
+=properties=JsonObject(3):
+{"is_vararg":false,"rank":1,"name":"y"}
+
+
+Edge
+=type=10:RETURNTYPE
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+5:MType
+10:MSignature
+=properties=JsonObject(1):
+{"parameter_names":["x","y"]}
+----
+=to=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+5:MType
+8:MRawType
+=properties=JsonObject(1):
+{"text":["boolean"]}
+
+
+Edge
+=type=4:TYPE
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+10:MParameter
+=properties=JsonObject(3):
+{"is_vararg":false,"rank":0,"name":"x"}
+----
+=to=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+5:MType
+8:MRawType
+=properties=JsonObject(1):
+{"text":["int"]}
+
+
+Edge
+=type=4:TYPE
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+10:MParameter
+=properties=JsonObject(3):
+{"is_vararg":false,"rank":1,"name":"y"}
+----
+=to=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+5:MType
+8:MRawType
+=properties=JsonObject(1):
+{"text":["EmptyClass"]}
+
+
+Edge
+=type=9:CLASSTYPE
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#32:classorg_1_1example_1_1foo_1_1_a
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MClass
+=properties=JsonObject(5):
+{"kind":"abstract class","visibility":"public","full_name":"org::example::foo::A","name":"A","location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/A.java:18,1--23,1"}
+----
+=to=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+5:MType
+10:MClassType
+=properties=JsonObject(2):
+{"name":"A","full_name":"org::example::foo::A"}
+
+
+Edge
+=type=5:CLASS
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+5:MType
+10:MClassType
+=properties=JsonObject(2):
+{"name":"A","full_name":"org::example::foo::A"}
+----
+=to=Entity#32:classorg_1_1example_1_1foo_1_1_a
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MClass
+=properties=JsonObject(5):
+{"kind":"abstract class","visibility":"public","full_name":"org::example::foo::A","name":"A","location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/A.java:18,1--23,1"}
+
+
+Edge
+=type=9:BOUNDTYPE
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+9:MClassDef
+=properties=JsonObject(4):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/A.java:18,1--23,1","is_intro":true,"name":"A","full_name":"org::example::foo::A"}
+----
+=to=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+5:MType
+10:MClassType
+=properties=JsonObject(2):
+{"name":"A","full_name":"org::example::foo::A"}
+
+
+Edge
+=type=6:MCLASS
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+9:MClassDef
+=properties=JsonObject(4):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/A.java:18,1--23,1","is_intro":true,"name":"A","full_name":"org::example::foo::A"}
+----
+=to=Entity#32:classorg_1_1example_1_1foo_1_1_a
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MClass
+=properties=JsonObject(5):
+{"kind":"abstract class","visibility":"public","full_name":"org::example::foo::A","name":"A","location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/A.java:18,1--23,1"}
+
+
+Edge
+=type=10:INTRODUCES
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+9:MClassDef
+=properties=JsonObject(4):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/A.java:18,1--23,1","is_intro":true,"name":"A","full_name":"org::example::foo::A"}
+----
+=to=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+9:MProperty
+7:MMethod
+=properties=JsonObject(4):
+{"visibility":"public","is_init":false,"name":"bar","full_name":"org::example::foo::A::bar"}
+
+
+Edge
+=type=14:INTRO_CLASSDEF
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+9:MProperty
+7:MMethod
+=properties=JsonObject(4):
+{"visibility":"public","is_init":false,"name":"bar","full_name":"org::example::foo::A::bar"}
+----
+=to=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+9:MClassDef
+=properties=JsonObject(4):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/A.java:18,1--23,1","is_intro":true,"name":"A","full_name":"org::example::foo::A"}
+
+
+Edge
+=type=8:DECLARES
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+9:MClassDef
+=properties=JsonObject(4):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/A.java:18,1--23,1","is_intro":true,"name":"A","full_name":"org::example::foo::A"}
+----
+=to=Entity#67:classorg_1_1example_1_1foo_1_1_a_1add415ae4129969055d678c7e7e048852
+=labels=Array(4):
+3:foo
+7:MEntity
+8:MPropDef
+10:MMethodDef
+=properties=JsonObject(9):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/A.java:22,1--1,1","is_intern":false,"is_extern":false,"is_abstract":true,"visibility":"public","name":"bar","mdoc":["Does something..."],"is_intro":true,"full_name":"org::example::foo::A::bar"}
+
+
+Edge
+=type=7:DEFINES
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#67:classorg_1_1example_1_1foo_1_1_b_1ac6b627949b10b9357eefc0cafcae1d87
+=labels=Array(4):
+3:foo
+7:MEntity
+8:MPropDef
+13:MAttributeDef
+=properties=JsonObject(5):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/B.java:19,1---1,1","visibility":"protected","name":"qux","is_intro":true,"full_name":"org::example::foo::B::qux"}
+----
+=to=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+9:MProperty
+10:MAttribute
+=properties=JsonObject(3):
+{"visibility":"protected","name":"qux","full_name":"org::example::foo::B::qux"}
+
+
+Edge
+=type=4:TYPE
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#67:classorg_1_1example_1_1foo_1_1_b_1ac6b627949b10b9357eefc0cafcae1d87
+=labels=Array(4):
+3:foo
+7:MEntity
+8:MPropDef
+13:MAttributeDef
+=properties=JsonObject(5):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/B.java:19,1---1,1","visibility":"protected","name":"qux","is_intro":true,"full_name":"org::example::foo::B::qux"}
+----
+=to=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+5:MType
+8:MRawType
+=properties=JsonObject(1):
+{"text":["String"]}
+
+
+Edge
+=type=4:TYPE
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+10:MParameter
+=properties=JsonObject(3):
+{"is_vararg":false,"rank":0,"name":"x"}
+----
+=to=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+5:MType
+8:MRawType
+=properties=JsonObject(1):
+{"text":["int"]}
+
+
+Edge
+=type=4:TYPE
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+10:MParameter
+=properties=JsonObject(3):
+{"is_vararg":false,"rank":1,"name":"y"}
+----
+=to=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+5:MType
+8:MRawType
+=properties=JsonObject(1):
+{"text":["EmptyClass"]}
+
+
+Edge
+=type=7:DEFINES
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#67:classorg_1_1example_1_1foo_1_1_b_1a11e157943665cc9e3a9be1502ebeb3b5
+=labels=Array(4):
+3:foo
+7:MEntity
+8:MPropDef
+10:MMethodDef
+=properties=JsonObject(8):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/B.java:21,1--23,1","is_intern":false,"is_extern":false,"is_abstract":false,"visibility":"public","name":"bar","is_intro":true,"full_name":"org::example::foo::B::bar"}
+----
+=to=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+9:MProperty
+7:MMethod
+=properties=JsonObject(4):
+{"visibility":"public","is_init":false,"name":"bar","full_name":"org::example::foo::B::bar"}
+
+
+Edge
+=type=9:SIGNATURE
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#67:classorg_1_1example_1_1foo_1_1_b_1a11e157943665cc9e3a9be1502ebeb3b5
+=labels=Array(4):
+3:foo
+7:MEntity
+8:MPropDef
+10:MMethodDef
+=properties=JsonObject(8):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/B.java:21,1--23,1","is_intern":false,"is_extern":false,"is_abstract":false,"visibility":"public","name":"bar","is_intro":true,"full_name":"org::example::foo::B::bar"}
+----
+=to=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+5:MType
+10:MSignature
+=properties=JsonObject(1):
+{"parameter_names":["x","y"]}
+
+
+Edge
+=type=9:PARAMETER
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+5:MType
+10:MSignature
+=properties=JsonObject(1):
+{"parameter_names":["x","y"]}
+----
+=to=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+10:MParameter
+=properties=JsonObject(3):
+{"is_vararg":false,"rank":0,"name":"x"}
+
+
+Edge
+=type=9:PARAMETER
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+5:MType
+10:MSignature
+=properties=JsonObject(1):
+{"parameter_names":["x","y"]}
+----
+=to=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+10:MParameter
+=properties=JsonObject(3):
+{"is_vararg":false,"rank":1,"name":"y"}
+
+
+Edge
+=type=10:RETURNTYPE
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+5:MType
+10:MSignature
+=properties=JsonObject(1):
+{"parameter_names":["x","y"]}
+----
+=to=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+5:MType
+8:MRawType
+=properties=JsonObject(1):
+{"text":["boolean"]}
+
+
+Edge
+=type=4:TYPE
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+10:MParameter
+=properties=JsonObject(3):
+{"is_vararg":false,"rank":0,"name":"x"}
+----
+=to=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+5:MType
+8:MRawType
+=properties=JsonObject(1):
+{"text":["int"]}
+
+
+Edge
+=type=4:TYPE
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+10:MParameter
+=properties=JsonObject(3):
+{"is_vararg":false,"rank":1,"name":"y"}
+----
+=to=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+5:MType
+8:MRawType
+=properties=JsonObject(1):
+{"text":["EmptyClass"]}
+
+
+Edge
+=type=7:DEFINES
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#67:classorg_1_1example_1_1foo_1_1_b_1a733f4e076f29c7d0c41ed258199ea1d9
+=labels=Array(4):
+3:foo
+7:MEntity
+8:MPropDef
+10:MMethodDef
+=properties=JsonObject(9):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/B.java:28,1--28,1","is_intern":false,"is_extern":false,"is_abstract":false,"visibility":"public","name":"baz","mdoc":["Some overriden documentation."],"is_intro":false,"full_name":"org::example::foo::B::baz"}
+----
+=to=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+9:MProperty
+7:MMethod
+=properties=JsonObject(4):
+{"visibility":"public","is_init":false,"name":"baz","full_name":"org::example::foo::C::baz"}
+
+
+Edge
+=type=9:SIGNATURE
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#67:classorg_1_1example_1_1foo_1_1_b_1a733f4e076f29c7d0c41ed258199ea1d9
+=labels=Array(4):
+3:foo
+7:MEntity
+8:MPropDef
+10:MMethodDef
+=properties=JsonObject(9):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/B.java:28,1--28,1","is_intern":false,"is_extern":false,"is_abstract":false,"visibility":"public","name":"baz","mdoc":["Some overriden documentation."],"is_intro":false,"full_name":"org::example::foo::B::baz"}
+----
+=to=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+5:MType
+10:MSignature
+=properties=JsonObject(0):
+{}
+
+
+Edge
+=type=10:RETURNTYPE
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+5:MType
+10:MSignature
+=properties=JsonObject(0):
+{}
+----
+=to=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+5:MType
+8:MRawType
+=properties=JsonObject(1):
+{"text":["void"]}
+
+
+Edge
+=type=9:CLASSTYPE
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#32:classorg_1_1example_1_1foo_1_1_b
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MClass
+=properties=JsonObject(5):
+{"kind":"class","visibility":"public","full_name":"org::example::foo::B","name":"B","location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/B.java:18,1--29,1"}
+----
+=to=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+5:MType
+10:MClassType
+=properties=JsonObject(2):
+{"name":"B","full_name":"org::example::foo::B"}
+
+
+Edge
+=type=5:CLASS
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+5:MType
+10:MClassType
+=properties=JsonObject(2):
+{"name":"B","full_name":"org::example::foo::B"}
+----
+=to=Entity#32:classorg_1_1example_1_1foo_1_1_b
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MClass
+=properties=JsonObject(5):
+{"kind":"class","visibility":"public","full_name":"org::example::foo::B","name":"B","location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/B.java:18,1--29,1"}
+
+
+Edge
+=type=9:BOUNDTYPE
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+9:MClassDef
+=properties=JsonObject(4):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/B.java:18,1--29,1","is_intro":true,"name":"B","full_name":"org::example::foo::B"}
+----
+=to=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+5:MType
+10:MClassType
+=properties=JsonObject(2):
+{"name":"B","full_name":"org::example::foo::B"}
+
+
+Edge
+=type=6:MCLASS
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+9:MClassDef
+=properties=JsonObject(4):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/B.java:18,1--29,1","is_intro":true,"name":"B","full_name":"org::example::foo::B"}
+----
+=to=Entity#32:classorg_1_1example_1_1foo_1_1_b
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MClass
+=properties=JsonObject(5):
+{"kind":"class","visibility":"public","full_name":"org::example::foo::B","name":"B","location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/B.java:18,1--29,1"}
+
+
+Edge
+=type=8:INHERITS
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+9:MClassDef
+=properties=JsonObject(4):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/B.java:18,1--29,1","is_intro":true,"name":"B","full_name":"org::example::foo::B"}
+----
+=to=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+5:MType
+10:MClassType
+=properties=JsonObject(2):
+{"name":"A","full_name":"org::example::foo::A"}
+
+
+Edge
+=type=8:INHERITS
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+9:MClassDef
+=properties=JsonObject(4):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/B.java:18,1--29,1","is_intro":true,"name":"B","full_name":"org::example::foo::B"}
+----
+=to=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+5:MType
+10:MClassType
+=properties=JsonObject(2):
+{"name":"C","full_name":"org::example::foo::C"}
+
+
+Edge
+=type=10:INTRODUCES
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+9:MClassDef
+=properties=JsonObject(4):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/B.java:18,1--29,1","is_intro":true,"name":"B","full_name":"org::example::foo::B"}
+----
+=to=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+9:MProperty
+10:MAttribute
+=properties=JsonObject(3):
+{"visibility":"protected","name":"qux","full_name":"org::example::foo::B::qux"}
+
+
+Edge
+=type=14:INTRO_CLASSDEF
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+9:MProperty
+10:MAttribute
+=properties=JsonObject(3):
+{"visibility":"protected","name":"qux","full_name":"org::example::foo::B::qux"}
+----
+=to=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+9:MClassDef
+=properties=JsonObject(4):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/B.java:18,1--29,1","is_intro":true,"name":"B","full_name":"org::example::foo::B"}
+
+
+Edge
+=type=8:DECLARES
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+9:MClassDef
+=properties=JsonObject(4):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/B.java:18,1--29,1","is_intro":true,"name":"B","full_name":"org::example::foo::B"}
+----
+=to=Entity#67:classorg_1_1example_1_1foo_1_1_b_1ac6b627949b10b9357eefc0cafcae1d87
+=labels=Array(4):
+3:foo
+7:MEntity
+8:MPropDef
+13:MAttributeDef
+=properties=JsonObject(5):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/B.java:19,1---1,1","visibility":"protected","name":"qux","is_intro":true,"full_name":"org::example::foo::B::qux"}
+
+
+Edge
+=type=10:INTRODUCES
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+9:MClassDef
+=properties=JsonObject(4):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/B.java:18,1--29,1","is_intro":true,"name":"B","full_name":"org::example::foo::B"}
+----
+=to=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+9:MProperty
+7:MMethod
+=properties=JsonObject(4):
+{"visibility":"public","is_init":false,"name":"bar","full_name":"org::example::foo::B::bar"}
+
+
+Edge
+=type=14:INTRO_CLASSDEF
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+9:MProperty
+7:MMethod
+=properties=JsonObject(4):
+{"visibility":"public","is_init":false,"name":"bar","full_name":"org::example::foo::B::bar"}
+----
+=to=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+9:MClassDef
+=properties=JsonObject(4):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/B.java:18,1--29,1","is_intro":true,"name":"B","full_name":"org::example::foo::B"}
+
+
+Edge
+=type=8:DECLARES
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+9:MClassDef
+=properties=JsonObject(4):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/B.java:18,1--29,1","is_intro":true,"name":"B","full_name":"org::example::foo::B"}
+----
+=to=Entity#67:classorg_1_1example_1_1foo_1_1_b_1a11e157943665cc9e3a9be1502ebeb3b5
+=labels=Array(4):
+3:foo
+7:MEntity
+8:MPropDef
+10:MMethodDef
+=properties=JsonObject(8):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/B.java:21,1--23,1","is_intern":false,"is_extern":false,"is_abstract":false,"visibility":"public","name":"bar","is_intro":true,"full_name":"org::example::foo::B::bar"}
+
+
+Edge
+=type=8:DECLARES
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+9:MClassDef
+=properties=JsonObject(4):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/B.java:18,1--29,1","is_intro":true,"name":"B","full_name":"org::example::foo::B"}
+----
+=to=Entity#67:classorg_1_1example_1_1foo_1_1_b_1a733f4e076f29c7d0c41ed258199ea1d9
+=labels=Array(4):
+3:foo
+7:MEntity
+8:MPropDef
+10:MMethodDef
+=properties=JsonObject(9):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/B.java:28,1--28,1","is_intern":false,"is_extern":false,"is_abstract":false,"visibility":"public","name":"baz","mdoc":["Some overriden documentation."],"is_intro":false,"full_name":"org::example::foo::B::baz"}
+
+
+Edge
+=type=9:CLASSTYPE
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#42:classorg_1_1example_1_1foo_1_1_empty_class
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MClass
+=properties=JsonObject(6):
+{"kind":"class","visibility":"package","full_name":"org::example::foo::EmptyClass","name":"EmptyClass","location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/EmptyClass.java:21,1--21,1","mdoc":["This class is empty and is only visible in this package."]}
+----
+=to=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+5:MType
+10:MClassType
+=properties=JsonObject(2):
+{"name":"EmptyClass","full_name":"org::example::foo::EmptyClass"}
+
+
+Edge
+=type=5:CLASS
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+5:MType
+10:MClassType
+=properties=JsonObject(2):
+{"name":"EmptyClass","full_name":"org::example::foo::EmptyClass"}
+----
+=to=Entity#42:classorg_1_1example_1_1foo_1_1_empty_class
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MClass
+=properties=JsonObject(6):
+{"kind":"class","visibility":"package","full_name":"org::example::foo::EmptyClass","name":"EmptyClass","location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/EmptyClass.java:21,1--21,1","mdoc":["This class is empty and is only visible in this package."]}
+
+
+Edge
+=type=9:BOUNDTYPE
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+9:MClassDef
+=properties=JsonObject(5):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/EmptyClass.java:21,1--21,1","is_intro":true,"name":"EmptyClass","full_name":"org::example::foo::EmptyClass","mdoc":["This class is empty and is only visible in this package."]}
+----
+=to=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+5:MType
+10:MClassType
+=properties=JsonObject(2):
+{"name":"EmptyClass","full_name":"org::example::foo::EmptyClass"}
+
+
+Edge
+=type=6:MCLASS
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+9:MClassDef
+=properties=JsonObject(5):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/EmptyClass.java:21,1--21,1","is_intro":true,"name":"EmptyClass","full_name":"org::example::foo::EmptyClass","mdoc":["This class is empty and is only visible in this package."]}
+----
+=to=Entity#42:classorg_1_1example_1_1foo_1_1_empty_class
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MClass
+=properties=JsonObject(6):
+{"kind":"class","visibility":"package","full_name":"org::example::foo::EmptyClass","name":"EmptyClass","location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/EmptyClass.java:21,1--21,1","mdoc":["This class is empty and is only visible in this package."]}
+
+
+Edge
+=type=7:DEFINES
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#71:interfaceorg_1_1example_1_1foo_1_1_c_1a4e97061eb40b045e820de05b33c43d21
+=labels=Array(4):
+3:foo
+7:MEntity
+8:MPropDef
+13:MAttributeDef
+=properties=JsonObject(6):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/C.java:25,1---1,1","visibility":"public","name":"THE_ANSWER","mdoc":["\u000e2\u00080\u0009cAnswer to the Ultimate Question of Life, the Universe, and Everything.\u000e2\u00080\u0009c"],"is_intro":true,"full_name":"org::example::foo::C::THE_ANSWER"}
+----
+=to=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+9:MProperty
+10:MAttribute
+=properties=JsonObject(3):
+{"visibility":"public","name":"THE_ANSWER","full_name":"org::example::foo::C::THE_ANSWER"}
+
+
+Edge
+=type=4:TYPE
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#71:interfaceorg_1_1example_1_1foo_1_1_c_1a4e97061eb40b045e820de05b33c43d21
+=labels=Array(4):
+3:foo
+7:MEntity
+8:MPropDef
+13:MAttributeDef
+=properties=JsonObject(6):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/C.java:25,1---1,1","visibility":"public","name":"THE_ANSWER","mdoc":["\u000e2\u00080\u0009cAnswer to the Ultimate Question of Life, the Universe, and Everything.\u000e2\u00080\u0009c"],"is_intro":true,"full_name":"org::example::foo::C::THE_ANSWER"}
+----
+=to=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+5:MType
+8:MRawType
+=properties=JsonObject(1):
+{"text":["final long"]}
+
+
+Edge
+=type=7:DEFINES
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#71:interfaceorg_1_1example_1_1foo_1_1_c_1a28ac7ce349ebb3e4a7747a8dd951582b
+=labels=Array(4):
+3:foo
+7:MEntity
+8:MPropDef
+10:MMethodDef
+=properties=JsonObject(9):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/C.java:30,1--1,1","is_intern":false,"is_extern":false,"is_abstract":false,"visibility":"public","name":"baz","mdoc":["A function with implicit modifiers."],"is_intro":true,"full_name":"org::example::foo::C::baz"}
+----
+=to=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+9:MProperty
+7:MMethod
+=properties=JsonObject(4):
+{"visibility":"public","is_init":false,"name":"baz","full_name":"org::example::foo::C::baz"}
+
+
+Edge
+=type=9:SIGNATURE
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#71:interfaceorg_1_1example_1_1foo_1_1_c_1a28ac7ce349ebb3e4a7747a8dd951582b
+=labels=Array(4):
+3:foo
+7:MEntity
+8:MPropDef
+10:MMethodDef
+=properties=JsonObject(9):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/C.java:30,1--1,1","is_intern":false,"is_extern":false,"is_abstract":false,"visibility":"public","name":"baz","mdoc":["A function with implicit modifiers."],"is_intro":true,"full_name":"org::example::foo::C::baz"}
+----
+=to=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+5:MType
+10:MSignature
+=properties=JsonObject(0):
+{}
+
+
+Edge
+=type=10:RETURNTYPE
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+5:MType
+10:MSignature
+=properties=JsonObject(0):
+{}
+----
+=to=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+5:MType
+8:MRawType
+=properties=JsonObject(1):
+{"text":["void"]}
+
+
+Edge
+=type=9:CLASSTYPE
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#36:interfaceorg_1_1example_1_1foo_1_1_c
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MClass
+=properties=JsonObject(6):
+{"kind":"interface","visibility":"public","full_name":"org::example::foo::C","name":"C","location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/C.java:21,1--31,1","mdoc":["An interface"]}
+----
+=to=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+5:MType
+10:MClassType
+=properties=JsonObject(2):
+{"name":"C","full_name":"org::example::foo::C"}
+
+
+Edge
+=type=5:CLASS
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+5:MType
+10:MClassType
+=properties=JsonObject(2):
+{"name":"C","full_name":"org::example::foo::C"}
+----
+=to=Entity#36:interfaceorg_1_1example_1_1foo_1_1_c
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MClass
+=properties=JsonObject(6):
+{"kind":"interface","visibility":"public","full_name":"org::example::foo::C","name":"C","location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/C.java:21,1--31,1","mdoc":["An interface"]}
+
+
+Edge
+=type=9:BOUNDTYPE
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+9:MClassDef
+=properties=JsonObject(5):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/C.java:21,1--31,1","is_intro":true,"name":"C","full_name":"org::example::foo::C","mdoc":["An interface"]}
+----
+=to=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+5:MType
+10:MClassType
+=properties=JsonObject(2):
+{"name":"C","full_name":"org::example::foo::C"}
+
+
+Edge
+=type=6:MCLASS
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+9:MClassDef
+=properties=JsonObject(5):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/C.java:21,1--31,1","is_intro":true,"name":"C","full_name":"org::example::foo::C","mdoc":["An interface"]}
+----
+=to=Entity#36:interfaceorg_1_1example_1_1foo_1_1_c
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MClass
+=properties=JsonObject(6):
+{"kind":"interface","visibility":"public","full_name":"org::example::foo::C","name":"C","location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/C.java:21,1--31,1","mdoc":["An interface"]}
+
+
+Edge
+=type=10:INTRODUCES
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+9:MClassDef
+=properties=JsonObject(5):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/C.java:21,1--31,1","is_intro":true,"name":"C","full_name":"org::example::foo::C","mdoc":["An interface"]}
+----
+=to=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+9:MProperty
+10:MAttribute
+=properties=JsonObject(3):
+{"visibility":"public","name":"THE_ANSWER","full_name":"org::example::foo::C::THE_ANSWER"}
+
+
+Edge
+=type=14:INTRO_CLASSDEF
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+9:MProperty
+10:MAttribute
+=properties=JsonObject(3):
+{"visibility":"public","name":"THE_ANSWER","full_name":"org::example::foo::C::THE_ANSWER"}
+----
+=to=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+9:MClassDef
+=properties=JsonObject(5):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/C.java:21,1--31,1","is_intro":true,"name":"C","full_name":"org::example::foo::C","mdoc":["An interface"]}
+
+
+Edge
+=type=8:DECLARES
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+9:MClassDef
+=properties=JsonObject(5):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/C.java:21,1--31,1","is_intro":true,"name":"C","full_name":"org::example::foo::C","mdoc":["An interface"]}
+----
+=to=Entity#71:interfaceorg_1_1example_1_1foo_1_1_c_1a4e97061eb40b045e820de05b33c43d21
+=labels=Array(4):
+3:foo
+7:MEntity
+8:MPropDef
+13:MAttributeDef
+=properties=JsonObject(6):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/C.java:25,1---1,1","visibility":"public","name":"THE_ANSWER","mdoc":["\u000e2\u00080\u0009cAnswer to the Ultimate Question of Life, the Universe, and Everything.\u000e2\u00080\u0009c"],"is_intro":true,"full_name":"org::example::foo::C::THE_ANSWER"}
+
+
+Edge
+=type=10:INTRODUCES
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+9:MClassDef
+=properties=JsonObject(5):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/C.java:21,1--31,1","is_intro":true,"name":"C","full_name":"org::example::foo::C","mdoc":["An interface"]}
+----
+=to=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+9:MProperty
+7:MMethod
+=properties=JsonObject(4):
+{"visibility":"public","is_init":false,"name":"baz","full_name":"org::example::foo::C::baz"}
+
+
+Edge
+=type=14:INTRO_CLASSDEF
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+9:MProperty
+7:MMethod
+=properties=JsonObject(4):
+{"visibility":"public","is_init":false,"name":"baz","full_name":"org::example::foo::C::baz"}
+----
+=to=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+9:MClassDef
+=properties=JsonObject(5):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/C.java:21,1--31,1","is_intro":true,"name":"C","full_name":"org::example::foo::C","mdoc":["An interface"]}
+
+
+Edge
+=type=8:DECLARES
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+9:MClassDef
+=properties=JsonObject(5):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/C.java:21,1--31,1","is_intro":true,"name":"C","full_name":"org::example::foo::C","mdoc":["An interface"]}
+----
+=to=Entity#71:interfaceorg_1_1example_1_1foo_1_1_c_1a28ac7ce349ebb3e4a7747a8dd951582b
+=labels=Array(4):
+3:foo
+7:MEntity
+8:MPropDef
+10:MMethodDef
+=properties=JsonObject(9):
+{"location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/C.java:30,1--1,1","is_intern":false,"is_extern":false,"is_abstract":false,"visibility":"public","name":"baz","mdoc":["A function with implicit modifiers."],"is_intro":true,"full_name":"org::example::foo::C::baz"}
+
+
+Edge
+=type=7:PROJECT
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#12:namespaceorg
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MGroup
+=properties=JsonObject(5):
+{"kind":"namespace","visibility":"","full_name":"org","name":"org","location":"\/dev\/null:1,1--1,1"}
+----
+=to=Node
+=labels=Array(3):
+3:foo
+7:MEntity
+8:MProject
+=properties=JsonObject(1):
+{"name":"foo"}
+
+
+Edge
+=type=6:PARENT
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#12:namespaceorg
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MGroup
+=properties=JsonObject(5):
+{"kind":"namespace","visibility":"","full_name":"org","name":"org","location":"\/dev\/null:1,1--1,1"}
+----
+=to=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MGroup
+=properties=JsonObject(2):
+{"full_name":"","name":"foo"}
+
+
+Edge
+=type=5:NESTS
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MGroup
+=properties=JsonObject(2):
+{"full_name":"","name":"foo"}
+----
+=to=Entity#12:namespaceorg
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MGroup
+=properties=JsonObject(5):
+{"kind":"namespace","visibility":"","full_name":"org","name":"org","location":"\/dev\/null:1,1--1,1"}
+
+
+Edge
+=type=6:PARENT
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#23:namespaceorg_1_1example
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MGroup
+=properties=JsonObject(5):
+{"kind":"namespace","visibility":"","full_name":"org::example","name":"example","location":"\/dev\/null:1,1--1,1"}
+----
+=to=Entity#12:namespaceorg
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MGroup
+=properties=JsonObject(5):
+{"kind":"namespace","visibility":"","full_name":"org","name":"org","location":"\/dev\/null:1,1--1,1"}
+
+
+Edge
+=type=5:NESTS
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#12:namespaceorg
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MGroup
+=properties=JsonObject(5):
+{"kind":"namespace","visibility":"","full_name":"org","name":"org","location":"\/dev\/null:1,1--1,1"}
+----
+=to=Entity#23:namespaceorg_1_1example
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MGroup
+=properties=JsonObject(5):
+{"kind":"namespace","visibility":"","full_name":"org::example","name":"example","location":"\/dev\/null:1,1--1,1"}
+
+
+Edge
+=type=7:PROJECT
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#23:namespaceorg_1_1example
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MGroup
+=properties=JsonObject(5):
+{"kind":"namespace","visibility":"","full_name":"org::example","name":"example","location":"\/dev\/null:1,1--1,1"}
+----
+=to=Node
+=labels=Array(3):
+3:foo
+7:MEntity
+8:MProject
+=properties=JsonObject(1):
+{"name":"foo"}
+
+
+Edge
+=type=6:PARENT
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#30:namespaceorg_1_1example_1_1foo
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MGroup
+=properties=JsonObject(5):
+{"kind":"namespace","visibility":"","full_name":"org::example::foo","name":"foo","location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/A.java:16,1--1,1"}
+----
+=to=Entity#23:namespaceorg_1_1example
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MGroup
+=properties=JsonObject(5):
+{"kind":"namespace","visibility":"","full_name":"org::example","name":"example","location":"\/dev\/null:1,1--1,1"}
+
+
+Edge
+=type=5:NESTS
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#23:namespaceorg_1_1example
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MGroup
+=properties=JsonObject(5):
+{"kind":"namespace","visibility":"","full_name":"org::example","name":"example","location":"\/dev\/null:1,1--1,1"}
+----
+=to=Entity#30:namespaceorg_1_1example_1_1foo
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MGroup
+=properties=JsonObject(5):
+{"kind":"namespace","visibility":"","full_name":"org::example::foo","name":"foo","location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/A.java:16,1--1,1"}
+
+
+Edge
+=type=7:PROJECT
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#30:namespaceorg_1_1example_1_1foo
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MGroup
+=properties=JsonObject(5):
+{"kind":"namespace","visibility":"","full_name":"org::example::foo","name":"foo","location":"%SOURCE_DIRECTORY%\/org\/example\/foo\/A.java:16,1--1,1"}
+----
+=to=Node
+=labels=Array(3):
+3:foo
+7:MEntity
+8:MProject
+=properties=JsonObject(1):
+{"name":"foo"}
+
+
+---===DONE===---
--- /dev/null
+Reading ../contrib/neo_doxygen/tests/root-namespace/xml... Done.
+3 files read.
+Linking nodes...\e[s \e[u\e[J Done.
+Saving 6 nodes...
+---===DONE===---
+Saving 9 edges...
+Edge
+=type=4:ROOT
+=properties=JsonObject(0):
+{}
+----
+=from=Node
+=labels=Array(3):
+14:root-namespace
+7:MEntity
+8:MProject
+=properties=JsonObject(1):
+{"name":"root-namespace"}
+----
+=to=Entity#0:
+=labels=Array(3):
+14:root-namespace
+7:MEntity
+6:MGroup
+=properties=JsonObject(2):
+{"full_name":"","name":"root-namespace"}
+
+
+Edge
+=type=7:PROJECT
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+14:root-namespace
+7:MEntity
+6:MGroup
+=properties=JsonObject(2):
+{"full_name":"","name":"root-namespace"}
+----
+=to=Node
+=labels=Array(3):
+14:root-namespace
+7:MEntity
+8:MProject
+=properties=JsonObject(1):
+{"name":"root-namespace"}
+
+
+Edge
+=type=9:CLASSTYPE
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#9:class_foo
+=labels=Array(3):
+14:root-namespace
+7:MEntity
+6:MClass
+=properties=JsonObject(6):
+{"kind":"class","visibility":"package","full_name":"Foo","name":"Foo","location":"%SOURCE_DIRECTORY%\/Foo.java:19,1--19,1","mdoc":["A class in the root namespace"]}
+----
+=to=Entity#0:
+=labels=Array(4):
+14:root-namespace
+7:MEntity
+5:MType
+10:MClassType
+=properties=JsonObject(2):
+{"name":"Foo","full_name":"Foo"}
+
+
+Edge
+=type=5:CLASS
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(4):
+14:root-namespace
+7:MEntity
+5:MType
+10:MClassType
+=properties=JsonObject(2):
+{"name":"Foo","full_name":"Foo"}
+----
+=to=Entity#9:class_foo
+=labels=Array(3):
+14:root-namespace
+7:MEntity
+6:MClass
+=properties=JsonObject(6):
+{"kind":"class","visibility":"package","full_name":"Foo","name":"Foo","location":"%SOURCE_DIRECTORY%\/Foo.java:19,1--19,1","mdoc":["A class in the root namespace"]}
+
+
+Edge
+=type=9:BOUNDTYPE
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+14:root-namespace
+7:MEntity
+9:MClassDef
+=properties=JsonObject(5):
+{"location":"%SOURCE_DIRECTORY%\/Foo.java:19,1--19,1","is_intro":true,"name":"Foo","full_name":"Foo","mdoc":["A class in the root namespace"]}
+----
+=to=Entity#0:
+=labels=Array(4):
+14:root-namespace
+7:MEntity
+5:MType
+10:MClassType
+=properties=JsonObject(2):
+{"name":"Foo","full_name":"Foo"}
+
+
+Edge
+=type=6:MCLASS
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+14:root-namespace
+7:MEntity
+9:MClassDef
+=properties=JsonObject(5):
+{"location":"%SOURCE_DIRECTORY%\/Foo.java:19,1--19,1","is_intro":true,"name":"Foo","full_name":"Foo","mdoc":["A class in the root namespace"]}
+----
+=to=Entity#9:class_foo
+=labels=Array(3):
+14:root-namespace
+7:MEntity
+6:MClass
+=properties=JsonObject(6):
+{"kind":"class","visibility":"package","full_name":"Foo","name":"Foo","location":"%SOURCE_DIRECTORY%\/Foo.java:19,1--19,1","mdoc":["A class in the root namespace"]}
+
+
+Edge
+=type=8:DECLARES
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+14:root-namespace
+7:MEntity
+6:MGroup
+=properties=JsonObject(2):
+{"full_name":"","name":"root-namespace"}
+----
+=to=Entity#0:
+=labels=Array(3):
+14:root-namespace
+7:MEntity
+7:MModule
+=properties=JsonObject(3):
+{"location":"%SOURCE_DIRECTORY%\/Foo.java:1,1--1,1","name":"Foo","full_name":"Foo"}
+
+
+Edge
+=type=10:INTRODUCES
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+14:root-namespace
+7:MEntity
+7:MModule
+=properties=JsonObject(3):
+{"location":"%SOURCE_DIRECTORY%\/Foo.java:1,1--1,1","name":"Foo","full_name":"Foo"}
+----
+=to=Entity#9:class_foo
+=labels=Array(3):
+14:root-namespace
+7:MEntity
+6:MClass
+=properties=JsonObject(6):
+{"kind":"class","visibility":"package","full_name":"Foo","name":"Foo","location":"%SOURCE_DIRECTORY%\/Foo.java:19,1--19,1","mdoc":["A class in the root namespace"]}
+
+
+Edge
+=type=7:DEFINES
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+14:root-namespace
+7:MEntity
+7:MModule
+=properties=JsonObject(3):
+{"location":"%SOURCE_DIRECTORY%\/Foo.java:1,1--1,1","name":"Foo","full_name":"Foo"}
+----
+=to=Entity#0:
+=labels=Array(3):
+14:root-namespace
+7:MEntity
+9:MClassDef
+=properties=JsonObject(5):
+{"location":"%SOURCE_DIRECTORY%\/Foo.java:19,1--19,1","is_intro":true,"name":"Foo","full_name":"Foo","mdoc":["A class in the root namespace"]}
+
+
+---===DONE===---
--- /dev/null
+Reading ../contrib/neo_doxygen/tests/inner-class/xml... Done.
+4 files read.
+Linking nodes...\e[s \e[u\e[J Done.
+Saving 11 nodes...
+---===DONE===---
+Saving 21 edges...
+Edge
+=type=4:ROOT
+=properties=JsonObject(0):
+{}
+----
+=from=Node
+=labels=Array(3):
+11:inner-class
+7:MEntity
+8:MProject
+=properties=JsonObject(1):
+{"name":"inner-class"}
+----
+=to=Entity#0:
+=labels=Array(3):
+11:inner-class
+7:MEntity
+6:MGroup
+=properties=JsonObject(2):
+{"full_name":"","name":"inner-class"}
+
+
+Edge
+=type=7:PROJECT
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+11:inner-class
+7:MEntity
+6:MGroup
+=properties=JsonObject(2):
+{"full_name":"","name":"inner-class"}
+----
+=to=Node
+=labels=Array(3):
+11:inner-class
+7:MEntity
+8:MProject
+=properties=JsonObject(1):
+{"name":"inner-class"}
+
+
+Edge
+=type=9:CLASSTYPE
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#17:class_outer_class
+=labels=Array(3):
+11:inner-class
+7:MEntity
+6:MClass
+=properties=JsonObject(6):
+{"kind":"class","visibility":"public","full_name":"OuterClass","name":"OuterClass","location":"%SOURCE_DIRECTORY%\/OuterClass.java:19,1--24,1","mdoc":["A class with an inner class."]}
+----
+=to=Entity#0:
+=labels=Array(4):
+11:inner-class
+7:MEntity
+5:MType
+10:MClassType
+=properties=JsonObject(2):
+{"name":"OuterClass","full_name":"OuterClass"}
+
+
+Edge
+=type=5:CLASS
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(4):
+11:inner-class
+7:MEntity
+5:MType
+10:MClassType
+=properties=JsonObject(2):
+{"name":"OuterClass","full_name":"OuterClass"}
+----
+=to=Entity#17:class_outer_class
+=labels=Array(3):
+11:inner-class
+7:MEntity
+6:MClass
+=properties=JsonObject(6):
+{"kind":"class","visibility":"public","full_name":"OuterClass","name":"OuterClass","location":"%SOURCE_DIRECTORY%\/OuterClass.java:19,1--24,1","mdoc":["A class with an inner class."]}
+
+
+Edge
+=type=9:BOUNDTYPE
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+11:inner-class
+7:MEntity
+9:MClassDef
+=properties=JsonObject(5):
+{"location":"%SOURCE_DIRECTORY%\/OuterClass.java:19,1--24,1","is_intro":true,"name":"OuterClass","full_name":"OuterClass","mdoc":["A class with an inner class."]}
+----
+=to=Entity#0:
+=labels=Array(4):
+11:inner-class
+7:MEntity
+5:MType
+10:MClassType
+=properties=JsonObject(2):
+{"name":"OuterClass","full_name":"OuterClass"}
+
+
+Edge
+=type=6:MCLASS
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+11:inner-class
+7:MEntity
+9:MClassDef
+=properties=JsonObject(5):
+{"location":"%SOURCE_DIRECTORY%\/OuterClass.java:19,1--24,1","is_intro":true,"name":"OuterClass","full_name":"OuterClass","mdoc":["A class with an inner class."]}
+----
+=to=Entity#17:class_outer_class
+=labels=Array(3):
+11:inner-class
+7:MEntity
+6:MClass
+=properties=JsonObject(6):
+{"kind":"class","visibility":"public","full_name":"OuterClass","name":"OuterClass","location":"%SOURCE_DIRECTORY%\/OuterClass.java:19,1--24,1","mdoc":["A class with an inner class."]}
+
+
+Edge
+=type=10:INTRODUCES
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+11:inner-class
+7:MEntity
+9:MClassDef
+=properties=JsonObject(5):
+{"location":"%SOURCE_DIRECTORY%\/OuterClass.java:19,1--24,1","is_intro":true,"name":"OuterClass","full_name":"OuterClass","mdoc":["A class with an inner class."]}
+----
+=to=Entity#0:
+=labels=Array(4):
+11:inner-class
+7:MEntity
+9:MProperty
+11:MInnerClass
+=properties=JsonObject(3):
+{"visibility":"public","full_name":"OuterClass::InnerClass","name":"InnerClass"}
+
+
+Edge
+=type=14:INTRO_CLASSDEF
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(4):
+11:inner-class
+7:MEntity
+9:MProperty
+11:MInnerClass
+=properties=JsonObject(3):
+{"visibility":"public","full_name":"OuterClass::InnerClass","name":"InnerClass"}
+----
+=to=Entity#0:
+=labels=Array(3):
+11:inner-class
+7:MEntity
+9:MClassDef
+=properties=JsonObject(5):
+{"location":"%SOURCE_DIRECTORY%\/OuterClass.java:19,1--24,1","is_intro":true,"name":"OuterClass","full_name":"OuterClass","mdoc":["A class with an inner class."]}
+
+
+Edge
+=type=8:DECLARES
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+11:inner-class
+7:MEntity
+9:MClassDef
+=properties=JsonObject(5):
+{"location":"%SOURCE_DIRECTORY%\/OuterClass.java:19,1--24,1","is_intro":true,"name":"OuterClass","full_name":"OuterClass","mdoc":["A class with an inner class."]}
+----
+=to=Entity#0:
+=labels=Array(4):
+11:inner-class
+7:MEntity
+8:MPropDef
+14:MInnerClassDef
+=properties=JsonObject(5):
+{"location":"\/dev\/null:1,1--1,1","full_name":"OuterClass::InnerClass","name":"InnerClass","visibility":"public","is_intro":true}
+
+
+Edge
+=type=7:DEFINES
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(4):
+11:inner-class
+7:MEntity
+8:MPropDef
+14:MInnerClassDef
+=properties=JsonObject(5):
+{"location":"\/dev\/null:1,1--1,1","full_name":"OuterClass::InnerClass","name":"InnerClass","visibility":"public","is_intro":true}
+----
+=to=Entity#0:
+=labels=Array(4):
+11:inner-class
+7:MEntity
+9:MProperty
+11:MInnerClass
+=properties=JsonObject(3):
+{"visibility":"public","full_name":"OuterClass::InnerClass","name":"InnerClass"}
+
+
+Edge
+=type=5:NESTS
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(4):
+11:inner-class
+7:MEntity
+8:MPropDef
+14:MInnerClassDef
+=properties=JsonObject(5):
+{"location":"\/dev\/null:1,1--1,1","full_name":"OuterClass::InnerClass","name":"InnerClass","visibility":"public","is_intro":true}
+----
+=to=Entity#0:
+=labels=Array(3):
+11:inner-class
+7:MEntity
+9:MClassDef
+=properties=JsonObject(5):
+{"location":"%SOURCE_DIRECTORY%\/OuterClass.java:23,1--23,1","is_intro":true,"name":"OuterClass::InnerClass","full_name":"OuterClass::InnerClass","mdoc":["An instance (non-static) inner class."]}
+
+
+Edge
+=type=5:NESTS
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(4):
+11:inner-class
+7:MEntity
+9:MProperty
+11:MInnerClass
+=properties=JsonObject(3):
+{"visibility":"public","full_name":"OuterClass::InnerClass","name":"InnerClass"}
+----
+=to=Entity#33:class_outer_class_1_1_inner_class
+=labels=Array(3):
+11:inner-class
+7:MEntity
+6:MClass
+=properties=JsonObject(6):
+{"kind":"class","visibility":"public","full_name":"OuterClass::InnerClass","name":"OuterClass::InnerClass","location":"%SOURCE_DIRECTORY%\/OuterClass.java:23,1--23,1","mdoc":["An instance (non-static) inner class."]}
+
+
+Edge
+=type=9:CLASSTYPE
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#33:class_outer_class_1_1_inner_class
+=labels=Array(3):
+11:inner-class
+7:MEntity
+6:MClass
+=properties=JsonObject(6):
+{"kind":"class","visibility":"public","full_name":"OuterClass::InnerClass","name":"OuterClass::InnerClass","location":"%SOURCE_DIRECTORY%\/OuterClass.java:23,1--23,1","mdoc":["An instance (non-static) inner class."]}
+----
+=to=Entity#0:
+=labels=Array(4):
+11:inner-class
+7:MEntity
+5:MType
+10:MClassType
+=properties=JsonObject(2):
+{"name":"OuterClass::InnerClass","full_name":"OuterClass::InnerClass"}
+
+
+Edge
+=type=5:CLASS
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(4):
+11:inner-class
+7:MEntity
+5:MType
+10:MClassType
+=properties=JsonObject(2):
+{"name":"OuterClass::InnerClass","full_name":"OuterClass::InnerClass"}
+----
+=to=Entity#33:class_outer_class_1_1_inner_class
+=labels=Array(3):
+11:inner-class
+7:MEntity
+6:MClass
+=properties=JsonObject(6):
+{"kind":"class","visibility":"public","full_name":"OuterClass::InnerClass","name":"OuterClass::InnerClass","location":"%SOURCE_DIRECTORY%\/OuterClass.java:23,1--23,1","mdoc":["An instance (non-static) inner class."]}
+
+
+Edge
+=type=9:BOUNDTYPE
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+11:inner-class
+7:MEntity
+9:MClassDef
+=properties=JsonObject(5):
+{"location":"%SOURCE_DIRECTORY%\/OuterClass.java:23,1--23,1","is_intro":true,"name":"OuterClass::InnerClass","full_name":"OuterClass::InnerClass","mdoc":["An instance (non-static) inner class."]}
+----
+=to=Entity#0:
+=labels=Array(4):
+11:inner-class
+7:MEntity
+5:MType
+10:MClassType
+=properties=JsonObject(2):
+{"name":"OuterClass::InnerClass","full_name":"OuterClass::InnerClass"}
+
+
+Edge
+=type=6:MCLASS
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+11:inner-class
+7:MEntity
+9:MClassDef
+=properties=JsonObject(5):
+{"location":"%SOURCE_DIRECTORY%\/OuterClass.java:23,1--23,1","is_intro":true,"name":"OuterClass::InnerClass","full_name":"OuterClass::InnerClass","mdoc":["An instance (non-static) inner class."]}
+----
+=to=Entity#33:class_outer_class_1_1_inner_class
+=labels=Array(3):
+11:inner-class
+7:MEntity
+6:MClass
+=properties=JsonObject(6):
+{"kind":"class","visibility":"public","full_name":"OuterClass::InnerClass","name":"OuterClass::InnerClass","location":"%SOURCE_DIRECTORY%\/OuterClass.java:23,1--23,1","mdoc":["An instance (non-static) inner class."]}
+
+
+Edge
+=type=8:DECLARES
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+11:inner-class
+7:MEntity
+6:MGroup
+=properties=JsonObject(2):
+{"full_name":"","name":"inner-class"}
+----
+=to=Entity#0:
+=labels=Array(3):
+11:inner-class
+7:MEntity
+7:MModule
+=properties=JsonObject(3):
+{"location":"%SOURCE_DIRECTORY%\/OuterClass.java:1,1--1,1","name":"OuterClass","full_name":"OuterClass"}
+
+
+Edge
+=type=10:INTRODUCES
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+11:inner-class
+7:MEntity
+7:MModule
+=properties=JsonObject(3):
+{"location":"%SOURCE_DIRECTORY%\/OuterClass.java:1,1--1,1","name":"OuterClass","full_name":"OuterClass"}
+----
+=to=Entity#17:class_outer_class
+=labels=Array(3):
+11:inner-class
+7:MEntity
+6:MClass
+=properties=JsonObject(6):
+{"kind":"class","visibility":"public","full_name":"OuterClass","name":"OuterClass","location":"%SOURCE_DIRECTORY%\/OuterClass.java:19,1--24,1","mdoc":["A class with an inner class."]}
+
+
+Edge
+=type=7:DEFINES
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+11:inner-class
+7:MEntity
+7:MModule
+=properties=JsonObject(3):
+{"location":"%SOURCE_DIRECTORY%\/OuterClass.java:1,1--1,1","name":"OuterClass","full_name":"OuterClass"}
+----
+=to=Entity#0:
+=labels=Array(3):
+11:inner-class
+7:MEntity
+9:MClassDef
+=properties=JsonObject(5):
+{"location":"%SOURCE_DIRECTORY%\/OuterClass.java:19,1--24,1","is_intro":true,"name":"OuterClass","full_name":"OuterClass","mdoc":["A class with an inner class."]}
+
+
+Edge
+=type=10:INTRODUCES
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+11:inner-class
+7:MEntity
+7:MModule
+=properties=JsonObject(3):
+{"location":"%SOURCE_DIRECTORY%\/OuterClass.java:1,1--1,1","name":"OuterClass","full_name":"OuterClass"}
+----
+=to=Entity#33:class_outer_class_1_1_inner_class
+=labels=Array(3):
+11:inner-class
+7:MEntity
+6:MClass
+=properties=JsonObject(6):
+{"kind":"class","visibility":"public","full_name":"OuterClass::InnerClass","name":"OuterClass::InnerClass","location":"%SOURCE_DIRECTORY%\/OuterClass.java:23,1--23,1","mdoc":["An instance (non-static) inner class."]}
+
+
+Edge
+=type=7:DEFINES
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+11:inner-class
+7:MEntity
+7:MModule
+=properties=JsonObject(3):
+{"location":"%SOURCE_DIRECTORY%\/OuterClass.java:1,1--1,1","name":"OuterClass","full_name":"OuterClass"}
+----
+=to=Entity#0:
+=labels=Array(3):
+11:inner-class
+7:MEntity
+9:MClassDef
+=properties=JsonObject(5):
+{"location":"%SOURCE_DIRECTORY%\/OuterClass.java:23,1--23,1","is_intro":true,"name":"OuterClass::InnerClass","full_name":"OuterClass::InnerClass","mdoc":["An instance (non-static) inner class."]}
+
+
+---===DONE===---
--- /dev/null
+---===WITHOUT GLOBALS===---
+# Graph
+Edge
+=type=4:ROOT
+=properties=JsonObject(0):
+{}
+----
+=from=Node
+=labels=Array(3):
+3:foo
+7:MEntity
+8:MProject
+=properties=JsonObject(1):
+{"name":"foo"}
+----
+=to=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MGroup
+=properties=JsonObject(2):
+{"full_name":"","name":"foo"}
+
+Edge
+=type=7:PROJECT
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MGroup
+=properties=JsonObject(2):
+{"full_name":"","name":"foo"}
+----
+=to=Node
+=labels=Array(3):
+3:foo
+7:MEntity
+8:MProject
+=properties=JsonObject(1):
+{"name":"foo"}
+
+Edge
+=type=8:DECLARES
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MGroup
+=properties=JsonObject(2):
+{"full_name":"a::b","name":"b"}
+----
+=to=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+7:MModule
+=properties=JsonObject(3):
+{"location":"\/dev\/null:1,1--1,1","name":"Bar","full_name":"a::b::Bar"}
+
+Edge
+=type=10:INTRODUCES
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+7:MModule
+=properties=JsonObject(3):
+{"location":"\/dev\/null:1,1--1,1","name":"Bar","full_name":"a::b::Bar"}
+----
+=to=Entity#12:classa_b_bar
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MClass
+=properties=JsonObject(4):
+{"kind":"class","visibility":"public","full_name":"a::b::Bar","name":"Bar"}
+
+Edge
+=type=7:DEFINES
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+7:MModule
+=properties=JsonObject(3):
+{"location":"\/dev\/null:1,1--1,1","name":"Bar","full_name":"a::b::Bar"}
+----
+=to=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+9:MClassDef
+=properties=JsonObject(4):
+{"location":"\/dev\/null:1,1--1,1","is_intro":true,"name":"Bar","full_name":"a::b::Bar"}
+
+Edge
+=type=8:DECLARES
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#10:namespacec
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MGroup
+=properties=JsonObject(2):
+{"full_name":"c","name":"c"}
+----
+=to=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+7:MModule
+=properties=JsonObject(3):
+{"location":"\/dev\/null:1,1--1,1","name":"Bar","full_name":"c::Bar"}
+
+Edge
+=type=8:DECLARES
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#10:namespaced
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MGroup
+=properties=JsonObject(2):
+{"full_name":"d","name":"d"}
+----
+=to=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+7:MModule
+=properties=JsonObject(3):
+{"location":"\/dev\/null:1,1--1,1","name":"Bar","full_name":"d::Bar"}
+
+Edge
+=type=9:CLASSTYPE
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#12:classa_b_bar
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MClass
+=properties=JsonObject(4):
+{"kind":"class","visibility":"public","full_name":"a::b::Bar","name":"Bar"}
+----
+=to=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+5:MType
+10:MClassType
+=properties=JsonObject(2):
+{"name":"Bar","full_name":"a::b::Bar"}
+
+Edge
+=type=5:CLASS
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+5:MType
+10:MClassType
+=properties=JsonObject(2):
+{"name":"Bar","full_name":"a::b::Bar"}
+----
+=to=Entity#12:classa_b_bar
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MClass
+=properties=JsonObject(4):
+{"kind":"class","visibility":"public","full_name":"a::b::Bar","name":"Bar"}
+
+Edge
+=type=9:BOUNDTYPE
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+9:MClassDef
+=properties=JsonObject(4):
+{"location":"\/dev\/null:1,1--1,1","is_intro":true,"name":"Bar","full_name":"a::b::Bar"}
+----
+=to=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+5:MType
+10:MClassType
+=properties=JsonObject(2):
+{"name":"Bar","full_name":"a::b::Bar"}
+
+Edge
+=type=6:MCLASS
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+9:MClassDef
+=properties=JsonObject(4):
+{"location":"\/dev\/null:1,1--1,1","is_intro":true,"name":"Bar","full_name":"a::b::Bar"}
+----
+=to=Entity#12:classa_b_bar
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MClass
+=properties=JsonObject(4):
+{"kind":"class","visibility":"public","full_name":"a::b::Bar","name":"Bar"}
+
+Edge
+=type=9:CLASSTYPE
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#8:classbaz
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MClass
+=properties=JsonObject(4):
+{"kind":"class","visibility":"public","full_name":"Baz","name":"Baz"}
+----
+=to=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+5:MType
+10:MClassType
+=properties=JsonObject(2):
+{"name":"Baz","full_name":"Baz"}
+
+Edge
+=type=5:CLASS
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+5:MType
+10:MClassType
+=properties=JsonObject(2):
+{"name":"Baz","full_name":"Baz"}
+----
+=to=Entity#8:classbaz
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MClass
+=properties=JsonObject(4):
+{"kind":"class","visibility":"public","full_name":"Baz","name":"Baz"}
+
+Edge
+=type=9:BOUNDTYPE
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+9:MClassDef
+=properties=JsonObject(4):
+{"location":"\/dev\/null:1,1--1,1","is_intro":true,"name":"Baz","full_name":"Baz"}
+----
+=to=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+5:MType
+10:MClassType
+=properties=JsonObject(2):
+{"name":"Baz","full_name":"Baz"}
+
+Edge
+=type=6:MCLASS
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+9:MClassDef
+=properties=JsonObject(4):
+{"location":"\/dev\/null:1,1--1,1","is_intro":true,"name":"Baz","full_name":"Baz"}
+----
+=to=Entity#8:classbaz
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MClass
+=properties=JsonObject(4):
+{"kind":"class","visibility":"public","full_name":"Baz","name":"Baz"}
+
+Edge
+=type=7:PROJECT
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MGroup
+=properties=JsonObject(2):
+{"full_name":"a","name":"a"}
+----
+=to=Node
+=labels=Array(3):
+3:foo
+7:MEntity
+8:MProject
+=properties=JsonObject(1):
+{"name":"foo"}
+
+Edge
+=type=6:PARENT
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MGroup
+=properties=JsonObject(2):
+{"full_name":"a","name":"a"}
+----
+=to=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MGroup
+=properties=JsonObject(2):
+{"full_name":"","name":"foo"}
+
+Edge
+=type=5:NESTS
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MGroup
+=properties=JsonObject(2):
+{"full_name":"","name":"foo"}
+----
+=to=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MGroup
+=properties=JsonObject(2):
+{"full_name":"a","name":"a"}
+
+Edge
+=type=6:PARENT
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MGroup
+=properties=JsonObject(2):
+{"full_name":"a::b","name":"b"}
+----
+=to=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MGroup
+=properties=JsonObject(2):
+{"full_name":"a","name":"a"}
+
+Edge
+=type=5:NESTS
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MGroup
+=properties=JsonObject(2):
+{"full_name":"a","name":"a"}
+----
+=to=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MGroup
+=properties=JsonObject(2):
+{"full_name":"a::b","name":"b"}
+
+Edge
+=type=7:PROJECT
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MGroup
+=properties=JsonObject(2):
+{"full_name":"a::b","name":"b"}
+----
+=to=Node
+=labels=Array(3):
+3:foo
+7:MEntity
+8:MProject
+=properties=JsonObject(1):
+{"name":"foo"}
+
+Edge
+=type=7:PROJECT
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#10:namespacec
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MGroup
+=properties=JsonObject(2):
+{"full_name":"c","name":"c"}
+----
+=to=Node
+=labels=Array(3):
+3:foo
+7:MEntity
+8:MProject
+=properties=JsonObject(1):
+{"name":"foo"}
+
+Edge
+=type=6:PARENT
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#10:namespacec
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MGroup
+=properties=JsonObject(2):
+{"full_name":"c","name":"c"}
+----
+=to=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MGroup
+=properties=JsonObject(2):
+{"full_name":"","name":"foo"}
+
+Edge
+=type=5:NESTS
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MGroup
+=properties=JsonObject(2):
+{"full_name":"","name":"foo"}
+----
+=to=Entity#10:namespacec
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MGroup
+=properties=JsonObject(2):
+{"full_name":"c","name":"c"}
+
+Edge
+=type=7:PROJECT
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#10:namespaced
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MGroup
+=properties=JsonObject(2):
+{"full_name":"d","name":"d"}
+----
+=to=Node
+=labels=Array(3):
+3:foo
+7:MEntity
+8:MProject
+=properties=JsonObject(1):
+{"name":"foo"}
+
+Edge
+=type=6:PARENT
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#10:namespaced
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MGroup
+=properties=JsonObject(2):
+{"full_name":"d","name":"d"}
+----
+=to=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MGroup
+=properties=JsonObject(2):
+{"full_name":"","name":"foo"}
+
+Edge
+=type=5:NESTS
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MGroup
+=properties=JsonObject(2):
+{"full_name":"","name":"foo"}
+----
+=to=Entity#10:namespaced
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MGroup
+=properties=JsonObject(2):
+{"full_name":"d","name":"d"}
+
+
+---===WITH GLOBALS===---
+# Graph
+Edge
+=type=4:ROOT
+=properties=JsonObject(0):
+{}
+----
+=from=Node
+=labels=Array(3):
+3:foo
+7:MEntity
+8:MProject
+=properties=JsonObject(1):
+{"name":"foo"}
+----
+=to=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MGroup
+=properties=JsonObject(2):
+{"full_name":"","name":"foo"}
+
+Edge
+=type=7:PROJECT
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MGroup
+=properties=JsonObject(2):
+{"full_name":"","name":"foo"}
+----
+=to=Node
+=labels=Array(3):
+3:foo
+7:MEntity
+8:MProject
+=properties=JsonObject(1):
+{"name":"foo"}
+
+Edge
+=type=8:DECLARES
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MGroup
+=properties=JsonObject(2):
+{"full_name":"a::b","name":"b"}
+----
+=to=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+7:MModule
+=properties=JsonObject(3):
+{"location":"\/dev\/null:1,1--1,1","name":"Bar","full_name":"a::b::Bar"}
+
+Edge
+=type=10:INTRODUCES
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+7:MModule
+=properties=JsonObject(3):
+{"location":"\/dev\/null:1,1--1,1","name":"Bar","full_name":"a::b::Bar"}
+----
+=to=Entity#12:classa_b_bar
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MClass
+=properties=JsonObject(4):
+{"kind":"class","visibility":"public","full_name":"a::b::Bar","name":"Bar"}
+
+Edge
+=type=7:DEFINES
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+7:MModule
+=properties=JsonObject(3):
+{"location":"\/dev\/null:1,1--1,1","name":"Bar","full_name":"a::b::Bar"}
+----
+=to=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+9:MClassDef
+=properties=JsonObject(4):
+{"location":"\/dev\/null:1,1--1,1","is_intro":true,"name":"Bar","full_name":"a::b::Bar"}
+
+Edge
+=type=8:DECLARES
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#10:namespacec
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MGroup
+=properties=JsonObject(2):
+{"full_name":"c","name":"c"}
+----
+=to=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+7:MModule
+=properties=JsonObject(3):
+{"location":"\/dev\/null:1,1--1,1","name":"Bar","full_name":"c::Bar"}
+
+Edge
+=type=8:DECLARES
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#10:namespaced
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MGroup
+=properties=JsonObject(2):
+{"full_name":"d","name":"d"}
+----
+=to=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+7:MModule
+=properties=JsonObject(3):
+{"location":"\/dev\/null:1,1--1,1","name":"Bar","full_name":"d::Bar"}
+
+Edge
+=type=9:CLASSTYPE
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#12:classa_b_bar
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MClass
+=properties=JsonObject(4):
+{"kind":"class","visibility":"public","full_name":"a::b::Bar","name":"Bar"}
+----
+=to=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+5:MType
+10:MClassType
+=properties=JsonObject(2):
+{"name":"Bar","full_name":"a::b::Bar"}
+
+Edge
+=type=5:CLASS
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+5:MType
+10:MClassType
+=properties=JsonObject(2):
+{"name":"Bar","full_name":"a::b::Bar"}
+----
+=to=Entity#12:classa_b_bar
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MClass
+=properties=JsonObject(4):
+{"kind":"class","visibility":"public","full_name":"a::b::Bar","name":"Bar"}
+
+Edge
+=type=9:BOUNDTYPE
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+9:MClassDef
+=properties=JsonObject(4):
+{"location":"\/dev\/null:1,1--1,1","is_intro":true,"name":"Bar","full_name":"a::b::Bar"}
+----
+=to=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+5:MType
+10:MClassType
+=properties=JsonObject(2):
+{"name":"Bar","full_name":"a::b::Bar"}
+
+Edge
+=type=6:MCLASS
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+9:MClassDef
+=properties=JsonObject(4):
+{"location":"\/dev\/null:1,1--1,1","is_intro":true,"name":"Bar","full_name":"a::b::Bar"}
+----
+=to=Entity#12:classa_b_bar
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MClass
+=properties=JsonObject(4):
+{"kind":"class","visibility":"public","full_name":"a::b::Bar","name":"Bar"}
+
+Edge
+=type=9:CLASSTYPE
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#8:classbaz
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MClass
+=properties=JsonObject(4):
+{"kind":"class","visibility":"public","full_name":"Baz","name":"Baz"}
+----
+=to=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+5:MType
+10:MClassType
+=properties=JsonObject(2):
+{"name":"Baz","full_name":"Baz"}
+
+Edge
+=type=5:CLASS
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+5:MType
+10:MClassType
+=properties=JsonObject(2):
+{"name":"Baz","full_name":"Baz"}
+----
+=to=Entity#8:classbaz
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MClass
+=properties=JsonObject(4):
+{"kind":"class","visibility":"public","full_name":"Baz","name":"Baz"}
+
+Edge
+=type=9:BOUNDTYPE
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+9:MClassDef
+=properties=JsonObject(4):
+{"location":"\/dev\/null:1,1--1,1","is_intro":true,"name":"Baz","full_name":"Baz"}
+----
+=to=Entity#0:
+=labels=Array(4):
+3:foo
+7:MEntity
+5:MType
+10:MClassType
+=properties=JsonObject(2):
+{"name":"Baz","full_name":"Baz"}
+
+Edge
+=type=6:MCLASS
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+9:MClassDef
+=properties=JsonObject(4):
+{"location":"\/dev\/null:1,1--1,1","is_intro":true,"name":"Baz","full_name":"Baz"}
+----
+=to=Entity#8:classbaz
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MClass
+=properties=JsonObject(4):
+{"kind":"class","visibility":"public","full_name":"Baz","name":"Baz"}
+
+Edge
+=type=7:PROJECT
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MGroup
+=properties=JsonObject(2):
+{"full_name":"a","name":"a"}
+----
+=to=Node
+=labels=Array(3):
+3:foo
+7:MEntity
+8:MProject
+=properties=JsonObject(1):
+{"name":"foo"}
+
+Edge
+=type=6:PARENT
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MGroup
+=properties=JsonObject(2):
+{"full_name":"a","name":"a"}
+----
+=to=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MGroup
+=properties=JsonObject(2):
+{"full_name":"","name":"foo"}
+
+Edge
+=type=5:NESTS
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MGroup
+=properties=JsonObject(2):
+{"full_name":"","name":"foo"}
+----
+=to=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MGroup
+=properties=JsonObject(2):
+{"full_name":"a","name":"a"}
+
+Edge
+=type=6:PARENT
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MGroup
+=properties=JsonObject(2):
+{"full_name":"a::b","name":"b"}
+----
+=to=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MGroup
+=properties=JsonObject(2):
+{"full_name":"a","name":"a"}
+
+Edge
+=type=5:NESTS
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MGroup
+=properties=JsonObject(2):
+{"full_name":"a","name":"a"}
+----
+=to=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MGroup
+=properties=JsonObject(2):
+{"full_name":"a::b","name":"b"}
+
+Edge
+=type=7:PROJECT
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MGroup
+=properties=JsonObject(2):
+{"full_name":"a::b","name":"b"}
+----
+=to=Node
+=labels=Array(3):
+3:foo
+7:MEntity
+8:MProject
+=properties=JsonObject(1):
+{"name":"foo"}
+
+Edge
+=type=7:PROJECT
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#10:namespacec
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MGroup
+=properties=JsonObject(2):
+{"full_name":"c","name":"c"}
+----
+=to=Node
+=labels=Array(3):
+3:foo
+7:MEntity
+8:MProject
+=properties=JsonObject(1):
+{"name":"foo"}
+
+Edge
+=type=6:PARENT
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#10:namespacec
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MGroup
+=properties=JsonObject(2):
+{"full_name":"c","name":"c"}
+----
+=to=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MGroup
+=properties=JsonObject(2):
+{"full_name":"","name":"foo"}
+
+Edge
+=type=5:NESTS
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MGroup
+=properties=JsonObject(2):
+{"full_name":"","name":"foo"}
+----
+=to=Entity#10:namespacec
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MGroup
+=properties=JsonObject(2):
+{"full_name":"c","name":"c"}
+
+Edge
+=type=7:PROJECT
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#10:namespaced
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MGroup
+=properties=JsonObject(2):
+{"full_name":"d","name":"d"}
+----
+=to=Node
+=labels=Array(3):
+3:foo
+7:MEntity
+8:MProject
+=properties=JsonObject(1):
+{"name":"foo"}
+
+Edge
+=type=6:PARENT
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#10:namespaced
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MGroup
+=properties=JsonObject(2):
+{"full_name":"d","name":"d"}
+----
+=to=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MGroup
+=properties=JsonObject(2):
+{"full_name":"","name":"foo"}
+
+Edge
+=type=5:NESTS
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MGroup
+=properties=JsonObject(2):
+{"full_name":"","name":"foo"}
+----
+=to=Entity#10:namespaced
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MGroup
+=properties=JsonObject(2):
+{"full_name":"d","name":"d"}
+
+Edge
+=type=8:DECLARES
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MGroup
+=properties=JsonObject(2):
+{"full_name":"","name":"foo"}
+----
+=to=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+7:MModule
+=properties=JsonObject(3):
+{"location":"\/dev\/null:1,1--1,1","name":"Bar","full_name":"Bar"}
+
+Edge
+=type=10:INTRODUCES
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+7:MModule
+=properties=JsonObject(3):
+{"location":"\/dev\/null:1,1--1,1","name":"Bar","full_name":"Bar"}
+----
+=to=Entity#8:classbaz
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MClass
+=properties=JsonObject(4):
+{"kind":"class","visibility":"public","full_name":"Baz","name":"Baz"}
+
+Edge
+=type=7:DEFINES
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+7:MModule
+=properties=JsonObject(3):
+{"location":"\/dev\/null:1,1--1,1","name":"Bar","full_name":"Bar"}
+----
+=to=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+9:MClassDef
+=properties=JsonObject(4):
+{"location":"\/dev\/null:1,1--1,1","is_intro":true,"name":"Baz","full_name":"Baz"}
+
+
--- /dev/null
+# Graph
+Edge
+=type=4:ROOT
+=properties=JsonObject(0):
+{}
+----
+=from=Node
+=labels=Array(3):
+3:foo
+7:MEntity
+8:MProject
+=properties=JsonObject(1):
+{"name":"foo"}
+----
+=to=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MGroup
+=properties=JsonObject(2):
+{"full_name":"","name":"foo"}
+
+Edge
+=type=7:PROJECT
+=properties=JsonObject(0):
+{}
+----
+=from=Entity#0:
+=labels=Array(3):
+3:foo
+7:MEntity
+6:MGroup
+=properties=JsonObject(2):
+{"full_name":"","name":"foo"}
+----
+=to=Node
+=labels=Array(3):
+3:foo
+7:MEntity
+8:MProject
+=properties=JsonObject(1):
+{"name":"foo"}
+
+
--- /dev/null
+X
+X
+X
+Y
+Y
+Y
+Y
+A
+G
+B
+G
--- /dev/null
+X
+X
+X
+Y
+Y
+Y
+Y
+A
+G
+B
+G
-Runtime error: Cast failed. Expected `OTHER`, got `Float` (../lib/standard/kernel.nit:374)
+Runtime error: Cast failed. Expected `OTHER`, got `Float` (../lib/standard/kernel.nit:411)
11
21
31
-Runtime error: Cast failed. Expected `OTHER`, got `Float` (../lib/standard/kernel.nit:374)
+Runtime error: Cast failed. Expected `OTHER`, got `Float` (../lib/standard/kernel.nit:411)
11
21
31
-Runtime error: Cast failed. Expected `OTHER`, got `Float` (../lib/standard/kernel.nit:374)
+Runtime error: Cast failed. Expected `OTHER`, got `Float` (../lib/standard/kernel.nit:411)
11
21
31
--- /dev/null
+Not in a nitiwiki directory.
+Use --init to initialize one here.
--- /dev/null
+nitiWiki
+name: wiki2
+config: ../contrib/nitiwiki/tests/wiki1/config2.ini
+url: http://localhost/
+
+There is modified files:
+ + pages
+ + /pages/index.md
+
+Use nitiwiki --render to render modified files
--- /dev/null
+Render section out
-<span class="nitcode"><span class="line" id="L1"><span class="nc_c"># This file is part of NIT ( http://www.nitlanguage.org ).
+<span class="nitcode"><span class="line" id="L1"><span class="nc_c"># This file is part of NIT ( http://www.nitlanguage.org ).
</span></span><span class="line" id="L2"><span class="nc_c">#
</span></span><span class="line" id="L3"><span class="nc_c"># Copyright 2006-2008 Jean Privat <jean@pryen.org>
</span></span><span class="line" id="L4"><span class="nc_c">#
-</span></span><span class="line" id="L5"><span class="nc_c"># Licensed under the Apache License, Version 2.0 (the "License");
+</span></span><span class="line" id="L5"><span class="nc_c"># Licensed under the Apache License, Version 2.0 (the "License");
</span></span><span class="line" id="L6"><span class="nc_c"># you may not use this file except in compliance with the License.
</span></span><span class="line" id="L7"><span class="nc_c"># You may obtain a copy of the License at
</span></span><span class="line" id="L8"><span class="nc_c">#
-</span></span><span class="line" id="L9"><span class="nc_c"># http://www.apache.org/licenses/LICENSE-2.0
+</span></span><span class="line" id="L9"><span class="nc_c"># http://www.apache.org/licenses/LICENSE-2.0
</span></span><span class="line" id="L10"><span class="nc_c">#
</span></span><span class="line" id="L11"><span class="nc_c"># Unless required by applicable law or agreed to in writing, software
-</span></span><span class="line" id="L12"><span class="nc_c"># distributed under the License is distributed on an "AS IS" BASIS,
+</span></span><span class="line" id="L12"><span class="nc_c"># distributed under the License is distributed on an "AS IS" BASIS,
</span></span><span class="line" id="L13"><span class="nc_c"># WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
</span></span><span class="line" id="L14"><span class="nc_c"># See the License for the specific language governing permissions and
</span></span><span class="line" id="L15"><span class="nc_c"># limitations under the License.
</span></span><span class="line" id="L16">
</span><span class="line" id="L17"><span class="nc_k">import</span> <span class="nc_k">end</span>
</span><span class="line" id="L18">
-</span><span class="nc_cdef foldable" id="base_simple3#Object"><span class="line" id="L19"><span class="nc_k">interface</span> <span class="nc_def nc_t popupable" title="class Object" data-title="<a href="base_simple3.html#base_simple3#Object">class Object</a>" data-content="<div><b>class</b> <span>Object</span><br/><div class="dropdown"> <a data-toggle="dropdown" href="#"><b>hier</b> sub-classes<span class="caret"></span></a><ul class="dropdown-menu" role="menu" aria-labelledby="dLabel"><li><a href="base_simple3.html#base_simple3#Bool">Bool</a></li><li><a href="base_simple3.html#base_simple3#Int">Int</a></li><li><a href="base_simple3.html#base_simple3#A">A</a></li><li><a href="base_simple3.html#base_simple3#B">B</a></li><li><a href="base_simple3.html#base_simple3#C">C</a></li><li><a href="base_simple3.html#base_simple3#Sys">Sys</a></li></ul></div></div>" data-toggle="popover">Object</span>
+</span><span class="nc_cdef foldable" id="base_simple3#Object"><span class="line" id="L19"><span class="nc_k">interface</span> <span class="nc_def nc_t popupable" title="class Object" data-title="<a href="base_simple3.html#base_simple3#Object">class Object</a>" data-content="<div><b>class</b> <span>Object</span><br/><div class="dropdown"> <a data-toggle="dropdown" href="#"><b>hier</b> sub-classes<span class="caret"></span></a><ul class="dropdown-menu" role="menu" aria-labelledby="dLabel"><li><a href="base_simple3.html#base_simple3#Bool">Bool</a></li><li><a href="base_simple3.html#base_simple3#Int">Int</a></li><li><a href="base_simple3.html#base_simple3#A">A</a></li><li><a href="base_simple3.html#base_simple3#B">B</a></li><li><a href="base_simple3.html#base_simple3#C">C</a></li><li><a href="base_simple3.html#base_simple3#Sys">Sys</a></li></ul></div></div>" data-toggle="popover">Object</span>
</span><span class="line" id="L20"><span class="nc_k">end</span>
</span></span><span class="line" id="L21">
-</span><span class="nc_cdef foldable" id="base_simple3#Bool"><span class="line" id="L22"><span class="nc_k">enum</span> <span class="nc_def nc_t popupable" title="class Bool" data-title="<a href="base_simple3.html#base_simple3#Bool">class Bool</a>" data-content="<div><b>class</b> <span>Bool</span><br/><div class="dropdown"> <a data-toggle="dropdown" href="#"><b>hier</b> super-classes<span class="caret"></span></a><ul class="dropdown-menu" role="menu" aria-labelledby="dLabel"><li><a href="base_simple3.html#base_simple3#Object">Object</a></li></ul></div></div>" data-toggle="popover">Bool</span>
+</span><span class="nc_cdef foldable" id="base_simple3#Bool"><span class="line" id="L22"><span class="nc_k">enum</span> <span class="nc_def nc_t popupable" title="class Bool" data-title="<a href="base_simple3.html#base_simple3#Bool">class Bool</a>" data-content="<div><b>class</b> <span>Bool</span><br/><div class="dropdown"> <a data-toggle="dropdown" href="#"><b>hier</b> super-classes<span class="caret"></span></a><ul class="dropdown-menu" role="menu" aria-labelledby="dLabel"><li><a href="base_simple3.html#base_simple3#Object">Object</a></li></ul></div></div>" data-toggle="popover">Bool</span>
</span><span class="line" id="L23"><span class="nc_k">end</span>
</span></span><span class="line" id="L24">
-</span><span class="nc_cdef foldable" id="base_simple3#Int"><span class="line" id="L25"><span class="nc_k">enum</span> <span class="nc_def nc_t popupable" title="class Int" data-title="<a href="base_simple3.html#base_simple3#Int">class Int</a>" data-content="<div><b>class</b> <span>Int</span><br/><div class="dropdown"> <a data-toggle="dropdown" href="#"><b>hier</b> super-classes<span class="caret"></span></a><ul class="dropdown-menu" role="menu" aria-labelledby="dLabel"><li><a href="base_simple3.html#base_simple3#Object">Object</a></li></ul></div></div>" data-toggle="popover">Int</span>
-</span><span class="nc_pdef foldable" id="base_simple3#Int#output"><span class="line" id="L26"> <span class="nc_k">fun</span> <span class="nc_def popupable" title="base_simple3#Int#output" data-title="<a href="base_simple3.html#base_simple3#Int#output">base_simple3#Int#output</a>" data-content="<div><b>fun</b> <span>output<span></span></span><br/></div>" data-toggle="popover"><span class="nc_i">output</span></span> <span class="nc_k">is</span> <span class="nc_i">intern</span>
+</span><span class="nc_cdef foldable" id="base_simple3#Int"><span class="line" id="L25"><span class="nc_k">enum</span> <span class="nc_def nc_t popupable" title="class Int" data-title="<a href="base_simple3.html#base_simple3#Int">class Int</a>" data-content="<div><b>class</b> <span>Int</span><br/><div class="dropdown"> <a data-toggle="dropdown" href="#"><b>hier</b> super-classes<span class="caret"></span></a><ul class="dropdown-menu" role="menu" aria-labelledby="dLabel"><li><a href="base_simple3.html#base_simple3#Object">Object</a></li></ul></div></div>" data-toggle="popover">Int</span>
+</span><span class="nc_pdef foldable" id="base_simple3#Int#output"><span class="line" id="L26"> <span class="nc_k">fun</span> <span class="nc_def popupable" title="base_simple3#Int#output" data-title="<a href="base_simple3.html#base_simple3#Int#output">base_simple3#Int#output</a>" data-content="<div><b>fun</b> <span>output<span></span></span><br/></div>" data-toggle="popover"><span class="nc_i">output</span></span> <span class="nc_k">is</span> <span class="nc_i">intern</span>
</span></span><span class="line" id="L27"><span class="nc_k">end</span>
</span></span><span class="line" id="L28">
-</span><span class="nc_cdef foldable" id="base_simple3#A"><span class="line" id="L29"><span class="nc_k">class</span> <span class="nc_def nc_t popupable" title="class A" data-title="<a href="base_simple3.html#base_simple3#A">class A</a>" data-content="<div><b>class</b> <span>A</span><br/><div class="dropdown"> <a data-toggle="dropdown" href="#"><b>hier</b> super-classes<span class="caret"></span></a><ul class="dropdown-menu" role="menu" aria-labelledby="dLabel"><li><a href="base_simple3.html#base_simple3#Object">Object</a></li></ul></div></div>" data-toggle="popover">A</span>
-</span><span class="nc_pdef foldable" id="base_simple3#A#init"><span class="line" id="L30"> <span class="nc_k">init</span> <span class="nc_k">do</span> <span class="nc_l popupable" title="Int" data-title="<a href="base_simple3.html#base_simple3#Int">Int</a>" data-content="<div><b>class</b> <span><a href="base_simple3.html#base_simple3#Int">Int</a></span><br/></div>" data-toggle="popover">5</span><span>.</span><span class="nc_i popupable" title="call base_simple3#Int#output" data-title="<a href="base_simple3.html#base_simple3#Int#output">call base_simple3#Int#output</a>" data-content="<div><b>call</b> <span><a href="base_simple3.html#base_simple3#Int#output">output</a><span></span></span><br/></div>" data-toggle="popover">output</span>
-</span></span><span class="nc_pdef foldable" id="base_simple3#A#run"><span class="line" id="L31"> <span class="nc_k">fun</span> <span class="nc_def popupable" title="base_simple3#A#run" data-title="<a href="base_simple3.html#base_simple3#A#run">base_simple3#A#run</a>" data-content="<div><b>fun</b> <span>run<span></span></span><br/></div>" data-toggle="popover"><span class="nc_i">run</span></span> <span class="nc_k">do</span> <span class="nc_l popupable" title="Int" data-title="<a href="base_simple3.html#base_simple3#Int">Int</a>" data-content="<div><b>class</b> <span><a href="base_simple3.html#base_simple3#Int">Int</a></span><br/></div>" data-toggle="popover">6</span><span>.</span><span class="nc_i popupable" title="call base_simple3#Int#output" data-title="<a href="base_simple3.html#base_simple3#Int#output">call base_simple3#Int#output</a>" data-content="<div><b>call</b> <span><a href="base_simple3.html#base_simple3#Int#output">output</a><span></span></span><br/></div>" data-toggle="popover">output</span>
+</span><span class="nc_cdef foldable" id="base_simple3#A"><span class="line" id="L29"><span class="nc_k">class</span> <span class="nc_def nc_t popupable" title="class A" data-title="<a href="base_simple3.html#base_simple3#A">class A</a>" data-content="<div><b>class</b> <span>A</span><br/><div class="dropdown"> <a data-toggle="dropdown" href="#"><b>hier</b> super-classes<span class="caret"></span></a><ul class="dropdown-menu" role="menu" aria-labelledby="dLabel"><li><a href="base_simple3.html#base_simple3#Object">Object</a></li></ul></div></div>" data-toggle="popover">A</span>
+</span><span class="nc_pdef foldable" id="base_simple3#A#init"><span class="line" id="L30"> <span class="nc_k">init</span> <span class="nc_k">do</span> <span class="nc_l popupable" title="Int" data-title="<a href="base_simple3.html#base_simple3#Int">Int</a>" data-content="<div><b>class</b> <span><a href="base_simple3.html#base_simple3#Int">Int</a></span><br/></div>" data-toggle="popover">5</span><span>.</span><span class="nc_i popupable" title="call base_simple3#Int#output" data-title="<a href="base_simple3.html#base_simple3#Int#output">call base_simple3#Int#output</a>" data-content="<div><b>call</b> <span><a href="base_simple3.html#base_simple3#Int#output">output</a><span></span></span><br/></div>" data-toggle="popover">output</span>
+</span></span><span class="nc_pdef foldable" id="base_simple3#A#run"><span class="line" id="L31"> <span class="nc_k">fun</span> <span class="nc_def popupable" title="base_simple3#A#run" data-title="<a href="base_simple3.html#base_simple3#A#run">base_simple3#A#run</a>" data-content="<div><b>fun</b> <span>run<span></span></span><br/></div>" data-toggle="popover"><span class="nc_i">run</span></span> <span class="nc_k">do</span> <span class="nc_l popupable" title="Int" data-title="<a href="base_simple3.html#base_simple3#Int">Int</a>" data-content="<div><b>class</b> <span><a href="base_simple3.html#base_simple3#Int">Int</a></span><br/></div>" data-toggle="popover">6</span><span>.</span><span class="nc_i popupable" title="call base_simple3#Int#output" data-title="<a href="base_simple3.html#base_simple3#Int#output">call base_simple3#Int#output</a>" data-content="<div><b>call</b> <span><a href="base_simple3.html#base_simple3#Int#output">output</a><span></span></span><br/></div>" data-toggle="popover">output</span>
</span></span><span class="line" id="L32"><span class="nc_k">end</span>
</span></span><span class="line" id="L33">
-</span><span class="nc_cdef foldable" id="base_simple3#B"><span class="line" id="L34"><span class="nc_k">class</span> <span class="nc_def nc_t popupable" title="class B" data-title="<a href="base_simple3.html#base_simple3#B">class B</a>" data-content="<div><b>class</b> <span>B</span><br/><div class="dropdown"> <a data-toggle="dropdown" href="#"><b>hier</b> super-classes<span class="caret"></span></a><ul class="dropdown-menu" role="menu" aria-labelledby="dLabel"><li><a href="base_simple3.html#base_simple3#Object">Object</a></li></ul></div></div>" data-toggle="popover">B</span>
-</span><span class="nc_pdef foldable" id="base_simple3#B#_val"><a id="base_simple3#B#val"></a><a id="base_simple3#B#val="></a><span class="line" id="L35"> <span class="nc_k">var</span> <span class="nc_def nc_i popupable" title="base_simple3#B#val" data-title="<a href="base_simple3.html#base_simple3#B#val">base_simple3#B#val</a>" data-content="<div><b>fun</b> <span>val<span>: <a href="base_simple3.html#base_simple3#Int">Int</a></span></span><br/></div>" data-toggle="popover">val</span><span>:</span> <span class="nc_t popupable" title="Int" data-title="<a href="base_simple3.html#base_simple3#Int">Int</a>" data-content="<div><b>class</b> <span><a href="base_simple3.html#base_simple3#Int">Int</a></span><br/></div>" data-toggle="popover">Int</span>
-</span></span><span class="nc_pdef foldable" id="base_simple3#B#init"><span class="line" id="L36"> <span class="nc_k">init</span><span>(</span><span class="nc_v nc_i popupable" title="v: Int" data-content="<div><b>local var</b> <span>v:<a href="base_simple3.html#base_simple3#Int">Int</a></span><br/></div>" data-toggle="popover">v</span><span>:</span> <span class="nc_t popupable" title="Int" data-title="<a href="base_simple3.html#base_simple3#Int">Int</a>" data-content="<div><b>class</b> <span><a href="base_simple3.html#base_simple3#Int">Int</a></span><br/></div>" data-toggle="popover">Int</span><span>)</span>
+</span><span class="nc_cdef foldable" id="base_simple3#B"><span class="line" id="L34"><span class="nc_k">class</span> <span class="nc_def nc_t popupable" title="class B" data-title="<a href="base_simple3.html#base_simple3#B">class B</a>" data-content="<div><b>class</b> <span>B</span><br/><div class="dropdown"> <a data-toggle="dropdown" href="#"><b>hier</b> super-classes<span class="caret"></span></a><ul class="dropdown-menu" role="menu" aria-labelledby="dLabel"><li><a href="base_simple3.html#base_simple3#Object">Object</a></li></ul></div></div>" data-toggle="popover">B</span>
+</span><span class="nc_pdef foldable" id="base_simple3#B#_val"><a id="base_simple3#B#val"></a><a id="base_simple3#B#val="></a><span class="line" id="L35"> <span class="nc_k">var</span> <span class="nc_def nc_i popupable" title="base_simple3#B#val" data-title="<a href="base_simple3.html#base_simple3#B#val">base_simple3#B#val</a>" data-content="<div><b>fun</b> <span>val<span>: <a href="base_simple3.html#base_simple3#Int">Int</a></span></span><br/></div>" data-toggle="popover">val</span><span>:</span> <span class="nc_t popupable" title="Int" data-title="<a href="base_simple3.html#base_simple3#Int">Int</a>" data-content="<div><b>class</b> <span><a href="base_simple3.html#base_simple3#Int">Int</a></span><br/></div>" data-toggle="popover">Int</span>
+</span></span><span class="nc_pdef foldable" id="base_simple3#B#init"><span class="line" id="L36"> <span class="nc_k">init</span><span>(</span><span class="nc_v nc_i popupable" title="v: Int" data-content="<div><b>local var</b> <span>v:<a href="base_simple3.html#base_simple3#Int">Int</a></span><br/></div>" data-toggle="popover">v</span><span>:</span> <span class="nc_t popupable" title="Int" data-title="<a href="base_simple3.html#base_simple3#Int">Int</a>" data-content="<div><b>class</b> <span><a href="base_simple3.html#base_simple3#Int">Int</a></span><br/></div>" data-toggle="popover">Int</span><span>)</span>
</span><span class="line" id="L37"> <span class="nc_k">do</span>
-</span><span class="line" id="L38"> <span class="nc_l popupable" title="Int" data-title="<a href="base_simple3.html#base_simple3#Int">Int</a>" data-content="<div><b>class</b> <span><a href="base_simple3.html#base_simple3#Int">Int</a></span><br/></div>" data-toggle="popover">7</span><span>.</span><span class="nc_i popupable" title="call base_simple3#Int#output" data-title="<a href="base_simple3.html#base_simple3#Int#output">call base_simple3#Int#output</a>" data-content="<div><b>call</b> <span><a href="base_simple3.html#base_simple3#Int#output">output</a><span></span></span><br/></div>" data-toggle="popover">output</span>
-</span><span class="line" id="L39"> <span class="nc_k">self</span><span>.</span><span class="nc_i popupable" title="call base_simple3#B#val=" data-title="<a href="base_simple3.html#base_simple3#B#val=">call base_simple3#B#val=</a>" data-content="<div><b>call</b> <span><a href="base_simple3.html#base_simple3#B#val=">val=</a><span>(val: <a href="base_simple3.html#base_simple3#Int">Int</a>)</span></span><br/></div>" data-toggle="popover">val</span> <span>=</span> <span class="nc_v nc_i popupable" title="v: Int" data-content="<div><b>local var</b> <span>v:<a href="base_simple3.html#base_simple3#Int">Int</a></span><br/></div>" data-toggle="popover">v</span>
+</span><span class="line" id="L38"> <span class="nc_l popupable" title="Int" data-title="<a href="base_simple3.html#base_simple3#Int">Int</a>" data-content="<div><b>class</b> <span><a href="base_simple3.html#base_simple3#Int">Int</a></span><br/></div>" data-toggle="popover">7</span><span>.</span><span class="nc_i popupable" title="call base_simple3#Int#output" data-title="<a href="base_simple3.html#base_simple3#Int#output">call base_simple3#Int#output</a>" data-content="<div><b>call</b> <span><a href="base_simple3.html#base_simple3#Int#output">output</a><span></span></span><br/></div>" data-toggle="popover">output</span>
+</span><span class="line" id="L39"> <span class="nc_k">self</span><span>.</span><span class="nc_i popupable" title="call base_simple3#B#val=" data-title="<a href="base_simple3.html#base_simple3#B#val=">call base_simple3#B#val=</a>" data-content="<div><b>call</b> <span><a href="base_simple3.html#base_simple3#B#val=">val=</a><span>(val: <a href="base_simple3.html#base_simple3#Int">Int</a>)</span></span><br/></div>" data-toggle="popover">val</span> <span>=</span> <span class="nc_v nc_i popupable" title="v: Int" data-content="<div><b>local var</b> <span>v:<a href="base_simple3.html#base_simple3#Int">Int</a></span><br/></div>" data-toggle="popover">v</span>
</span><span class="line" id="L40"> <span class="nc_k">end</span>
-</span></span><span class="nc_pdef foldable" id="base_simple3#B#run"><span class="line" id="L41"> <span class="nc_k">fun</span> <span class="nc_def popupable" title="base_simple3#B#run" data-title="<a href="base_simple3.html#base_simple3#B#run">base_simple3#B#run</a>" data-content="<div><b>fun</b> <span>run<span></span></span><br/></div>" data-toggle="popover"><span class="nc_i">run</span></span> <span class="nc_k">do</span> <span class="nc_i popupable" title="call base_simple3#B#val" data-title="<a href="base_simple3.html#base_simple3#B#val">call base_simple3#B#val</a>" data-content="<div><b>call</b> <span><a href="base_simple3.html#base_simple3#B#val">val</a><span>: <a href="base_simple3.html#base_simple3#Int">Int</a></span></span><br/></div>" data-toggle="popover">val</span><span>.</span><span class="nc_i popupable" title="call base_simple3#Int#output" data-title="<a href="base_simple3.html#base_simple3#Int#output">call base_simple3#Int#output</a>" data-content="<div><b>call</b> <span><a href="base_simple3.html#base_simple3#Int#output">output</a><span></span></span><br/></div>" data-toggle="popover">output</span>
+</span></span><span class="nc_pdef foldable" id="base_simple3#B#run"><span class="line" id="L41"> <span class="nc_k">fun</span> <span class="nc_def popupable" title="base_simple3#B#run" data-title="<a href="base_simple3.html#base_simple3#B#run">base_simple3#B#run</a>" data-content="<div><b>fun</b> <span>run<span></span></span><br/></div>" data-toggle="popover"><span class="nc_i">run</span></span> <span class="nc_k">do</span> <span class="nc_i popupable" title="call base_simple3#B#val" data-title="<a href="base_simple3.html#base_simple3#B#val">call base_simple3#B#val</a>" data-content="<div><b>call</b> <span><a href="base_simple3.html#base_simple3#B#val">val</a><span>: <a href="base_simple3.html#base_simple3#Int">Int</a></span></span><br/></div>" data-toggle="popover">val</span><span>.</span><span class="nc_i popupable" title="call base_simple3#Int#output" data-title="<a href="base_simple3.html#base_simple3#Int#output">call base_simple3#Int#output</a>" data-content="<div><b>call</b> <span><a href="base_simple3.html#base_simple3#Int#output">output</a><span></span></span><br/></div>" data-toggle="popover">output</span>
</span></span><span class="line" id="L42"><span class="nc_k">end</span>
</span></span><span class="line" id="L43">
-</span><span class="nc_cdef foldable" id="base_simple3#C"><span class="line" id="L44"><span class="nc_k">class</span> <span class="nc_def nc_t popupable" title="class C" data-title="<a href="base_simple3.html#base_simple3#C">class C</a>" data-content="<div><b>class</b> <span>C</span><br/><div class="dropdown"> <a data-toggle="dropdown" href="#"><b>hier</b> super-classes<span class="caret"></span></a><ul class="dropdown-menu" role="menu" aria-labelledby="dLabel"><li><a href="base_simple3.html#base_simple3#Object">Object</a></li></ul></div></div>" data-toggle="popover">C</span>
-</span><span class="nc_pdef foldable" id="base_simple3#C#_val1"><a id="base_simple3#C#val1"></a><a id="base_simple3#C#val1="></a><span class="line" id="L45"> <span class="nc_k">var</span> <span class="nc_def nc_i popupable" title="base_simple3#C#val1" data-title="<a href="base_simple3.html#base_simple3#C#val1">base_simple3#C#val1</a>" data-content="<div><b>fun</b> <span>val1<span>: <a href="base_simple3.html#base_simple3#Int">Int</a></span></span><br/></div>" data-toggle="popover">val1</span><span>:</span> <span class="nc_t popupable" title="Int" data-title="<a href="base_simple3.html#base_simple3#Int">Int</a>" data-content="<div><b>class</b> <span><a href="base_simple3.html#base_simple3#Int">Int</a></span><br/></div>" data-toggle="popover">Int</span>
-</span></span><span class="nc_pdef foldable" id="base_simple3#C#_val2"><a id="base_simple3#C#val2"></a><a id="base_simple3#C#val2="></a><span class="line" id="L46"> <span class="nc_k">var</span> <span class="nc_def nc_i popupable" title="base_simple3#C#val2" data-title="<a href="base_simple3.html#base_simple3#C#val2">base_simple3#C#val2</a>" data-content="<div><b>fun</b> <span>val2<span>: <a href="base_simple3.html#base_simple3#Int">Int</a></span></span><br/></div>" data-toggle="popover">val2</span><span>:</span> <span class="nc_t popupable" title="Int" data-title="<a href="base_simple3.html#base_simple3#Int">Int</a>" data-content="<div><b>class</b> <span><a href="base_simple3.html#base_simple3#Int">Int</a></span><br/></div>" data-toggle="popover">Int</span> <span>=</span> <span class="nc_l popupable" title="Int" data-title="<a href="base_simple3.html#base_simple3#Int">Int</a>" data-content="<div><b>class</b> <span><a href="base_simple3.html#base_simple3#Int">Int</a></span><br/></div>" data-toggle="popover">10</span>
+</span><span class="nc_cdef foldable" id="base_simple3#C"><span class="line" id="L44"><span class="nc_k">class</span> <span class="nc_def nc_t popupable" title="class C" data-title="<a href="base_simple3.html#base_simple3#C">class C</a>" data-content="<div><b>class</b> <span>C</span><br/><div class="dropdown"> <a data-toggle="dropdown" href="#"><b>hier</b> super-classes<span class="caret"></span></a><ul class="dropdown-menu" role="menu" aria-labelledby="dLabel"><li><a href="base_simple3.html#base_simple3#Object">Object</a></li></ul></div></div>" data-toggle="popover">C</span>
+</span><span class="nc_pdef foldable" id="base_simple3#C#_val1"><a id="base_simple3#C#val1"></a><a id="base_simple3#C#val1="></a><span class="line" id="L45"> <span class="nc_k">var</span> <span class="nc_def nc_i popupable" title="base_simple3#C#val1" data-title="<a href="base_simple3.html#base_simple3#C#val1">base_simple3#C#val1</a>" data-content="<div><b>fun</b> <span>val1<span>: <a href="base_simple3.html#base_simple3#Int">Int</a></span></span><br/></div>" data-toggle="popover">val1</span><span>:</span> <span class="nc_t popupable" title="Int" data-title="<a href="base_simple3.html#base_simple3#Int">Int</a>" data-content="<div><b>class</b> <span><a href="base_simple3.html#base_simple3#Int">Int</a></span><br/></div>" data-toggle="popover">Int</span>
+</span></span><span class="nc_pdef foldable" id="base_simple3#C#_val2"><a id="base_simple3#C#val2"></a><a id="base_simple3#C#val2="></a><span class="line" id="L46"> <span class="nc_k">var</span> <span class="nc_def nc_i popupable" title="base_simple3#C#val2" data-title="<a href="base_simple3.html#base_simple3#C#val2">base_simple3#C#val2</a>" data-content="<div><b>fun</b> <span>val2<span>: <a href="base_simple3.html#base_simple3#Int">Int</a></span></span><br/></div>" data-toggle="popover">val2</span><span>:</span> <span class="nc_t popupable" title="Int" data-title="<a href="base_simple3.html#base_simple3#Int">Int</a>" data-content="<div><b>class</b> <span><a href="base_simple3.html#base_simple3#Int">Int</a></span><br/></div>" data-toggle="popover">Int</span> <span>=</span> <span class="nc_l popupable" title="Int" data-title="<a href="base_simple3.html#base_simple3#Int">Int</a>" data-content="<div><b>class</b> <span><a href="base_simple3.html#base_simple3#Int">Int</a></span><br/></div>" data-toggle="popover">10</span>
</span></span><span class="line" id="L47"><span class="nc_k">end</span>
</span></span><span class="line" id="L48">
-</span><span class="nc_pdef foldable" id="base_simple3#Object#foo"><span class="line" id="L49"><span class="nc_k">fun</span> <span class="nc_def popupable" title="base_simple3#Object#foo" data-title="<a href="base_simple3.html#base_simple3#Object#foo">base_simple3#Object#foo</a>" data-content="<div><b>fun</b> <span>foo<span></span></span><br/></div>" data-toggle="popover"><span class="nc_i">foo</span></span> <span class="nc_k">do</span> <span class="nc_l popupable" title="Int" data-title="<a href="base_simple3.html#base_simple3#Int">Int</a>" data-content="<div><b>class</b> <span><a href="base_simple3.html#base_simple3#Int">Int</a></span><br/></div>" data-toggle="popover">2</span><span>.</span><span class="nc_i popupable" title="call base_simple3#Int#output" data-title="<a href="base_simple3.html#base_simple3#Int#output">call base_simple3#Int#output</a>" data-content="<div><b>call</b> <span><a href="base_simple3.html#base_simple3#Int#output">output</a><span></span></span><br/></div>" data-toggle="popover">output</span>
-</span></span><span class="nc_pdef foldable" id="base_simple3#Object#bar"><span class="line" id="L50"><span class="nc_k">fun</span> <span class="nc_def popupable" title="base_simple3#Object#bar" data-title="<a href="base_simple3.html#base_simple3#Object#bar">base_simple3#Object#bar</a>" data-content="<div><b>fun</b> <span>bar<span>(i: <a href="base_simple3.html#base_simple3#Int">Int</a>)</span></span><br/></div>" data-toggle="popover"><span class="nc_i">bar</span></span><span>(</span><span class="nc_v nc_i popupable" title="i: Int" data-content="<div><b>local var</b> <span>i:<a href="base_simple3.html#base_simple3#Int">Int</a></span><br/></div>" data-toggle="popover">i</span><span>:</span> <span class="nc_t popupable" title="Int" data-title="<a href="base_simple3.html#base_simple3#Int">Int</a>" data-content="<div><b>class</b> <span><a href="base_simple3.html#base_simple3#Int">Int</a></span><br/></div>" data-toggle="popover">Int</span><span>)</span> <span class="nc_k">do</span> <span class="nc_v nc_i popupable" title="i: Int" data-content="<div><b>local var</b> <span>i:<a href="base_simple3.html#base_simple3#Int">Int</a></span><br/></div>" data-toggle="popover">i</span><span>.</span><span class="nc_i popupable" title="call base_simple3#Int#output" data-title="<a href="base_simple3.html#base_simple3#Int#output">call base_simple3#Int#output</a>" data-content="<div><b>call</b> <span><a href="base_simple3.html#base_simple3#Int#output">output</a><span></span></span><br/></div>" data-toggle="popover">output</span>
-</span></span><span class="nc_pdef foldable" id="base_simple3#Object#baz"><span class="line" id="L51"><span class="nc_k">fun</span> <span class="nc_def popupable" title="base_simple3#Object#baz" data-title="<a href="base_simple3.html#base_simple3#Object#baz">base_simple3#Object#baz</a>" data-content="<div><b>fun</b> <span>baz<span>: <a href="base_simple3.html#base_simple3#Int">Int</a></span></span><br/></div>" data-toggle="popover"><span class="nc_i">baz</span></span><span>:</span> <span class="nc_t popupable" title="Int" data-title="<a href="base_simple3.html#base_simple3#Int">Int</a>" data-content="<div><b>class</b> <span><a href="base_simple3.html#base_simple3#Int">Int</a></span><br/></div>" data-toggle="popover">Int</span> <span class="nc_k">do</span> <span class="nc_k">return</span> <span class="nc_l popupable" title="Int" data-title="<a href="base_simple3.html#base_simple3#Int">Int</a>" data-content="<div><b>class</b> <span><a href="base_simple3.html#base_simple3#Int">Int</a></span><br/></div>" data-toggle="popover">4</span>
+</span><span class="nc_pdef foldable" id="base_simple3#Object#foo"><span class="line" id="L49"><span class="nc_k">fun</span> <span class="nc_def popupable" title="base_simple3#Object#foo" data-title="<a href="base_simple3.html#base_simple3#Object#foo">base_simple3#Object#foo</a>" data-content="<div><b>fun</b> <span>foo<span></span></span><br/></div>" data-toggle="popover"><span class="nc_i">foo</span></span> <span class="nc_k">do</span> <span class="nc_l popupable" title="Int" data-title="<a href="base_simple3.html#base_simple3#Int">Int</a>" data-content="<div><b>class</b> <span><a href="base_simple3.html#base_simple3#Int">Int</a></span><br/></div>" data-toggle="popover">2</span><span>.</span><span class="nc_i popupable" title="call base_simple3#Int#output" data-title="<a href="base_simple3.html#base_simple3#Int#output">call base_simple3#Int#output</a>" data-content="<div><b>call</b> <span><a href="base_simple3.html#base_simple3#Int#output">output</a><span></span></span><br/></div>" data-toggle="popover">output</span>
+</span></span><span class="nc_pdef foldable" id="base_simple3#Object#bar"><span class="line" id="L50"><span class="nc_k">fun</span> <span class="nc_def popupable" title="base_simple3#Object#bar" data-title="<a href="base_simple3.html#base_simple3#Object#bar">base_simple3#Object#bar</a>" data-content="<div><b>fun</b> <span>bar<span>(i: <a href="base_simple3.html#base_simple3#Int">Int</a>)</span></span><br/></div>" data-toggle="popover"><span class="nc_i">bar</span></span><span>(</span><span class="nc_v nc_i popupable" title="i: Int" data-content="<div><b>local var</b> <span>i:<a href="base_simple3.html#base_simple3#Int">Int</a></span><br/></div>" data-toggle="popover">i</span><span>:</span> <span class="nc_t popupable" title="Int" data-title="<a href="base_simple3.html#base_simple3#Int">Int</a>" data-content="<div><b>class</b> <span><a href="base_simple3.html#base_simple3#Int">Int</a></span><br/></div>" data-toggle="popover">Int</span><span>)</span> <span class="nc_k">do</span> <span class="nc_v nc_i popupable" title="i: Int" data-content="<div><b>local var</b> <span>i:<a href="base_simple3.html#base_simple3#Int">Int</a></span><br/></div>" data-toggle="popover">i</span><span>.</span><span class="nc_i popupable" title="call base_simple3#Int#output" data-title="<a href="base_simple3.html#base_simple3#Int#output">call base_simple3#Int#output</a>" data-content="<div><b>call</b> <span><a href="base_simple3.html#base_simple3#Int#output">output</a><span></span></span><br/></div>" data-toggle="popover">output</span>
+</span></span><span class="nc_pdef foldable" id="base_simple3#Object#baz"><span class="line" id="L51"><span class="nc_k">fun</span> <span class="nc_def popupable" title="base_simple3#Object#baz" data-title="<a href="base_simple3.html#base_simple3#Object#baz">base_simple3#Object#baz</a>" data-content="<div><b>fun</b> <span>baz<span>: <a href="base_simple3.html#base_simple3#Int">Int</a></span></span><br/></div>" data-toggle="popover"><span class="nc_i">baz</span></span><span>:</span> <span class="nc_t popupable" title="Int" data-title="<a href="base_simple3.html#base_simple3#Int">Int</a>" data-content="<div><b>class</b> <span><a href="base_simple3.html#base_simple3#Int">Int</a></span><br/></div>" data-toggle="popover">Int</span> <span class="nc_k">do</span> <span class="nc_k">return</span> <span class="nc_l popupable" title="Int" data-title="<a href="base_simple3.html#base_simple3#Int">Int</a>" data-content="<div><b>class</b> <span><a href="base_simple3.html#base_simple3#Int">Int</a></span><br/></div>" data-toggle="popover">4</span>
</span></span><span class="line" id="L52">
-</span><span class="nc_pdef foldable" id="base_simple3#Sys#main"><span class="line" id="L53"><span class="nc_l popupable" title="Int" data-title="<a href="base_simple3.html#base_simple3#Int">Int</a>" data-content="<div><b>class</b> <span><a href="base_simple3.html#base_simple3#Int">Int</a></span><br/></div>" data-toggle="popover">1</span><span>.</span><span class="nc_i popupable" title="call base_simple3#Int#output" data-title="<a href="base_simple3.html#base_simple3#Int#output">call base_simple3#Int#output</a>" data-content="<div><b>call</b> <span><a href="base_simple3.html#base_simple3#Int#output">output</a><span></span></span><br/></div>" data-toggle="popover">output</span>
-</span><span class="line" id="L54"><span class="nc_i popupable" title="call base_simple3#Object#foo" data-title="<a href="base_simple3.html#base_simple3#Object#foo">call base_simple3#Object#foo</a>" data-content="<div><b>call</b> <span><a href="base_simple3.html#base_simple3#Object#foo">foo</a><span></span></span><br/></div>" data-toggle="popover">foo</span>
-</span><span class="line" id="L55"><span class="nc_i popupable" title="call base_simple3#Object#bar" data-title="<a href="base_simple3.html#base_simple3#Object#bar">call base_simple3#Object#bar</a>" data-content="<div><b>call</b> <span><a href="base_simple3.html#base_simple3#Object#bar">bar</a><span>(i: <a href="base_simple3.html#base_simple3#Int">Int</a>)</span></span><br/></div>" data-toggle="popover">bar</span><span>(</span><span class="nc_l popupable" title="Int" data-title="<a href="base_simple3.html#base_simple3#Int">Int</a>" data-content="<div><b>class</b> <span><a href="base_simple3.html#base_simple3#Int">Int</a></span><br/></div>" data-toggle="popover">3</span><span>)</span>
-</span><span class="line" id="L56"><span class="nc_i popupable" title="call base_simple3#Object#baz" data-title="<a href="base_simple3.html#base_simple3#Object#baz">call base_simple3#Object#baz</a>" data-content="<div><b>call</b> <span><a href="base_simple3.html#base_simple3#Object#baz">baz</a><span>: <a href="base_simple3.html#base_simple3#Int">Int</a></span></span><br/></div>" data-toggle="popover">baz</span><span>.</span><span class="nc_i popupable" title="call base_simple3#Int#output" data-title="<a href="base_simple3.html#base_simple3#Int#output">call base_simple3#Int#output</a>" data-content="<div><b>call</b> <span><a href="base_simple3.html#base_simple3#Int#output">output</a><span></span></span><br/></div>" data-toggle="popover">output</span>
+</span><span class="nc_pdef foldable" id="base_simple3#Sys#main"><span class="line" id="L53"><span class="nc_l popupable" title="Int" data-title="<a href="base_simple3.html#base_simple3#Int">Int</a>" data-content="<div><b>class</b> <span><a href="base_simple3.html#base_simple3#Int">Int</a></span><br/></div>" data-toggle="popover">1</span><span>.</span><span class="nc_i popupable" title="call base_simple3#Int#output" data-title="<a href="base_simple3.html#base_simple3#Int#output">call base_simple3#Int#output</a>" data-content="<div><b>call</b> <span><a href="base_simple3.html#base_simple3#Int#output">output</a><span></span></span><br/></div>" data-toggle="popover">output</span>
+</span><span class="line" id="L54"><span class="nc_i popupable" title="call base_simple3#Object#foo" data-title="<a href="base_simple3.html#base_simple3#Object#foo">call base_simple3#Object#foo</a>" data-content="<div><b>call</b> <span><a href="base_simple3.html#base_simple3#Object#foo">foo</a><span></span></span><br/></div>" data-toggle="popover">foo</span>
+</span><span class="line" id="L55"><span class="nc_i popupable" title="call base_simple3#Object#bar" data-title="<a href="base_simple3.html#base_simple3#Object#bar">call base_simple3#Object#bar</a>" data-content="<div><b>call</b> <span><a href="base_simple3.html#base_simple3#Object#bar">bar</a><span>(i: <a href="base_simple3.html#base_simple3#Int">Int</a>)</span></span><br/></div>" data-toggle="popover">bar</span><span>(</span><span class="nc_l popupable" title="Int" data-title="<a href="base_simple3.html#base_simple3#Int">Int</a>" data-content="<div><b>class</b> <span><a href="base_simple3.html#base_simple3#Int">Int</a></span><br/></div>" data-toggle="popover">3</span><span>)</span>
+</span><span class="line" id="L56"><span class="nc_i popupable" title="call base_simple3#Object#baz" data-title="<a href="base_simple3.html#base_simple3#Object#baz">call base_simple3#Object#baz</a>" data-content="<div><b>call</b> <span><a href="base_simple3.html#base_simple3#Object#baz">baz</a><span>: <a href="base_simple3.html#base_simple3#Int">Int</a></span></span><br/></div>" data-toggle="popover">baz</span><span>.</span><span class="nc_i popupable" title="call base_simple3#Int#output" data-title="<a href="base_simple3.html#base_simple3#Int#output">call base_simple3#Int#output</a>" data-content="<div><b>call</b> <span><a href="base_simple3.html#base_simple3#Int#output">output</a><span></span></span><br/></div>" data-toggle="popover">output</span>
</span><span class="line" id="L57">
-</span><span class="line" id="L58"><span class="nc_k">var</span> <span class="nc_v nc_i popupable" title="a: A" data-content="<div><b>local var</b> <span>a:<a href="base_simple3.html#base_simple3#A">A</a></span><br/></div>" data-toggle="popover">a</span> <span>=</span> <span class="nc_k">new</span> <span class="nc_t popupable" title="A" data-title="<a href="base_simple3.html#base_simple3#A">A</a>" data-content="<div><b>class</b> <span><a href="base_simple3.html#base_simple3#A">A</a></span><br/></div>" data-toggle="popover">A</span>
-</span><span class="line" id="L59"><span class="nc_v nc_i popupable" title="a: A" data-content="<div><b>local var</b> <span>a:<a href="base_simple3.html#base_simple3#A">A</a></span><br/></div>" data-toggle="popover">a</span><span>.</span><span class="nc_i popupable" title="call base_simple3#A#run" data-title="<a href="base_simple3.html#base_simple3#A#run">call base_simple3#A#run</a>" data-content="<div><b>call</b> <span><a href="base_simple3.html#base_simple3#A#run">run</a><span></span></span><br/></div>" data-toggle="popover">run</span>
+</span><span class="line" id="L58"><span class="nc_k">var</span> <span class="nc_v nc_i popupable" title="a: A" data-content="<div><b>local var</b> <span>a:<a href="base_simple3.html#base_simple3#A">A</a></span><br/></div>" data-toggle="popover">a</span> <span>=</span> <span class="nc_k">new</span> <span class="nc_t popupable" title="A" data-title="<a href="base_simple3.html#base_simple3#A">A</a>" data-content="<div><b>class</b> <span><a href="base_simple3.html#base_simple3#A">A</a></span><br/></div>" data-toggle="popover">A</span>
+</span><span class="line" id="L59"><span class="nc_v nc_i popupable" title="a: A" data-content="<div><b>local var</b> <span>a:<a href="base_simple3.html#base_simple3#A">A</a></span><br/></div>" data-toggle="popover">a</span><span>.</span><span class="nc_i popupable" title="call base_simple3#A#run" data-title="<a href="base_simple3.html#base_simple3#A#run">call base_simple3#A#run</a>" data-content="<div><b>call</b> <span><a href="base_simple3.html#base_simple3#A#run">run</a><span></span></span><br/></div>" data-toggle="popover">run</span>
</span><span class="line" id="L60">
-</span><span class="line" id="L61"><span class="nc_k">var</span> <span class="nc_v nc_i popupable" title="b: B" data-content="<div><b>local var</b> <span>b:<a href="base_simple3.html#base_simple3#B">B</a></span><br/></div>" data-toggle="popover">b</span> <span>=</span> <span class="nc_k">new</span> <span class="nc_t popupable" title="B" data-title="<a href="base_simple3.html#base_simple3#B">B</a>" data-content="<div><b>class</b> <span><a href="base_simple3.html#base_simple3#B">B</a></span><br/></div>" data-toggle="popover">B</span><span>(</span><span class="nc_l popupable" title="Int" data-title="<a href="base_simple3.html#base_simple3#Int">Int</a>" data-content="<div><b>class</b> <span><a href="base_simple3.html#base_simple3#Int">Int</a></span><br/></div>" data-toggle="popover">8</span><span>)</span>
-</span><span class="line" id="L62"><span class="nc_v nc_i popupable" title="b: B" data-content="<div><b>local var</b> <span>b:<a href="base_simple3.html#base_simple3#B">B</a></span><br/></div>" data-toggle="popover">b</span><span>.</span><span class="nc_i popupable" title="call base_simple3#B#run" data-title="<a href="base_simple3.html#base_simple3#B#run">call base_simple3#B#run</a>" data-content="<div><b>call</b> <span><a href="base_simple3.html#base_simple3#B#run">run</a><span></span></span><br/></div>" data-toggle="popover">run</span>
+</span><span class="line" id="L61"><span class="nc_k">var</span> <span class="nc_v nc_i popupable" title="b: B" data-content="<div><b>local var</b> <span>b:<a href="base_simple3.html#base_simple3#B">B</a></span><br/></div>" data-toggle="popover">b</span> <span>=</span> <span class="nc_k">new</span> <span class="nc_t popupable" title="B" data-title="<a href="base_simple3.html#base_simple3#B">B</a>" data-content="<div><b>class</b> <span><a href="base_simple3.html#base_simple3#B">B</a></span><br/></div>" data-toggle="popover">B</span><span>(</span><span class="nc_l popupable" title="Int" data-title="<a href="base_simple3.html#base_simple3#Int">Int</a>" data-content="<div><b>class</b> <span><a href="base_simple3.html#base_simple3#Int">Int</a></span><br/></div>" data-toggle="popover">8</span><span>)</span>
+</span><span class="line" id="L62"><span class="nc_v nc_i popupable" title="b: B" data-content="<div><b>local var</b> <span>b:<a href="base_simple3.html#base_simple3#B">B</a></span><br/></div>" data-toggle="popover">b</span><span>.</span><span class="nc_i popupable" title="call base_simple3#B#run" data-title="<a href="base_simple3.html#base_simple3#B#run">call base_simple3#B#run</a>" data-content="<div><b>call</b> <span><a href="base_simple3.html#base_simple3#B#run">run</a><span></span></span><br/></div>" data-toggle="popover">run</span>
</span><span class="line" id="L63">
-</span><span class="line" id="L64"><span class="nc_k">var</span> <span class="nc_v nc_i popupable" title="c: C" data-content="<div><b>local var</b> <span>c:<a href="base_simple3.html#base_simple3#C">C</a></span><br/></div>" data-toggle="popover">c</span> <span>=</span> <span class="nc_k">new</span> <span class="nc_t popupable" title="C" data-title="<a href="base_simple3.html#base_simple3#C">C</a>" data-content="<div><b>class</b> <span><a href="base_simple3.html#base_simple3#C">C</a></span><br/></div>" data-toggle="popover">C</span><span>(</span><span class="nc_l popupable" title="Int" data-title="<a href="base_simple3.html#base_simple3#Int">Int</a>" data-content="<div><b>class</b> <span><a href="base_simple3.html#base_simple3#Int">Int</a></span><br/></div>" data-toggle="popover">9</span><span>)</span>
-</span><span class="line" id="L65"><span class="nc_v nc_i popupable" title="c: C" data-content="<div><b>local var</b> <span>c:<a href="base_simple3.html#base_simple3#C">C</a></span><br/></div>" data-toggle="popover">c</span><span>.</span><span class="nc_i popupable" title="call base_simple3#C#val1" data-title="<a href="base_simple3.html#base_simple3#C#val1">call base_simple3#C#val1</a>" data-content="<div><b>call</b> <span><a href="base_simple3.html#base_simple3#C#val1">val1</a><span>: <a href="base_simple3.html#base_simple3#Int">Int</a></span></span><br/></div>" data-toggle="popover">val1</span><span>.</span><span class="nc_i popupable" title="call base_simple3#Int#output" data-title="<a href="base_simple3.html#base_simple3#Int#output">call base_simple3#Int#output</a>" data-content="<div><b>call</b> <span><a href="base_simple3.html#base_simple3#Int#output">output</a><span></span></span><br/></div>" data-toggle="popover">output</span>
-</span><span class="line" id="L66"><span class="nc_v nc_i popupable" title="c: C" data-content="<div><b>local var</b> <span>c:<a href="base_simple3.html#base_simple3#C">C</a></span><br/></div>" data-toggle="popover">c</span><span>.</span><span class="nc_i popupable" title="call base_simple3#C#val2" data-title="<a href="base_simple3.html#base_simple3#C#val2">call base_simple3#C#val2</a>" data-content="<div><b>call</b> <span><a href="base_simple3.html#base_simple3#C#val2">val2</a><span>: <a href="base_simple3.html#base_simple3#Int">Int</a></span></span><br/></div>" data-toggle="popover">val2</span><span>.</span><span class="nc_i popupable" title="call base_simple3#Int#output" data-title="<a href="base_simple3.html#base_simple3#Int#output">call base_simple3#Int#output</a>" data-content="<div><b>call</b> <span><a href="base_simple3.html#base_simple3#Int#output">output</a><span></span></span><br/></div>" data-toggle="popover">output</span>
+</span><span class="line" id="L64"><span class="nc_k">var</span> <span class="nc_v nc_i popupable" title="c: C" data-content="<div><b>local var</b> <span>c:<a href="base_simple3.html#base_simple3#C">C</a></span><br/></div>" data-toggle="popover">c</span> <span>=</span> <span class="nc_k">new</span> <span class="nc_t popupable" title="C" data-title="<a href="base_simple3.html#base_simple3#C">C</a>" data-content="<div><b>class</b> <span><a href="base_simple3.html#base_simple3#C">C</a></span><br/></div>" data-toggle="popover">C</span><span>(</span><span class="nc_l popupable" title="Int" data-title="<a href="base_simple3.html#base_simple3#Int">Int</a>" data-content="<div><b>class</b> <span><a href="base_simple3.html#base_simple3#Int">Int</a></span><br/></div>" data-toggle="popover">9</span><span>)</span>
+</span><span class="line" id="L65"><span class="nc_v nc_i popupable" title="c: C" data-content="<div><b>local var</b> <span>c:<a href="base_simple3.html#base_simple3#C">C</a></span><br/></div>" data-toggle="popover">c</span><span>.</span><span class="nc_i popupable" title="call base_simple3#C#val1" data-title="<a href="base_simple3.html#base_simple3#C#val1">call base_simple3#C#val1</a>" data-content="<div><b>call</b> <span><a href="base_simple3.html#base_simple3#C#val1">val1</a><span>: <a href="base_simple3.html#base_simple3#Int">Int</a></span></span><br/></div>" data-toggle="popover">val1</span><span>.</span><span class="nc_i popupable" title="call base_simple3#Int#output" data-title="<a href="base_simple3.html#base_simple3#Int#output">call base_simple3#Int#output</a>" data-content="<div><b>call</b> <span><a href="base_simple3.html#base_simple3#Int#output">output</a><span></span></span><br/></div>" data-toggle="popover">output</span>
+</span><span class="line" id="L66"><span class="nc_v nc_i popupable" title="c: C" data-content="<div><b>local var</b> <span>c:<a href="base_simple3.html#base_simple3#C">C</a></span><br/></div>" data-toggle="popover">c</span><span>.</span><span class="nc_i popupable" title="call base_simple3#C#val2" data-title="<a href="base_simple3.html#base_simple3#C#val2">call base_simple3#C#val2</a>" data-content="<div><b>call</b> <span><a href="base_simple3.html#base_simple3#C#val2">val2</a><span>: <a href="base_simple3.html#base_simple3#Int">Int</a></span></span><br/></div>" data-toggle="popover">val2</span><span>.</span><span class="nc_i popupable" title="call base_simple3#Int#output" data-title="<a href="base_simple3.html#base_simple3#Int#output">call base_simple3#Int#output</a>" data-content="<div><b>call</b> <span><a href="base_simple3.html#base_simple3#Int#output">output</a><span></span></span><br/></div>" data-toggle="popover">output</span>
</span></span><span class="line" id="L67"><span></span></span></span>
\ No newline at end of file
-Usage: nitls [OPTION]... <file.nit|directory>...
-Lists the projects and/or paths of Nit sources files.
-Use --help for help
+UNDEFINED
-base_simple3 (base_simple3.nit)
-project1 (project1)
+\e[1mbase_simple3\e[m (\e[33mbase_simple3.nit\e[m)
+project1 (\e[33mproject1\e[m)
+|--\e[1mmodule1\e[m (\e[33mproject1/module1.nit\e[m)
+|--\e[1mmodule2\e[m (\e[33mproject1/module2.nit\e[m)
+`--\e[1mproject1\e[m (\e[33mproject1/project1.nit\e[m)
-base_simple3 (base_simple3.nit)
-`--base_simple3 (base_simple3.nit)
-project1 (project1)
-`--project1 (project1/project1.nit)
+\e[1mbase_simple3\e[m (\e[33mbase_simple3.nit\e[m)
+project1 (\e[33mproject1\e[m)
+|--\e[1mmodule1\e[m (\e[33mproject1/module1.nit\e[m)
+|--\e[1mmodule2\e[m (\e[33mproject1/module2.nit\e[m)
+`--\e[1mproject1\e[m (\e[33mproject1/project1.nit\e[m)
-base_simple3 (base_simple3.nit)
-`--base_simple3 (base_simple3.nit)
-project1 (project1)
-|--module1 (project1/module1.nit)
-|--module2 (project1/module2.nit)
-`--project1 (project1/project1.nit)
+\e[1mbase_simple3\e[m (\e[33mbase_simple3.nit\e[m)
+project1 (\e[33mproject1\e[m)
+|--\e[1mmodule1\e[m (\e[33mproject1/module1.nit\e[m)
+|--\e[1mmodule2\e[m (\e[33mproject1/module2.nit\e[m)
+`--\e[1mproject1\e[m (\e[33mproject1/project1.nit\e[m)
-base_simple3/base_simple3 (base_simple3.nit)
-project1/project1 (project1/project1.nit)
+base_simple3/\e[1mbase_simple3\e[m (\e[33mbase_simple3.nit\e[m)
+project1/\e[1mmodule1\e[m (\e[33mproject1/module1.nit\e[m)
+project1/\e[1mmodule2\e[m (\e[33mproject1/module2.nit\e[m)
+project1/\e[1mproject1\e[m (\e[33mproject1/project1.nit\e[m)
Object -> Bool [dir=back arrowtail=open style=dashed];
Float [
- label = "{Float||}"
+ label = "{Float||+ is_approx(other: Float, precision: Float): Bool\l}"
]
Numeric -> Float [dir=back arrowtail=open style=dashed];
Object -> Bool [dir=back arrowtail=open style=dashed];
Float [
- label = "{Float||}"
+ label = "{Float||+ is_approx(other: Float, precision: Float): Bool\l}"
]
Numeric -> Float [dir=back arrowtail=open style=dashed];
test_nitunit.nit:23,2--25,0: FAILURE: nitunit.test_nitunit.test_nitunit::X.test_nitunit::X::foo (in .nitunit/test_nitunit-3.nit): .nitunit/test_nitunit-3.nit:5,8--27: Error: Method or variable 'undefined_identifier' unknown in Sys.
-test_test_nitunit.nit:36,2--40,4: ERROR: test_foo1 (in file .nitunit/test_test_nitunit_TestX_test_foo1.nit): Runtime error: Assert failed (test_test_nitunit.nit:39)
+test_test_nitunit.nit:36,2--40,4: ERROR: test_foo1 (in file .nitunit/gen_test_test_nitunit.nit): Runtime error: Assert failed (test_test_nitunit.nit:39)
DocUnits:
Entities: 27; Documented ones: 3; With nitunits: 3; Failures: 2
Class suites: 1; Test Cases: 3; Failures: 1
<testsuites><testsuite package="test_nitunit"><testcase classname="nitunit.test_nitunit.<module>" name="<module>"><system-err></system-err><system-out>assert true
</system-out></testcase><testcase classname="nitunit.test_nitunit.test_nitunit::X" name="<class>"><system-err></system-err><system-out>assert false
-</system-out><error message="Runtime error: Assert failed (.nitunit/test_nitunit-2.nit:5)
+</system-out><error message="Runtime error: Assert failed (.nitunit/test_nitunit-2.nit:5)
"></error></testcase><testcase classname="nitunit.test_nitunit.test_nitunit::X" name="test_nitunit::X::foo"><system-err></system-err><system-out>assert undefined_identifier
-</system-out><failure message=".nitunit/test_nitunit-3.nit:5,8--27: Error: Method or variable 'undefined_identifier' unknown in Sys.
+</system-out><failure message=".nitunit/test_nitunit-3.nit:5,8--27: Error: Method or variable 'undefined_identifier' unknown in Sys.
"></failure></testcase></testsuite><testsuite package="test_test_nitunit"><testcase classname="nitunit.test_test_nitunit.test_test_nitunit::TestX" name="test_test_nitunit::TestX::test_foo"><system-err></system-err><system-out>out</system-out></testcase><testcase classname="nitunit.test_test_nitunit.test_test_nitunit::TestX" name="test_test_nitunit::TestX::test_foo1"><system-err></system-err><system-out>out</system-out><error message="Runtime error: Assert failed (test_test_nitunit.nit:39)
"></error></testcase><testcase classname="nitunit.test_test_nitunit.test_test_nitunit::TestX" name="test_test_nitunit::TestX::test_foo2"><system-err></system-err><system-out>out</system-out></testcase></testsuite></testsuites>
\ No newline at end of file
--- /dev/null
+DocUnits:
+DocUnits Success
+Entities: 6; Documented ones: 5; With nitunits: 3; Failures: 0
+
+TestSuites:
+No test cases found
+Class suites: 0; Test Cases: 0; Failures: 0
+<testsuites><testsuite package="test_doc2"><testcase classname="nitunit.test_doc2.standard::kernel::Object" name="test_doc2::Object::foo1"><system-err></system-err><system-out>assert true # tested
+</system-out></testcase><testcase classname="nitunit.test_doc2.standard::kernel::Object" name="test_doc2::Object::foo2"><system-err></system-err><system-out>assert true # tested
+</system-out></testcase><testcase classname="nitunit.test_doc2.standard::kernel::Object" name="test_doc2::Object::foo3"><system-err></system-err><system-out>assert true # tested
+</system-out></testcase></testsuite><testsuite></testsuite></testsuites>
\ No newline at end of file
-Runtime error: Assert failed (../lib/c.nit:64)
+Runtime error: Assert failed (../lib/c.nit:45)
-Runtime error: Assert failed (../lib/c.nit:57)
+Runtime error: Assert failed (../lib/c.nit:37)
0
-Runtime error: Assert failed (../lib/c.nit:57)
+Runtime error: Assert failed (../lib/c.nit:37)
0
-Runtime error: Assert failed (../lib/c.nit:56)
+Runtime error: Assert failed (../lib/c.nit:36)
0
0
1
h5 {font-weight:bold;}
.nitcode a { color: inherit; cursor:pointer; }
.nitcode .popupable:hover { text-decoration: underline; cursor:help; } /* underline titles */
-pre.nitcode .foldable { display: block } /* for block productions*/
-pre.nitcode .line{ display: block } /* for lines */
-pre.nitcode .line:hover{ background-color: #FFFFE0; } /* current line */
+.nitcode .foldable { display: block } /* for block productions*/
+.nitcode .line{ display: block } /* for lines */
+.nitcode .line:hover{ background-color: #FFFFE0; } /* current line */
.nitcode :target { background-color: #FFF3C2 } /* target highlight*/
/* lexical raw tokens. independent of usage or semantic: */
.nitcode .nc_c { color: gray; font-style: italic; } /* comment */
</span><span class="line" id="L2"><span class="nc_i">block</span>
</span><span class="line" id="L3"><span></span></span></span></pre><p>a first example</p><pre class="nitcode"><span class="nitcode"><span class="line" id="L1"><span class="nc_k">assert</span> <span class="nc_l">1</span> <span class="nc_o">+</span> <span class="nc_l">1</span> <span class="nc_o">==</span> <span class="nc_l">2</span>
</span><span class="line" id="L2"><span></span></span></span></pre><p>and a last example to illustrate the <code class="nitcode"><span class="nitcode"><span class="line" id="L1"><span class="nc_i">to_s</span><span></span></span></span></code> method on <code class="nitcode"><span class="nitcode"><span class="line" id="L1"><span class="nc_t">A</span><span></span></span></span></code>.</p><pre class="nitcode"><span class="nitcode"><span class="line" id="L1"><span class="nc_k">var</span> <span class="nc_i">a</span> <span>=</span> <span class="nc_k">new</span> <span class="nc_t">A</span>
-</span><span class="line" id="L2"><span class="nc_k">assert</span> <span class="nc_i">a</span><span>.</span><span class="nc_i">to_s</span> <span class="nc_o">==</span> <span class="nc_s">"A"</span>
+</span><span class="line" id="L2"><span class="nc_k">assert</span> <span class="nc_i">a</span><span>.</span><span class="nc_i">to_s</span> <span class="nc_o">==</span> <span class="nc_s">"A"</span>
</span><span class="line" id="L3"><span></span></span></span></pre></div><script src="http://code.jquery.com/jquery-1.11.0.min.js"></script>
<script src="http://netdna.bootstrapcdn.com/bootstrap/3.1.1/js/bootstrap.min.js"></script>
<script>$(".popupable").popover({html:true, placement:'top'})/*initialize bootstrap popover*/</script></body></html>
\ No newline at end of file
--- /dev/null
+<html><head>
+<meta charset="utf-8">
+<link rel="stylesheet" href="http://netdna.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap.min.css">
+<style type="text/css">
+code {margin: 0 2px;
+padding: 0px 5px;
+border: 1px solid #ddd;
+background-color: #f8f8f8;
+border-radius: 3px;}
+pre {
+background-color: #f8f8f8;
+border: 1px solid #ddd;
+font-size: 13px;
+line-height: 19px;
+overflow: auto;
+padding: 6px 6px;
+border-radius: 3px;
+}
+.rawcode[title] {
+border-color: red;
+}
+h5 {font-weight:bold;}
+.nitcode a { color: inherit; cursor:pointer; }
+.nitcode .popupable:hover { text-decoration: underline; cursor:help; } /* underline titles */
+.nitcode .foldable { display: block } /* for block productions*/
+.nitcode .line{ display: block } /* for lines */
+.nitcode .line:hover{ background-color: #FFFFE0; } /* current line */
+.nitcode :target { background-color: #FFF3C2 } /* target highlight*/
+/* lexical raw tokens. independent of usage or semantic: */
+.nitcode .nc_c { color: gray; font-style: italic; } /* comment */
+.nitcode .nc_d { color: #3D8127; font-style: italic; } /* documentation comments */
+.nitcode .nc_k { font-weight: bold; } /* keyword */
+.nitcode .nc_o {} /* operator */
+.nitcode .nc_i {} /* standard identifier */
+.nitcode .nc_t { color: #445588; font-weight: bold; } /* type/class identifier */
+.nitcode .nc_a { color: #445588; font-style: italic; } /* old style attribute identifier */
+.nitcode .nc_l { color: #009999; } /* char and number literal */
+.nitcode .nc_s { color: #8F1546; } /* string literal */
+/* syntactic token usage. added because of their position in the AST */
+.nitcode .nc_ast { color: blue; } /* assert label */
+.nitcode .nc_la { color: blue; } /* break/continue label */
+.nitcode .nc_m { color: #445588; } /* module name */
+/* syntactic groups */
+.nitcode .nc_def { font-weight: bold; color: blue; } /* name used in a definition */
+ .nitcode .nc_def.nc_a { color: blue; } /* name used in a attribute definition */
+ .nitcode .nc_def.nc_t { color: blue; } /* name used in a class or vt definition */
+.nitcode .nc_ss { color: #9E6BEB; } /* superstrings */
+.nitcode .nc_cdef {} /* A whole class definition */
+.nitcode .nc_pdef {} /* A whole property definition */
+/* semantic token usage */
+.nitcode .nc_v { font-style: italic; } /* local variable or parameter */
+.nitcode .nc_vt { font-style: italic; } /* virtual type or formal type */
+
+.nitcode .nc_error { border: 1px red solid;} /* not used */
+.popover { max-width: 800px !important; }
+
+</style>
+</head><body><h3 id='test_doc2'>module test_doc2</h1><h5 id='test_doc2#Object#foo1'>prop test_doc2#Object#foo1</h3><div class="nitdoc"><p class="synopsys">Test code</p><pre class="nitcode"><span class="nitcode"><span class="line" id="L1"><span class="nc_k">assert</span> <span class="nc_k">true</span> <span># tested
+</span></span><span class="line" id="L2"><span></span></span></span></pre></div><h5 id='test_doc2#Object#foo2'>prop test_doc2#Object#foo2</h3><div class="nitdoc"><p class="synopsys">Test code</p><pre class="nitcode"><span class="nitcode"><span class="line" id="L1"><span class="nc_k">assert</span> <span class="nc_k">true</span> <span># tested
+</span></span><span class="line" id="L2"><span></span></span></span></pre></div><h5 id='test_doc2#Object#foo3'>prop test_doc2#Object#foo3</h3><div class="nitdoc"><p class="synopsys">Test code</p><pre class="nitcode"><span class="nitcode"><span class="line" id="L1"><span class="nc_k">assert</span> <span class="nc_k">true</span> <span># tested
+</span></span><span class="line" id="L2"><span></span></span></span></pre></div><h5 id='test_doc2#Object#foo4'>prop test_doc2#Object#foo4</h3><div class="nitdoc"><p class="synopsys">Test code</p><pre class="rawcode">assert false # not tested (and not highlighted)
+</pre></div><h5 id='test_doc2#Object#foo5'>prop test_doc2#Object#foo5</h3><div class="nitdoc"><p class="synopsys">Test code</p><pre class="nitcode"><span class="nitcode"><span class="line" id="L1"><span class="nc_k">assert</span> <span class="nc_k">false</span> <span># not tested (but highlighted)
+</span></span><span class="line" id="L2"><span></span></span></span></pre></div><script src="http://code.jquery.com/jquery-1.11.0.min.js"></script>
+<script src="http://netdna.bootstrapcdn.com/bootstrap/3.1.1/js/bootstrap.min.js"></script>
+<script>$(".popupable").popover({html:true, placement:'top'})/*initialize bootstrap popover*/</script></body></html>
\ No newline at end of file
--- /dev/null
+From Objective-C: 2468 12.340000 1234
+From Nit: 2468 12.34 1234
--- /dev/null
+test_glsl_validation.nit:24,0: Shader error on 'binding' : not supported for this version or the enabled extensions
+test_glsl_validation.nit:24,0: Shader error on 'binding' : requires uniform or buffer storage qualifier
+test_glsl_validation.nit:24,0: Shader error on 'binding' : requires block, or sampler/image, or atomic-counter type
+test_glsl_validation.nit:28,0: Shader error on 'gl_FragColor' : undeclared identifier
+test_glsl_validation.nit:28,0: Shader error on 'assign' : cannot convert from 'mediump 4-component vector of float' to 'float'
+test_glsl_validation.nit:29,0: Shader error on 'b' : undeclared identifier
-Runtime error: Cast failed. Expected `E`, got `Bool` (../lib/standard/collection/array.nit:782)
+Runtime error: Cast failed. Expected `E`, got `Bool` (../lib/standard/collection/array.nit:785)
NativeString
N
Nit
--- /dev/null
+`clear` and `append`: abcd
+`clear` and `add`: ab
+`add` at `maxlen + 1`: c
+`append` up to `maxlen + 1`: ab
+`reverse`: xyz
+`upper`: foo
+`lower`: BAR
--- /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.
+
+# Test code
+#
+# assert true # tested
+fun foo1 do end
+
+# Test code
+#
+# ~~~~
+# assert true # tested
+# ~~~~
+fun foo2 do end
+
+# Test code
+#
+# ~~~~nit
+# assert true # tested
+# ~~~~
+fun foo3 do end
+
+# Test code
+#
+# ~~~~raw
+# assert false # not tested (and not highlighted)
+# ~~~~
+fun foo4 do end
+
+# Test code
+#
+# ~~~~nitish
+# assert false # not tested (but highlighted)
+# ~~~~
+fun foo5 do end
--- /dev/null
+test_doc.nit
+test_doc2.nit
--- /dev/null
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Copyright 2014 Alexis Laferrière <alexis.laf@xymus.net>
+#
+# 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.
+
+module test_ffi_objc_types_and_callbacks
+
+fun foo(i: Int, f: Float, s: String)
+import bar, String.to_cstring, Int.+ in "ObjC" `{
+ char *cstr = String_to_cstring(s);
+
+ long ii = Int__plus(i, i);
+
+ printf("From Objective-C: %ld %f %s\n", ii, f, cstr);
+
+ Object_bar(recv, ii, f, s);
+`}
+
+fun bar(i: Int, f: Float, s: String)
+do
+ print "From Nit: {i} {f} {s}"
+end
+
+foo(1234, 12.34, "1234")
--- /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.
+
+import glesv2
+
+var shader = """
+#version 300 es
+precision mediump float;
+
+in vec4 v_color;
+in vec2 v_texCoord;
+uniform sampler2D vTex;
+layout(binding = 0) out vec4 outColor;
+
+void main()
+{
+ gl_FragColor = v_color * texture(vTex, v_texCoord);
+ b;
+}
+""" @ glsl_fragment_shader
+
+shader.to_s # silences the "never read warning"
+++ /dev/null
-test_doc.nit
print "\n# Test lazy\n"
-client = new Neo4jClient("http://localhost:7474")
+client = new Neo4jClient("http://localhost:7474/")
assert client.is_ok
# Read Andres
--- /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.
+
+# Checks that `RopeBuffer.add` does not makes the internal buffer overflow.
+#
+# Note: In order to help repoducibility, this test read an private attribute of
+# the buffer.
+module test_ropes_buffer_add_overflow
+
+import standard
+intrude import ropes
+
+var buffer = new RopeBuffer
+
+buffer.append("x" * maxlen)
+buffer.add 'y'
+assert buffer.rpos <= maxlen else print "{buffer.rpos} > {maxlen}"
--- /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.
+
+# Checks if `RopeBuffer.clear` actually reset everything.
+module test_ropes_buffer_clear
+
+import standard
+
+var buffer = new RopeBuffer
+
+buffer.append "1"
+# Force to flush the internal buffer, so that all the internal positions will be
+# set to a non-zero value.
+buffer.append("?" * (maxlen + 1))
+buffer.clear
+buffer.append "23"
+print buffer
+
+buffer = new RopeBuffer
+buffer.append "12"
+# Force to flush the internal buffer, so that all the internal positions will be
+# set to a non-zero value.
+buffer.append("?" * (maxlen + 1))
+buffer.clear
+buffer.append "3"
+print buffer
--- /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.
+
+module test_ropes_buffer_reverse
+
+import standard
+
+redef fun maxlen do return 3
+
+var buffer = new RopeBuffer
+
+buffer.reverse
+print "/{buffer}/"
+
+buffer.append("x" * (maxlen + 1))
+buffer.add 'y'
+buffer.reverse
+print buffer.to_s
--- /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.
+
+# Checks the immutability of the strings returned by `RopeBuffer.to_s`.
+module test_ropes_buffer_to_s
+
+import standard
+
+# Note: In this sort of test, never print the string more than once: the string
+# itself may cache an flatten representation of itself when `print` calls `to_s`
+# on it. For example, the original bug that motivated the writting of the
+# present test got unoticed until we tried to edit the buffer **before**
+# outputting `s`.
+
+var buffer = new RopeBuffer
+var s: String
+
+sys.stdout.write "`clear` and `append`: "
+buffer.append "abcd"
+s = buffer.to_s
+buffer.clear
+buffer.append "ef"
+print s
+
+sys.stdout.write "`clear` and `add`: "
+buffer.clear
+buffer.add 'a'
+buffer.add 'b'
+s = buffer.to_s
+buffer.clear
+buffer.add 'c'
+print s
+
+sys.stdout.write "`add` at `maxlen + 1`: "
+buffer.clear
+buffer.add 'c'
+s = buffer.to_s
+buffer.append("*" * (maxlen -1))
+buffer.add 'x'
+print s
+
+sys.stdout.write "`append` up to `maxlen + 1`: "
+buffer.clear
+buffer.append "ab"
+s = buffer.to_s
+buffer.append("*" * (maxlen -1))
+print s
+
+sys.stdout.write "`reverse`: "
+buffer.clear
+buffer.append "xyz"
+s = buffer.to_s
+buffer.reverse
+print s
+
+sys.stdout.write "`upper`: "
+buffer.clear
+buffer.append "foo"
+s = buffer.to_s
+buffer.upper
+print s
+
+sys.stdout.write "`lower`: "
+buffer.clear
+buffer.append "BAR"
+s = buffer.to_s
+buffer.lower
+print s
paths=`echo $JAVA_HOME/jre/lib/*/{client,server}/`
paths=($paths)
JNI_LIB_PATH=${paths[0]}
-echo $JAVA_HOME
-echo $JNI_LIB_PATH
shopt -u nullglob
outdir="out"
echo >>$xml "<testcase classname='`xmlesc "$3"`' name='`xmlesc "$2"`' `timestamp`><skipped/></testcase>"
return 0
fi
+
+ # Skip by OS
+ os_skip_file=`uname`.skip
+ if test -e $os_skip_file && echo "$1" | grep -f "$os_skip_file"; then
+ echo "=> $2: [skip os]"
+ echo >>$xml "<testcase classname='`xmlesc "$3"`' name='`xmlesc "$2"`' `timestamp`><skipped/></testcase>"
+ return 0
+ fi
return 1
}