[Geany] Scoped Ruby declarations, with a hackish patch

Colomban Wendling lists.ban at xxxxx
Fri Sep 7 00:22:23 UTC 2012


Le 07/09/2012 00:49, Lex Trotman a écrit :
> On 7 September 2012 04:58, Colomban Wendling <lists.ban at herbesfolles.org> wrote:
>> Hi guys,
>>
>> I saw that the ruby parser don't properly generate tags declarations like:
>>
>>         class Foo::Bar
>>         end
>>
>> which should generate a tag "Bar" with the scope "Foo";  but it
>> generates a tag "Foo" and simply ignores "Bar".  This seems to apply to
>> modules, classes and methods at least -- almost everything.
>>
>> So I wanted to fix that.  Unfortunately the scoping code in CTags don't
>> really support to easily put several scopes at the same "level", e.g. if
>> you want to push several scope you gotta handle the popping yourself.
>> And since there is one single block end, it's tricky to do.
>>
>> Since I was way too lazy (and didn't even found a good implementation)
>> to fix that, I just did it the dirty way: reading the whole "Foo::Bar"
> 
> This is of course what C++ does when the declarations are not visible eg
> 
> a::b::f(){}; makes a function 'a::b::f' if the declarations of a and b
> are not visible (eg in a closed .hpp file), if they are visible it
> puts f inside the declaration of b. Compare the symbols pane entrys
> for the definitions of f() and g() in the attached.

I don't think you got what I meant.  I'm not talking about what you see
in the symbol list, I'm talking about how the tags get parsed.  Of
course the symbol list shows something like "A::B::C" if A and B are not
declared, but that's just because symbol C has scope A::B and we display
the scope if we can't display the actual parent.

OK, maybe I could take a look at how the C++ parser parses A::B::C,
maybe they have a better solution;  but what I'm saying is that the
parser first reads identifiers A, B and C and put them in a single
string (with a separator of course) as if it was the identifier itself,
and splits it back later in "A::B" and "C" and uses the first as an
additional scope and the last as the symbol name.  This means that if
the separator token ("::" in the example) can appear in a legitimate,
non-scoped identifier, it'd break.  And the code is quite ugly since it
first packs to later unpack.

A nicer approach would perhaps be to have a separation between blocks
and scope, e.g. a stack of blocks each accepting a multi-level scope,
instead of assuming block level == scope level.  Something like:

	struct Block {
		char *scope[];
		struct Block children[];
	}

thus the code:

	namespace Foo {}
	class Foo::Bar {
		class Baz {}
	}
	method Foo::Bar::something {}

would give:

	Block root = {
		.scope = {}
		.children = {
			{
				.scope = { "Foo" }
				.children = {}
			},
			{
				.scope = { "Foo", "Bar" },
				.children = {
					{
						.scope = { "Baz" },
						.children = {}
					}
			  	}
			},
			{
				.scope = { "Foo", "Bar", "something" },
				.children = {}
			}
		}
	}

Of course in practice we only need one block (with parents) at a time,
so we could simply use a two-dimensional array instead of such a complex
tree.  E.g. hierarchy inside class Baz would be:

	{ { "Foo", "Bar" }, { "Baz" } }

but if it was written like:

	namespace Foo {
		class Bar {
			class Baz {}
		}
	}

the hierarchy would've been

	{ { "Foo" }, { "Bar" }, { "Baz" } }

e.g. "classic", where each block level corresponds to only one scope --
like it is now.

But again, I'm only talking about how the parser is written.

> I'm not a rubyist but I assume that Foo doesn't need to be declared
> before Bar in the above example and thats the problem.  From the C++
> example what you would need to do is "autodeclare" Foo (as what?) so
> you had somewhere to put Bar.

Nope, basic test shows that Ruby wants the levels to be declared, so
there is no need for auto-declaration.  However I think Vala's
namespaces needs the feature, e.g. the following:

	namespace Foo.Bar {}

declares both namespaces Foo and Foo::Bar for that scope, and

	class Foo.Bar () {}

declares namespace Foo and class Foo::Bar.

>> as a single tag name ("Foo.Bar") and tuning the code registering the tag
>> to split this on the last ".", putting the left part (if any) in the
>> scope.  Patch attached.  This is quite dirty, but works fine unless a
>> legitimate tag may include a "." in its name, which doesn't seem the
>> case currently looking at the parser.
>>
>> Note that Ruby isn't the only language that allows such kind of scoping.
>>  For example, Vala allows to prefix stuff with a namespace -- and there
>> is the same problem here.
> 
> But it is statically declared so it should work like C++ should it not?

What do you mean?

> 
> Cheers
> Lex
> 
>>
>> So, especially Nick, what do you guys think of this?  Is this patch too
>> dirty?  Do somebody have a better idea?  Or is this too dirty and "we
>> don't care because nobody writes ruby anyway"?  In one word: opinions?
>>
>> Thanks,
>> Colomban
>>
>> _______________________________________________
>> Geany mailing list
>> Geany at uvena.de
>> https://lists.uvena.de/cgi-bin/mailman/listinfo/geany
>>
>>
>>
>> _______________________________________________
>> Geany mailing list
>> Geany at uvena.de
>> https://lists.uvena.de/cgi-bin/mailman/listinfo/geany




More information about the Users mailing list