QML のパーサーの作り方
はじめに
大規模な Qt Quick のアプリケーションの開発時などに、QML ファイルの何かをチェックしたり、一括で処理をするようなツールが欲しくなることがあります。
その作業を正確に行うには、QML のパースが必要となりますが、ゼロから書く気にはなりませんよね。
当然ですが、QtQml モジュールには QML のパーサーが実装されているため、これを使ってパースをしてみましょう。
.pro
TEAMPLATE = app QT = qml-private CONFIG += cmdline SOURCES = main.cpp
シンプルですね。
QtQml モジュールの内部クラスを利用するため、 QT に qml-private を指定しています。
CONFIG += cmdline は、Qt 5.12.2 あたりで追加された cmdline.prf を有効にするせっていです。
main.cpp
QML のパースは、qtdeclarative/src/qml/parser/ 以下で実装されている機能を使います。
- QQmlJS::Engine のインスタンスを生成
- QQmlJS::Lexer のインスタンスを生成
- QQmlJS::Lexer::setCode でパースする QML の内容をセット
- qqmljs.g という文法ファイルを元に Qt のコンパイル時に生成される、QQmlJS::Parser のインスタンスを生成
- QQmlJS::Parser::parse() が成功すると、QQmlJS::Parser::ast() より QML の 抽象構文木 が取得できるようになります。
- QQmlJS::Visitor のサブクラスを生成し、その AST を走査します。
これらを実装したものを https://github.com/task-jp/qmlanalyzer に置いておきましたので、興味のある方はご覧ください。
実行
デフォルトでは、ソースコード内に含まれている以下の QML のコードを解析します。
QString source("import QtQuick 2.0\nItem { id: root }");
$ ./qmlanalyzer
+ UiProgram + UiHeaderItemList + UiImport "import" + UiQualifiedId "QtQuick" - UiQualifiedId "2.0" - UiImport - UiHeaderItemList + UiObjectMemberList + UiObjectDefinition + UiQualifiedId "Item" - UiQualifiedId + UiObjectInitializer "{" + UiObjectMemberList + UiScriptBinding + UiQualifiedId "id" - UiQualifiedId ":" + ExpressionStatement + IdentifierExpression "root" - IdentifierExpression - ExpressionStatement - UiScriptBinding - UiObjectMemberList "}" - UiObjectInitializer - UiObjectDefinition - UiObjectMemberList - UiProgram
引数に qml ファイルを渡すことで、その qml を解析できるようになっていますので、色々試して挙動を確認していただければと思います。
終わりに
QtQml 内部の機能を利用し、QML のパースと走査をしてみました。
これを発展させることで、import 文のチェックや、高度な置換、QML の分析などが可能になります。
QML をパースする必要がある際には、今回作成したサンプルコードを元に色々改造していただければと思います。