UWSCRの開発状況について

# リリーススケジュールについて

## 0.15.0

2023年内リリースの予定でしたが間に合わなさそうです。すいません。Language Serverが思ってた以上にむずかしかった…

- Language Serverを最低限実装
    - [x] Diagnostics
    - [ ] Completion
    - [ ] Semantic Tokens
- VSCode拡張機能
    - [ ] Language Client
    - [ ] tmLanguage → Semantic Tokensあれば不要？
    - [ ] language configuration

あたりが終わればリリースします。24年1月予定。

## 0.16.0

**操作記録**を実装する予定です。

- 高レベル記録
- ブラウザ操作

:::note info
操作記録がここまで後回しにされた理由は、これが個人的には不要だと思っていた機能でそもそも実装予定がなかったからです。記録機能に関してはUWSCを使ってもらえばいいんじゃないの？という気持ちもありました。なんですが、当時とは認識も変わってきてまして実装を決意しました。なるべく使いやすい形で提供できたらいいなと思っています。
:::


それと、未実装のまま放置されてる`OPTION`設定をどうにかしていきます。

24年2月予定です。

## 1.0.0

0.16.0のあとはいよいよ正式リリース版となります。
バグフィックスや細かな不足機能の追加などをやります。やれそうならLanguage Serverの拡張及びDebugger対応も。
それと、Microsoft Storeでのリリースができそうならやりたいですね。

24年3月に…出します！ここはもう絶対でやっていきます。

# 開発で大変だったこと

ついでに開発の思い出とかを。

## 全体的に大変

UWSCはとにかく機能が多すぎる上に単一の関数でアプリケーションひとつ作れるくらいのボリュームがあったりするんですね。機能ごとに必要になる知識がぜんぜん違うし、その都度学習も必要になります。umiumiさんまじパネェなって何度思ったか知れない。

## Win32 API

