Playing with the QML/JS plugin

Sven Brauch svenbrauch at googlemail.com
Mon Apr 7 20:38:54 UTC 2014


Hi,

On Monday 07 April 2014 22:10:58 Denis Steckelmacher wrote:
> I've pushed an experimental branch of the QML/JS plugin in
> kde:scratch/dsteckelmacher/kdev-qmljs, branch "experiments". This branch
> contains one commit that is mostly the result of me playing with the
> plugin and the DUChain for a day.
Awesome! Would you mind picking out things you think are working into separate 
commits and maybe submitting them to reviewboard for example?

> My patch mostly moves code around (it removes expressionvisitor.cpp and
> merges its code into declarationbuilder.cpp, the commit message explains
> why) and adds some small type inference features.
Intuitively, I'm skeptical about whether that is going to work. In other 
languages (when I say that, I mostly speak about python ;) the Expression 
visitor is used to get the type of an expression in a variety of places. For 
example, when I have a = 3 I create an expression visitor to visit the 3, then 
assign the type to the variable. However, when I have foo.append(3), then 
maybe I want to add the type of 3 to the list content type of foo. Having a 
tool which allows to do "determine the type of this expression and return it" 
is very flexible and usable in a variety of situations.
You might be able to replace that flexibility partially by what you're doing 
now -- storing the types of nodes in those nodes themselves. I can't really 
judge whether this is "good enough", though. For example, for code completion 
it sounds a bit difficult to re-use (you don't want to run the declaration 
builder on the expressions you handle in completion).

What motivated you to remove the expression visitor? Why is it an advantage?

> For instance, the
> plugin is now able to correctly guess the types of all these variables :
> 
> // Variables that were already guessed before my patch
> var a = 5;	// int
> var b = a;	// int
> var f = function() { return "hello" };  // function string()
> var c = f();	// string
> 
> // Variable not guessed correctly by ExpressionVisitor
> var d = (a == b); // ExpressionVisitor::lastType guessed int
> 
> // Things that were not previously guessed
> var e = (a > b);	// bool
> var f = (aFunction() & 0x1)	// int
> var g = (function() { return c; })(); // string
> 
> The whole testsuite of the plugin passes without failure, and I've added
> two tests (one for the variable "g" of my example, and one for "d" which
> was wrongly guessed).
Great, especially that you added tests ;)

> (for instance, I never know
> where I have to hold a DUChain read lock, therefore many of them may be
> missing).
Me neither *cough* :D
In more seriousness, whenever you have pointers to duchain objects around 
(e.g. Declaration*) you generally need to hold a read lock, and when you 
change anything which is already in the persistent database you need a write 
lock. It is a bit unclear how strict the former is in the parsejob though, 
there would be some investigation needed eventually -- which is probably 
difficult :(
In any case, if you compile kdevplatform in debug mode, it will assert in 
almost all situations where you do it wrong. There's very little chances for 
screwing this up.

> As the type inference system and the declaration builder are
> now intertwined, I also had to declare variables and QML fields in
> endVisit() instead of visit(), because the types get known only when
> endVisit() is called. I would appreciate any comment on what I've done :-) .
To me it seems like all those problems are generally avoided by having the 
expression visitor separate. Because then when you visit e.g. an assignment (a 
= 3) you can just do
  ExpressionVisitor v(assignment->rhs);
  lhs_decl->setType(v.type());
or so.

> * Can I change the type of a declaration once it has been closed (for
> instance, by using getDeclaration(...)->setType(new_type))? This would
> allow me to guess that a in "var a; a = 5" is of type int, and it would
> be especially useful for setting the type of function parameters once
> they are used in a context were their type becomes evident.
Yes, you can do that at any time. Make sure to look at how unsure types work, 
too, those are important for dynamic languages ;)

> * Is it possible for a declaration to have a source range outside the
> range of its parent context? It would be very useful to implement things
> like "var a = {}; a.b = 5;", with b being a field declared in the {}
> context created in the first statement.
I'm not 100% sure but I think no, not so easily. I think we already discussed 
this as a possible issue a while back in IRC, no? Much of the duchain, esp. 
its memory management (cleanup logic) is built around having everything nicely 
ordered and nested range-wise. Python has an ugly hack for allowing pretty 
much exactly this (declaring class members from outside the class context). We 
should investigate if we can find a more proper solution some day, now that 
more languages than just one need this.

Greetings!
Sven


More information about the KDevelop-devel mailing list