KotlinでApexを記述できるAltApexというのを作っています。
本記事ではAltApexを作った背景や使い方、現状の機能をざっと説明します。
背景
現在、Salesforceのサーバーサイド言語としてはApexしか対応していません。 ApexはJavaに似た言語になっていますが、名前空間に対応していない、無名関数が無い、型の明示的な記述が必要など 書き味が悪く管理もしづらい言語仕様になっています。
AltApexとは
KotlinでApexを記述できるようにするトランスパイラです(JavaScriptに対するTypeScript的な)
- ANTLRでKotlinのファイルをパースしてASTを生成
- ASTを辿ってApexファイルを出力
というように処理をして動いています。
インストール
今のところバイナリを配布していないのでgo getしてください。
$ go get -u github.com/tzmfreedom/alt-apex
使い方
Kotlinのファイルを指定すると標準出力にファイルの内容が出力されます
$ alt-apex {file}
対応状況
Kotlinの文法対応状況ですが、現時点では以下のファイルが通るようになっています。
package hoge.foo
class User(private val name: String) {
private var age:Int = 0
constructor(name:String, age:Int) : this(name) {
this.hoge.fuga.age = age
}
fun hoge() {
var i:Int = 0
if (i == 1) {
System.debug("hoge")
} else {
System.debug(true)
}
var hoge:String = if (i == 1) {
"hello"
} else {
"world"
}
for (number in numbers) {
System.debug(number)
}
while (i == 1) {
System.debug(1)
}
var i:Int = when (i) {
1 -> {
Hoge.fuga("hoge")
}
else -> {
Hoge.fuga("else")
}
}
val pr:PageReference = PageReference()
var pr:Database.Hoge = Database.Hoge()
var pr:Int = System.debug(123)
var pr:Database.Hoge.Fuga = Database.Hoge.Fuga()
var pr:Hoge = fuga()
val sum = { x: Int, y:Int -> x + y }
System.debug(sum(1, 2));
}
}
Apexにトランスパイルされるとこんな感じ
public class Hoge_Foo_User {
public User(String name) {
this.name = name;
}
Integer age = 0;
public User(String name, Integer age) {
this.hoge.fuga.age = age;
}
public hoge() {
Integer i = 0;
if (i == 1) {
System.debug('hoge');
} else {
System.debug(true);
}
String hoge;
if (i == 1) {
hoge = 'hello';
} else {
hoge = 'world';
}
for (number : numbers) {
System.debug(number);
}
while (i == 1) {
System.debug(1);
}
Integer i;
switch on i {
when 1 {
i = Hoge.hoge('hoge');
}
when else {
i = Hoge.fuga('else');
}
}
PageReference pr = new PageReference();
Database.Hoge pr = new Database.Hoge();
Integer pr = System.debug(123);
Database.Hoge.Fuga pr = new Database.Hoge.Fuga();
Hoge pr = fuga();
Lambda_0 sum = new Lambda_0();
System.debug(sum.run(1, 2));
}
class Lambda_0 {
public run(Integer x, Integer y) {
return x + y;
}
}
}
実はfor文だけ正しい構文ではないです。 Kotlinのfor文を実装するには型推論が必要なんですがまだ型推論は未実装なので…。
対応予定
- 型推論
- 現状は型を明示的に指定
- for文など型推論が前提となっている文法も今のところ未実装
- 名前空間対応
- クラス名だけ疑似名前空間になっていますが呼び出しで変換をかけていないので動かないです
- SOQL
- 実装するとKotlin互換ではなくなりますが、まぁ許容範囲かな…
- var/val対応
- 出力内容の適切なインデント
所感
トランスパイルして開発する場合は、基本的にApexファイルを編集するのではなくローカルのKotlinで編集・管理することになります。 よって、トランスパイラの精度はそれなりに要求されることになりますが、現状では精度が低いので実用には向きません。 (趣味的に開発を続けて精度は上げていく予定です)
ただ、技術的に今風な言語でApexを動かせる可能性がありそうというのはわかったのは面白いですねー。 ソースファイルはKotlinなのでローカルKotlinをうまく動かせるように調整することで、Apexを介さずにApexをローカル環境で実行することも実現できるかもしれません。