大体の機能がまぁ、Win32との睨み合いとなります。幸い[windows-rs](https://github.com/microsoft/windows-rs)があったのでそれなりにRustの流儀でできるようになってたのは助かりました。とはいえ`unsafe`まみれですし、関数によっては未だに生ポインタを扱う必要があってなかなかしんどい部分も多いのですが。正直どこでメモリリークしてるかわかったもんじゃないのでそこは怖いですね。

## COM

つらかったわーCOM。

### VARIANT

UWSCですとね、あれDelphiで出来てたんですけどDelphiってなんかVARIANTがわりとそのまま使えるっぽい？んですよね。んでUWSCって値をVARIANTで持ってて、値の比較とかVARIANTのそれなんですよね。
UWSCRは最初はVARIANTなんて考慮せず開発が始まってたので、UWSCRの型⇔VARIANTの相互変換とかものすごくがんばりました。しかしその、値の比較とかはUWSCのを再現しきれてないです。
そしてUWSCRではもうVARIANTは外にはほぼ出てきません。ユーザーはVARIANTを意識する必要はありません！

:::note info
一応VARIANT型の値という形では存在していて、どうしても特定の型のVARIANTが必要な場合に`vartype()`の型変換を使うと任意のVARIANTが得られるようにはなっています。
:::


同じようにSAFEARRAYも配列と相互変換されるようになっています。

### メソッドやプロパティの呼び出し

よくもまぁここまでわけわからん仕組みにしてくれたもんだな、というのが率直な感想でした。
UWSCだと

```php
excel.quit
```

みたいな感じで引数を取らないメソッドは`()`なしでもなぜか動作してたんですけどこれはプロパティ取得とメソッド実行両方のフラグを立ててメンバの呼び出しをするという実装をするからです。

:::note info
UWSCRでは`()`なしの場合はメソッドとして扱わないようになっているので上記はエラーになります。UWSCでも`()`をつけないメソッド呼び出しに起因する想定外の動作があったので、ここは厳しくしました。
:::

```php
foo = collection.items("foo")
foo = collection.items["foo"]
```

のようにパラメータ付きプロパティが`()`でも`[]`でも動作するのは、やってると自然とそうなる感じでしたね。

### WMIのメソッド

WMIのオブジェクトで`ISWbemObject`と`ISWbemObjectEx`てのがあるんですけど、こいつのメソッド呼び出しがとても面倒なので面倒じゃなくなるようにしました。これも裏でいろいろがんばっていますがおかげで`.メソッド()`で呼び出せるようになっています。

:::note info
`Methods_()`でメソッドを得て`InParameters().SpawnInstance_()`で引数作って`ExecMethod_`に渡して…というのを中でこっそりやっています。
:::

### イベント処理

イベント処理はうまくいきませんでした。これは実装が悪いのかwindows-rs側に不都合があるのか、原因がよくわかりません。とはいえIE以外で`oleevent`が使われることあるか？というと通常はなさそうなのでまぁひとまず平気かしら…とはいえ僕自身過去に[こんなの](https://stuncloud.wordpress.com/2018/04/06/uwsc_com_notifyicon/)を書いているので早いとこなんとかしたいです。

## def_dll

要は動的にdllをロードして関数を呼びたいという話なんですけど最初まじでなにしていいのかすらわかりませんでした。`libffi`でできそう！というのをなにかで見つけて藁をもすがる思いでやったらなんとか出来た。とはいえ一度大改修をする必要に迫られるくらいには難儀しています。ちなみに[libffi::middle](https://docs.rs/libffi/latest/libffi/middle/index.html)を使えばやりたいことは実現できました。なんとコールバックにも対応できました。コールバックが動いたときの感動たるや。
ここはとにかく生ポインタとの戦いなので、うっかりすると引数は正しく渡らないわヒープぶっ壊れるわその他なんやかんや起きるけどデバッグつらいわでつらかったのがつらかったです。

### 構造体

Cっぽい構造体作ってdll関数に渡したいというのがあったのでそこもがんばりました。最初はてきとーにやってましたけど[これ](https://learn.microsoft.com/ja-jp/cpp/c-language/padding-and-alignment-of-structure-members?view=msvc-170)読んでちゃんとパディングしたりとかしています。計算間違いが何度も発生しててバグもやたらと出していました。出来上がった構造体のサイズがおかしかったら計算ミスによるバグです。さすがにもう大丈夫だと思いたいけど自信がない。
はからずもコールバックのLPARAMに使えたのは良かったです。

## ACC, UIA

Accesibility ControlとUI Automationによるウィンドウ操作等の実装もかなり大変でした。UWSCの動作を完全に再現しきれていない部分があります。このへんも一度作り直したんだっけな。UWSCの実装がどうなっているかが見えなさすぎて苦戦しました。まぁここに限らずUWSCがどのように実装してるかわからないとこは無限にあったんですが…

## ブラウザ操作

webdriverにはもう懲りたので`Chrome Devtools Protocol`でやり始めたら結果としてとても良かったです。当初は`NodeId`ベースでやっていましたがこれだとどうしても表にDOMのオブジェクトを持ってくるというのが出来なかったので、`Runtime.evaluate`と`Runtime.callFunctionOn`を使って`Runtime.RemoteObject`を得る方針に変更しました。これによりさもDOMを直接触っているかのようにスクリプトを記述できるようになりました。
`Chrome Devtools Protocol`はwebsocketを使いますが、これには[tungstenite-rs](https://github.com/snapview/tungstenite-rs)を使っています。すごく簡単でよかった。

## Language Server/Client

今まさにやってるやつです。[tower-lsp](https://github.com/ebkalderon/tower-lsp/tree/master)というLanguage Serverを作るためのcrateがあって助かりました。とはいえ最初はInitialize時にServer側の機能をClientに通知してやる必要があるということに気づかず、何も動かなくて途方にくれました。

ClientもVSCode拡張機能を並行して開発しているのですが、それも`vscode-languageclient`を使うことで難なく実装できる…んですけどどこまで何をやってくれているか？が全然わからなくて思うように動かない原因がServerの実装なのかClientの実装なのかすらわからないという日々が続き自分の無能を呪いました。

今は仕組みが飲み込めて来たのでどうにかServerの実装を進めていますが、Clientに渡す情報を作る仕組みがやはり必要で、機能ごとにどう実装していくか？を今やっているところです。

Diagnosticはparserの解析結果が使えそうだったのですが、いくらか不足している情報があったり、そもそもparserの解析エラーの出し方が雑すぎたこともありparserにかなり手を入れました。おかげで解析エラーそのものもすっきりし情報もそこそこ正確になっています。(もっとわかりやすくしたほうが良さそうな気がしないでもないですがひとまずリリース優先でDiagnosticについてはここまでにしてます)

あとは

- lexerの軸解析結果を元にSemantic Tokens (エディタ上の装飾) の実装
- Evaluatorとは異なる構文木の評価機構を作ってCompletion (入力補完) の実装
    - 関数・定数・引数
        - 組み込み
        - ユーザー定義

を作ります。Completionは後々拡張して組み込みオブジェクトのメソッドやプロパティの補完にも対応していきたいです。(型推論器の実装が必要になりそう)

# 最後に

すでに3年以上をUWSCRの開発に費やしていて、いい加減に区切りをつけなければという焦りもありましたがどうにか、どうにか来年の第一四半期にはバージョン1.0をリリースできそうです。というかする！します！
もちろん1.0リリースで開発が終わりというわけではなく、追加で実装したい機能もありますし未発見のバグも数多でしょうからその対応もやります。が、さすがにそろそろ可能な範囲でなにかしら金銭を得る活動をしていかなくてはいけないですし、更新ペースは落ちていくと思います (今でもさほど早くはないんですが…)。
CAMPFIREで支援して下さった方々にも何かしらのお礼ができたらいいなと考えてます。

あ、あと来年もUWSCRアドベントカレンダーできたらいいですね。
それでは良いお年を！