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 をパースする必要がある際には、今回作成したサンプルコードを元に色々改造していただければと思います。