2019-06-06

KotlinでApexを記述できるAltApexを作っている話

KotlinでApexを記述できるAltApexというのを作っています。

本記事ではAltApexを作った背景や使い方、現状の機能をざっと説明します。

背景

現在、Salesforceのサーバーサイド言語としてはApexしか対応していません。 ApexはJavaに似た言語になっていますが、名前空間に対応していない、無名関数が無い、型の明示的な記述が必要など 書き味が悪く管理もしづらい言語仕様になっています。

AltApexとは

KotlinでApexを記述できるようにするトランスパイラです(JavaScriptに対するTypeScript的な)

  1. ANTLRでKotlinのファイルをパースしてASTを生成
  2. 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文を実装するには型推論が必要なんですがまだ型推論は未実装なので…。

対応予定

所感

トランスパイルして開発する場合は、基本的にApexファイルを編集するのではなくローカルのKotlinで編集・管理することになります。 よって、トランスパイラの精度はそれなりに要求されることになりますが、現状では精度が低いので実用には向きません。 (趣味的に開発を続けて精度は上げていく予定です)

ただ、技術的に今風な言語でApexを動かせる可能性がありそうというのはわかったのは面白いですねー。 ソースファイルはKotlinなのでローカルKotlinをうまく動かせるように調整することで、Apexを介さずにApexをローカル環境で実行することも実現できるかもしれません。

このエントリーをはてなブックマークに追加