Merge: Better Entity::full_name
authorJean Privat <jean@pryen.org>
Thu, 28 Apr 2016 23:04:51 +0000 (19:04 -0400)
committerJean Privat <jean@pryen.org>
Thu, 28 Apr 2016 23:04:51 +0000 (19:04 -0400)
This PR is a continuation of previous work on packages, model entities and namespaces. See #1069, #1092 or #1032 for the history.

The point of `full_name` is to offer the simpler canonical names possible that is:

* global. i.e. based on the package name.
* stable on modifications. i.e. the name of an entity does not change if other entities are added.
* human readable. i.e. some encoding but not binary.
* scalable. i.e. simple entities have simple names, complex entities have more complex names.

This PR add the following:

* no name collision on distinct kind of entities (packages, root groups, and default modules conflict no more).
* do not use characters that have a special semantic in URL (no more `#` and `/`).
* some bugfixes and simplifications.
* a complex test case with a lot of rare entity constructions (so complex names).
* a extended `test_model_visitor` that check and count names.

## Proposed full_name policy

### Common public entities

They are those you might look for in a doc.
They can appear in error messages.
In case of name conflict in programs, you might also use them to disambiguate things (in the future)

* packages have a simple name.
  e.g. `core` or `nitcorn` (unchanged)
* groups, are separated by `>` (instead of `/`) and terminated by a trailing `>` (to distinguish them)
  e.g. `core>` or `core>collection>`
* modules are just prefixed by their package, even the default module
  e.g. `core::kernel` or `core::core`
* public classes are prefixed by their packages
  e.g. `core::Object` or `core::Buffer` (unchanged)
* public global properties without refinement, are prefixed by their package and class
  e.g. `core::Object::==` or `core::Buffer::add` (unchanged)

Because of modules and class refinement, things unusual in other languages must have a full_name:

Public global properties introduced by a refinement, require the module (between the package and the class)
e.g. `core::file::Sys::print`
Currently, the compiler allows that a same package refines a public class in two distinct modules, with two homonym properties.
I'm not sure this is a good idea, but the rare uses force us to accept them.
The most infamous are `nitc::nitc::ToolContext::opt_dir` and `nitc::nitdoc::ToolContext::opt_dir`.

Private classes and properties are only visible by their module, thus the module name is required in their full_name.
e.g. `core::hash_collection::HashNode` or `core::hash_collection::HashNode::key` (unchanged)

### Definitions

As you know, class definitions (introductions and refinements) and property definitions are distinguished from their global counterpart.
Most of the time, we try to avoid referring specifically to them when the global thing is sufficient.

Class definitions combine the information of a class and a module.
Property definitions combine the information of a class definition and a property.
Therefore, the quantity of information for the worst case of property definition can be quite large.

A `$` is used to separate the information (it was `#` previously).
A single `$` means a class definition and two `$` means a property definition.

Introductions (without refinement nor redefinition) are designated like global properties (`::` are just replaced by `$`).

* `core$Object` is the definition that introduces of `core::Object`
* `core$Buffer$add` is the definition that introduces `core::Buffer::add`
* `core::hash_collection$HashNode$key` is the definition that introduces `core::hash_collection::HashNode::key`.

For refinements of classes, the class part is prefixed by package and module information when they are needed.
As requested, the full_name of the refinement of a public class in the same package is more simple than the refinement of a private class in a different package.

* `core::file$Sys` is the refinement of Sys in `core::file`. `Sys` is unambiguously `core::Sys`
* `counter::counter$core::Collection` is the refinement of `core::Collection` in the module `counter::counter`
* `hash_debug::hash_debug$core::hash_collection::HashCollection` is the refinement of `HashCollection` (it's a private class) in `hash_debug`
* `pthreads::extra$::pthreads::NativePthread` is the refinement of the private class `NativePthread` in an extra module in the same package (`$::` means that the package name is the same).

For redefinitions of properties, the full_name for the class definition is used (see above), then the property part contains whatever package, module or class information is required.

* `core$Array$SimpleCollection::add` the redefinition of `SimpleCollection::add` into `Array`
* `core$String$::abstract_text::Text::substrings` the redefinition of the private method `Text::substrings` in `String`

For simple method refinements (refinement of the introduction), most of the information is already given by the module or the class, the property part is thus simple.

* `hash_debug::hash_debug$core::hash_collection::HashCollection$store` is the refinement of the private method `HashCollection::store` in the useful package `has_debug`.

Complex method redefinition of private things provide the worst full_name (3 package names, 3 module names, 2 class names and a property name).

* `ropes_debug::ropes_debug$core::ropes::Concat$::ropes_debug::Text::internal_to_dot` is the redefinition of `ropes_debug::ropes_debug::Text::internal_to_dot` in the class `core::ropes::Concat` by the module `ropes_debug::ropes_debug`.

Pull-Request: #2041
Reviewed-by: Alexis Laferrière <alexis.laf@xymus.net>


Trivial merge