Montag, 16. Juli 2012

I can haz QMetaObject?

I was asked if it was possible to define signals and slots from inside qling. While I hadn't thought about that until then, the solution seemed simple enough and I went ahead and implemented it.

I am just searching for Q_OBJECT in the user's input and, if found, invoke moc, pipe the users input into moc's stdin and, if successful, pass moc's output back into the interpreter. While this solution definitely has its flaws (atm there is no check if the user's input was correct, if the macro is inside a class-definition of if the class is actually derived from QObject), it serves as a starting point. And it's kinda fun :)

This "dumb" method is needed for the run-off-the-mill cling (SVN trunk). I am working on a patch to (hopefully soon) be included in cling that will allow me to install an ASTConsumer and a preprocessor-callback. The ASTConsumer allows me to monitor if a subclass of QObject was defined and the preprocessor-callback allows me to monitor if the Q_OBJECT macro was expanded. If both conditions are met, moc will be invoked. This will certainly be the correct way to go, until then the dumbed-down string-matching version will do its job... kinda... :)
Oh, almost forgot to add a screenshot:



Cheers, Thomas

Dienstag, 10. Juli 2012

Multi-line input

Qling has gotten a new feature and while it's nothing too fancy, I think it deserves a blog entry since it kinda touches an interesting detail about cling.

The feature is: multi-line input. Using the conventional line-by-line approach, there were several uncomfortable issues with entering longer chunks of code, like a class definition. It was possible to do the following:
struct Struct {     //press enter
  int m_i;          //press enter
  Struct():m_i(0){} //press enter
};                  //press enter
After pressing enter after the first line, cling notices that the input was not complete and waits for you to enter more code until the declaration is complete.

Problem: If you notice a typo in a line that has already been submitted, you have no way to correct it and need to finish the declaration, have clang issue an error and re-type the whole code - this time without typo (which always works as expected, as we all know ;) ).
But let's just cope with that.
(Edit: This statement is not correct, you can enter ".@" to cancel input)

So entering multiple lines has always been possible, cling will notice if my input is complete or not, right? So one might assume that the following works:
Assume "inst" is an instance of a class (let's call it Struct again) implementing the named parameter idiom and your intent is to write sth like:
inst.setA(1).setB(5).setC("foo");
And you'd assume that it also works this way:
inst.setA(1)      //press enter
  .setB(5)        //press enter
  .setC("foo");   //press enter
...as would be legal C++. Well, not quite.
The problem: Cling has a nice feature. If you enter a statement that has no trailing semicolon, cling will notice that, add the semicolon and print the value of the expression if it is or returns a value.
So this:
functionReturningIntOfValueFive()  //note: no semicolon
will print:
(int) 5
Thus, after entering the first line in our "inst"-example above will print:
(struct Struct) @0x7fbd13380024
because Struct::setA() returns a reference to itself. And qling chokes on the lines after that one.

Multi-line input to the rescue:

The code-input is not a simple QLineEdit anymore, it is now a QTextEdit with no vertical scrollbar that adjusts its height to fit the text. So you can now enter a whole chunk of code and navigate and edit the (yet unsubmitted) code as you would expect from a proper text-edit. Only after pressing Ctrl+Enter, the code will be submitted.
Note: since the arrow keys are now needed for navigating in the text, you need to press Ctrl+KeyUp and Ctrl+KeyDown to move in the history.
So, I can just paste whole source-files in the code-edit and be happy?
...well, not quite. There is another point worth mentioning:

Preprocessor directives such as #include or #define need to be submitted separately from simple statements such as function calls. So in a nutshell if you enter the following:
#define HULA
#ifdef HULA
#define BLUBB 1
#endif
#include <iostream>
std::cout<<"blubb: "<<BLUBB<<std::endl;
the input is split in two chunks: the first 5 lines containing the preprocessor directives and the last line. These two chunks are interpreted separately. That's fine and works, the output is "blubb: 1" as one would expect.
Whereas the following fails:
#ifdef HULA
struct MaybeHula{void foo(){std::cout<<"Hula defined\n";}};
#else
struct MaybeHula{void foo(){std::cout<<"Hula NOT defined\n";}};
#endif
The nitty-gritty details about why this fails will be explained in the next blog-post, this one is getting a little long...

Montag, 9. Juli 2012

Meet qling

I just published my first own OSS project called qling. (yay)

It is a simple Qt interface for cling, a C++ interpreter based on clang.

Interpreted C++ offers the possibility for the user to fiddle with the program using C/C++ - so "scripting" an app with C++ is possible - for whatever reason you'd like to use that. For example CERN's ROOT system uses a C++ interpreter (currently CINT, to be replaced by cling) to "handle and analyze large amounts of data in a very efficient way" - yes, also for finding the Higgs Boson ;)
I see it as a great way to teach C++ (trying stuff, fiddling with C++ without the compile/link cycle and the need to cope tool-chain technicalities for simple examples) and - coupled with the Qt interface - a great way to make first steps with Qt.

Of course, here's the obligatory screenshot:

Check it out at https://github.com/cptG/qling - feedback is welcome!
It's at a very early stage, there are lots of ideas waiting to be implemented.

Have fun,

Thomas