A long time ago, I joked about Raptor mode for Lancelot. The idea was plausable thanks to a tool I started developing to make the Lancelot development easier. It was PUCK - the Plasma UI Compiler (as named by Danny Allen). It generated C++ code from the XML-based UI definition.
After a while, I stopped working on PUCK since Lancelot’s UI stopped changing that much. I even removed it from the build system.
Now with QML, the need for a tool like that disappeared.
One thing that I do not like when QML is concerned is its use of JavaScript.
An alternative
An idea I got some time ago is to create a simple format that compiles to QML, that would allow the user to write code in any language that is compilable to JavaScript. I decided to base the format on YAML (since every language I know of has a parser for it, and it is not XML :) ).
YAML has its limitations, and some of them are making it a bit problematic for this use-case, but all in all I think this can work.
PUCK - the new one
Since the old PUCK haven’t been used for a long time, and the new project is kinda related, I decided to reuse the old name.
To cut a long story short, I’ll just post an example of what the current syntax looks like. I’ll write more details later (along with a small manual), when the syntax becomes stable enough. I’m still planning to make a few small changes that will make PUCK a desirable alternative to QML not only for the ability to replace JavaScript.
This is an example reimplementing the first part of samegame.qml from the Qt5 demos (I’m overly lazy to actually reimplement the whole example).
imports:
- QtQuick 2.0
- QtQuick.Particles 2.0
- ^content/samegame.js as Logic
- ^content
Rectangle:
id: root
width: Settings.screenWidth
height: Settings.screenHeight
properties:
- int acc: 0
functions:
loadPuzzle: |
@coffee
Logic.cleanUp() if game.mode != ""
Logic.startNewGame(gameCanvas, "puzzle",
"levels/level" + acc + ".qml")
nextPuzzle: |
@lang=livescript;global=acc
acc = (acc + 1) % 10
loadPuzzle()
children:
- Timer:
id: gameOverTimer
interval: 1500
running : gameCanvas.gameOver && gameCanvas.mode == "puzzle"
repeat : false
onTriggered: |
@coffee
Logic.cleanUp()
nextPuzzle()
- Image:
source: ^content/gfx/background.png
anchors.fill: parent
Error reporting
One of the great things about the compilation to QML is that you’ll get script errors during the build of your project and not at the runtime.
The compilation errors get reported to the console output along with the code that failed, but also inside the resulting QML as well.
Console output of a failed CoffeeScript function:
Error: Compilation failed
Source:
1 function === without arguments
2
Error message:
[stdin]:1:1: error: reserved word 'function'
function === without arguments
^^^^^^^^
Insides of the QML file:
function error_coffee_function() /*
[stdin]:1:1: error: reserved word 'function'
function === without arguments
^^^^^^^^
*/
Supported languages
Currently, CoffeeScript, LiveScript and (obviously) JavaScript are supported, but this can be extended in the future. I will probably add the support for linters and minifiers in the near future.