Enforce rules indicated in #1047.
So, having homonymous public modules and classes in a same project raises an error.
In the current code there was no conflicting modules. It is not surprising because for a long time the compilers refused homonymous modules even in different projects.
There was only 2 conflicting classes (on a total of 3640). This is more a good surprise since I expected a lot of conflicts. It is some kind of prof that the proposed policy is not that crazy. The two pairs of conflicting classes were `UnicodeChar` in `lib/string_experimentations/utf8.nit` and `lib/string_experimentations/utf8_noindex.nit`, and `Frame` in `naive_interpreter` and `abstract_compiler`. Some commits in the PR rename one of each pair to solve the conflicts.
For public properties, the proposed rule is to have a unique full-name "project::class::name".
There was 11 conflicts, again, it is far less than I expected.
Two of these conflict are resolved in some commits.
The other 9 are currently left as is (and the displayed error is in fact a warning).
All these remaining conflicts are a variation of the same pattern: homonymous options in refinements of ToolContext for different tools. Eg `opt_rta` for `nitmetrics` and for `nitc`.
I am not sure what is the correct way to solve these since the conflict is not only in the name but also in the behavior (a refinement of those two modules will have a broken option parsing). Maybe, behind the name conflict, there is also a bad model that misuses class refinement.
Pull-Request: #1069
Reviewed-by: Alexis Laferrière <alexis.laf@xymus.net>
Reviewed-by: Alexandre Terrasa <alexandre@moz-code.org>
redef class AnalysisManager
- fun run(src: String)
+ fun run_web(src: String)
do
sys.suggest_garbage_collection
end
redef class NativeString
- fun run_analysis do manager.run to_s
+ fun run_analysis do manager.run_web to_s
end
fun dummy_set_callbacks import NativeString.run_analysis in "C++" `{
# UTF-8 char as defined in RFC-3629, e.g. 1-4 Bytes
#
# A UTF-8 char has its bytes stored in a NativeString (char*)
-extern class UnicodeChar `{ UTF8Char* `}
+extern class UTF8Char `{ UTF8Char* `}
new(pos: Int, ns: NativeString) `{
UTF8Char* u = malloc(sizeof(UTF8Char));
# Returns the Unicode code point representing the character
#
# Note : A unicode character might not be a visible glyph, but it will be used to determine canonical equivalence
- fun code_point: Int import UnicodeChar.len `{
- switch(UnicodeChar_len(recv)){
+ fun code_point: Int import UTF8Char.len `{
+ switch(UTF8Char_len(recv)){
case 1:
return (long)(0x7F & (unsigned char)recv->ns[recv->pos]);
case 2:
#
# NOTE : Works only on ASCII chars
# TODO : Support unicode for to_upper
- fun to_upper: UnicodeChar import UnicodeChar.code_point `{
- int cp = UnicodeChar_code_point(recv);
+ fun to_upper: UTF8Char import UTF8Char.code_point `{
+ int cp = UTF8Char_code_point(recv);
if(cp < 97 || cp > 122){ return recv; }
char* ns = malloc(2);
ns[1] = '\0';
#
# NOTE : Works only on ASCII chars
# TODO : Support unicode for to_upper
- fun to_lower: UnicodeChar import UnicodeChar.code_point `{
- int cp = UnicodeChar_code_point(recv);
+ fun to_lower: UTF8Char import UTF8Char.code_point `{
+ int cp = UTF8Char_code_point(recv);
if(cp < 65 || cp > 90){ return recv; }
char* ns = malloc(2);
ns[1] = '\0';
if o isa Char then
if len != 1 then return false
if code_point == o.ascii then return true
- else if o isa UnicodeChar then
+ else if o isa UTF8Char then
if len != o.len then return false
if code_point == o.code_point then return true
end
return false
end
- redef fun output import UnicodeChar.code_point `{
- switch(UnicodeChar_len(recv)){
+ redef fun output import UTF8Char.code_point `{
+ switch(UTF8Char_len(recv)){
case 1:
printf("%c", recv->ns[recv->pos]);
break;
`}
redef fun to_s import NativeString.to_s_with_length `{
- int len = utf8___UnicodeChar_len___impl(recv);
+ int len = utf8___UTF8Char_len___impl(recv);
char* r = malloc(len + 1);
r[len] = '\0';
char* src = (recv->ns + recv->pos);
new(size: Int) `{ return malloc(size*sizeof(UTF8Char)); `}
# Sets the character at `index` as `item`
- fun []=(index: Int, item: UnicodeChar) `{ recv[index] = *item; `}
+ fun []=(index: Int, item: UTF8Char) `{ recv[index] = *item; `}
# Gets the character at position `id`
- fun [](id: Int): UnicodeChar `{ return &recv[id]; `}
+ fun [](id: Int): UTF8Char `{ return &recv[id]; `}
# Copies a part of self starting at index `my_from` of length `length` into `other`, starting at `its_from`
fun copy_to(other: StringIndex, my_from: Int, its_from: Int, length: Int)`{
var uchar = index[i]
var uchar_len = uchar.len
ipos -= uchar_len
- new_index[pos_index] = new UnicodeChar(ipos, native)
+ new_index[pos_index] = new UTF8Char(ipos, native)
pos_index -= 1
items.copy_to(native, uchar_len, pos, ipos)
pos += uchar_len
# Creates the index for said NativeString
# `length` is the size of the CString (in bytes, up to the first \0)
# real_len is just a way to store the length (UTF-8 characters)
- private fun make_index(length: Int, real_len: Container[Int]): StringIndex import Container[Int].item=, UnicodeChar.len `{
+ private fun make_index(length: Int, real_len: Container[Int]): StringIndex import Container[Int].item=, UTF8Char.len `{
int pos = 0;
int index_pos = 0;
UTF8Char* index = malloc(length*sizeof(UTF8Char));
UTF8Char* curr = &index[index_pos];
curr->pos = pos;
curr->ns = recv;
- pos += UnicodeChar_len(curr);
+ pos += UTF8Char_len(curr);
index_pos ++;
}
Container_of_Int_item__assign(real_len, index_pos);
# The current visited AST node
var current_node: nullable ANode = null is writable
- # The current `Frame`
- var frame: nullable Frame = null is writable
+ # The current `StaticFrame`
+ var frame: nullable StaticFrame = null is writable
# Alias for self.compiler.mainmodule.object_type
fun object_type: MClassType do return self.compiler.mainmodule.object_type
end
end
-# A frame correspond to a visited property in a `GlobalCompilerVisitor`
-class Frame
+# The static context of a visited property in a `AbstractCompilerVisitor`
+class StaticFrame
type VISITOR: AbstractCompilerVisitor
var oldnode = v.current_node
v.current_node = self
var old_frame = v.frame
- var frame = new Frame(v, self.mpropdef.as(not null), recv.mcasttype.as_notnullable.as(MClassType), [recv])
+ var frame = new StaticFrame(v, self.mpropdef.as(not null), recv.mcasttype.as_notnullable.as(MClassType), [recv])
v.frame = frame
var value
var oldnode = v.current_node
v.current_node = self
var old_frame = v.frame
- var frame = new Frame(v, self.mpropdef.as(not null), recv.mtype.as(MClassType), [recv])
+ var frame = new StaticFrame(v, self.mpropdef.as(not null), recv.mtype.as(MClassType), [recv])
v.frame = frame
# Force read to check the initialization
v.read_attribute(self.mpropdef.mproperty, recv)
selfvar.is_exact = true
end
var arguments = new Array[RuntimeVariable]
- var frame = new Frame(v, mmethoddef, recv, arguments)
+ var frame = new StaticFrame(v, mmethoddef, recv, arguments)
v.frame = frame
var sig = new FlatBuffer
ret = v.resolve_for(ret, arguments.first)
end
if self.mmethoddef.can_inline(v) then
- var frame = new Frame(v, self.mmethoddef, self.recv, arguments)
+ var frame = new StaticFrame(v, self.mmethoddef, self.recv, arguments)
frame.returnlabel = v.get_name("RET_LABEL")
if ret != null then
frame.returnvar = v.new_var(ret)
(compiler.modelbuilder.toolcontext.opt_inline_some_methods.value and mmethoddef.can_inline(self)) then
compiler.modelbuilder.nb_invok_by_inline += 1
if compiler.modelbuilder.toolcontext.opt_invocation_metrics.value then add("count_invoke_by_inline++;")
- var frame = new Frame(self, mmethoddef, recvtype, arguments)
+ var frame = new StaticFrame(self, mmethoddef, recvtype, arguments)
frame.returnlabel = self.get_name("RET_LABEL")
frame.returnvar = res
var old_frame = self.frame
# of the method (ie recv) if the static type is unresolved
# This is more complex than usual because the unresolved type must not be resolved
# with the current receiver (ie self).
- # Therefore to isolate the resolution from self, a local Frame is created.
+ # Therefore to isolate the resolution from self, a local StaticFrame is created.
# One can see this implementation as an inlined method of the receiver whose only
# job is to allocate the array
var old_frame = self.frame
- var frame = new Frame(self, mpropdef, mpropdef.mclassdef.bound_mtype, [recv])
+ var frame = new StaticFrame(self, mpropdef, mpropdef.mclassdef.bound_mtype, [recv])
self.frame = frame
#print "required Array[{elttype}] for recv {recv.inspect}. bound=Array[{self.resolve_for(elttype, recv)}]. selfvar={frame.arguments.first.inspect}"
var res = self.array_instance(varargs, elttype)
var v = compiler.new_visitor
var selfvar = new RuntimeVariable("self", recv, recv)
var arguments = new Array[RuntimeVariable]
- var frame = new Frame(v, mmethoddef, recv, arguments)
+ var frame = new StaticFrame(v, mmethoddef, recv, arguments)
v.frame = frame
var msignature = mmethoddef.msignature.resolve_for(mmethoddef.mclassdef.bound_mtype, mmethoddef.mclassdef.bound_mtype, mmethoddef.mclassdef.mmodule, true)
var v = compiler.new_visitor
var selfvar = new RuntimeVariable("self", v.object_type, recv)
var arguments = new Array[RuntimeVariable]
- var frame = new Frame(v, mmethoddef, recv, arguments)
+ var frame = new StaticFrame(v, mmethoddef, recv, arguments)
v.frame = frame
var sig = new FlatBuffer
end
end
+ # Check for conflicting module names in the project
+ if mgroup != null then
+ var others = model.get_mmodules_by_name(mod_name)
+ if others != null then for other in others do
+ if other.mgroup!= null and other.mgroup.mproject == mgroup.mproject then
+ var node: ANode
+ if decl == null then node = nmodule else node = decl.n_name
+ error(node, "Error: A module named `{other.full_name}` already exists at {other.location}")
+ break
+ end
+ end
+ end
+
# Create the module
var mmodule = new MModule(model, mgroup, mod_name, nmodule.location)
nmodule.mmodule = mmodule
assert mgroup.default_mmodule == null
mgroup.default_mmodule = self
end
- # placebo for old module nesting hierarchy
- var direct_owner = mgroup.default_mmodule
- if direct_owner == self then
- # The potential owner is the default_mmodule of the parent group
- if mgroup.parent != null then direct_owner = mgroup.parent.default_mmodule
- end
end
self.in_importation = model.mmodule_importation_hierarchy.add_node(self)
end
error(nclassdef, "Redef error: No imported class {name} to refine.")
return
end
+
+ # Check for conflicting class full-names in the project
+ if mmodule.mgroup != null and mvisibility >= protected_visibility then
+ var mclasses = model.get_mclasses_by_name(name)
+ if mclasses != null then for other in mclasses do
+ if other.intro_mmodule.mgroup != null and other.intro_mmodule.mgroup.mproject == mmodule.mgroup.mproject then
+ error(nclassdef, "Error: A class named `{other.full_name}` is already defined in module `{other.intro_mmodule}` at {other.intro.location}.")
+ break
+ end
+ end
+ end
+
mclass = new MClass(mmodule, name, names, mkind, mvisibility)
#print "new class {mclass}"
else if nclassdef isa AStdClassdef and nmodule.mclass2nclassdef.has_key(mclass) then
modelbuilder.error(self, "Redef error: {mclassdef.mclass}::{mprop.name} is an inherited property. To redefine it, add the redef keyword.")
return false
end
+
+ # Check for full-name conflicts in the project.
+ # A public property should have a unique qualified name `project::class::prop`.
+ if mprop.intro_mclassdef.mmodule.mgroup != null and mprop.visibility >= protected_visibility then
+ var others = modelbuilder.model.get_mproperties_by_name(mprop.name)
+ if others != null then for other in others do
+ if other != mprop and other.intro_mclassdef.mmodule.mgroup != null and other.intro_mclassdef.mmodule.mgroup.mproject == mprop.intro_mclassdef.mmodule.mgroup.mproject and other.intro_mclassdef.mclass.name == mprop.intro_mclassdef.mclass.name and other.visibility >= protected_visibility then
+ modelbuilder.advice(self, "full-name-conflict", "Warning: A property named `{other.full_name}` is already defined in module `{other.intro_mclassdef.mmodule}` for the class `{other.intro_mclassdef.mclass.name}`.")
+ break
+ end
+ end
+ end
else
if not need_redef then
modelbuilder.error(self, "Error: No property {mclassdef.mclass}::{mprop.name} is inherited. Remove the redef keyword to define a new property.")
import docdown
redef class ModelBuilder
- fun test_markdown(page: HTMLTag, mmodule: MModule)
+ fun do_test_markdown(page: HTMLTag, mmodule: MModule)
do
page.add_raw_html "<h3 id='{mmodule}'>module {mmodule}</h1>"
var mdoc = mmodule.mdoc
page.add mdoc.full_markdown
end
for m in g.mmodules do
- modelbuilder.test_markdown(page, m)
+ modelbuilder.do_test_markdown(page, m)
end
end
end
else
for m in mmodules do
- modelbuilder.test_markdown(page, m)
+ modelbuilder.do_test_markdown(page, m)
end
end