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.