Open15

Alt Dartを作りたい

菊池紘菊池紘

思い返すと2018年からKotlinでFlutterをやりたい、と言っている
KotlinでFlutterを書きたい

2020年も終わりという時期になってきてDartも改善が進んではいるが、まだ書いていてめちゃめちゃ楽しい言語かと言うとそういう訳でもない。

  • ユニオン型が無い(freezed使えば似たようなことは可能)
  • Class Delegationみたいな仕組みがない
  • Data Class (Case Class) 記法が無い(freezed使えば似たようなことは可能)
  • ifやtry-catchが式ではない
  • パターンマッチ構文がない
  • @override が必須ではない(analysis_optionで検出は可能)
  • ListやMapのImmutableとMutableの型レベルでの区別がない
  • 値を持ったenumを作る構文がない

一方でDartを長く使うことで、Kotlinに対しても要望があったりなかったり

  • 実行スレッドを気にしないで良い実行環境になると楽(CoroutineだとDispatcherがどこのスレッドなのかを気にしたりとかしないといけない)
  • 名前付きコンストラクタがあると良い
  • enumにだけセミコロンが必要なアンバランス感
  • Hot reloadできるような素早い再実行ができると良い

というわけで、Javaに対するKotlinのように、Dartの代替言語を作れたら良いのでは?
という方向に最近は考えがシフトしてきつつある。

菊池紘菊池紘

基本的な方針としては

  • Dart VM上で動作する
  • Dartの資産をシームレスに使用できる

という方向でなにか作れたら素敵。

ただし私自身に言語作成の経験が殆どないので、

  1. Dart VMで動く言語用のコンパイラに必要な要素はなにか検討する
  2. どんな文法が理想的なのか検討する
  3. その実装に必要な要素を検討する(型推論の方法とかとか)

ということを順々に調べながらやっていくことになりそう。
何年かかるやら。その間にDart本体がもっと良い言語になっていると嬉しい。

菊池紘菊池紘

Dart VMはDart Kernelという中間表現を持っている、らしい。
Kernel Documentation

dartコマンドのヘルプを見ると、 $ dart --snapshot=hoge.dill hoge.dart というコマンドを打つとsnapshotをDart Kernelバイナリ表現でファイルに落とすことができるとある。
(実際にそれっぽいバイナリファイルが出てくる)

Dart SDKリポジトリにkernelを取り扱うためのpackageがあって、どうやらこれを使えばDart Kernelファイルをパースできるらしい。
中身を見てみたいけれど、DartのバージョンによってDart Kernelのバージョンも違うらしく、まだ手元では適切なバージョンのpkg/kernelを使って中身を見ることができていない。

Dart KernelというのはDart VMの中間表現、Javaで言うところのclassファイルに相当するものなのでは、というのが今の自分の理解。
ということで、独自言語 -> Dart Kernelの変換が(コンパイルが)できれば目的は達成できそうな気がする。
(ホントか?)

菊池紘菊池紘

まずは単純な言語をDart Kernelに落とす方法を考えたい。

例としてはBrainFuck言語(名前がお下品なので以下BF)を動かせれば良さそう。

  1. DartでBFのインタープリターを作る(期待したパースができているかとか確かめるためにも)
  2. BF -> Dartソースコード の変換をするプログラムを作る(吐いたものをDart Kernel化すれば、まずはどんな構造のDart Kernelファイルを作ればよいのかわかると思う)
  3. BF -> Dart Kernelコンパイラを作る

こんな順番でできればいいかな。
BFができたらLisp的な比較的シンプルめな文法の言語にトライしても良いのかもしれない(ただしLispは全然触ったこと無いので簡単にかじっておくとかはしておきたい)

菊池紘菊池紘

BF -> Dartトランスパイラは作った。

https://github.com/kikuchy/bf_dart/blob/transpiler/lib/transpiler.dart

生成されたDartのソースコードはこんなかんじ
https://github.com/kikuchy/bf_dart/blob/main/generated_example/helloworld.dart

あとはDartのソースコードの代わりにDartKernelを吐けば良い?
Snapshotは dart:io の依存も解決した形で作られるなら、依存解決の仕組みも必要なのでは?
とりあえずはpkg/kernelを使えるように調整してから。

菊池紘菊池紘

一番簡単な形のDartKernelを読み込んでパースすることには成功した。

こんな感じの単純なDartソース

void main() {
  print('Hello world');
}

$ dart --snapshot=hello.dill hello.dart でDart Kernelを出力。出てきたdillファイルを以下のコードで出力すると、

import 'package:kernel/kernel.dart';

void main(List<String> arguments) {
  final component = loadComponentFromBinary('hello.dill');
  writeComponentToText(component);
}

こんなふうに中身が出力される。

main = hel::main;
library from "file:///Users/kikuchy/dev/dart/kernel_test/bin/hello.dart" as hel {

  static method main() → void {
    core::print("Hello world");
  }
}

問題のpkg/kernelは、自分が使っているDart SDKのバージョンに合わせたものをチェックアウトしてきて、 path 経由でpubspec.yamlに記述すれば使える。

dependencies:
  kernel:
    path: '../sdk/pkg/kernel'
菊池紘菊池紘

pkg/kernelを使って、元となるソースコードが無い状態からdillを作る方法はわかった。

  final sourceLibUri = Uri.file('/not/existing/path');
  final mainMethod = Procedure(
        Name('main'),
        ProcedureKind.Method,
        FunctionNode(
          Block([
            ExpressionStatement(
              StaticInvocation.byReference(
                CanonicalName.root()
                    .getChild('dart:core')
                    .getChild('@methods')
                    .getChild('print')
                    .getReference(),
                Arguments([StringLiteral(('Hello World'))]),
              ),
            ),
          ]),
          returnType: VoidType(),
        ),
        isStatic: true,
        fileUri: sourceLibUri,
      );
  final c = Component(nameRoot: CanonicalName.root(), uriToSource: {}, libraries: [
    Library(sourceLibUri, fileUri: sourceLibUri, procedures: [
      mainMethod,
    ]),
  ])
    ..setMainMethodAndMode(
      mainMethod.reference,
      true,
      NonNullableByDefaultCompiledMode.Disabled,
    );
  writeComponentToBinary(c, 'hello_manual.dill');

これは以下のコードを再現したもの

void main() {
  print('Hello World');
}

生成した hello_manual.dill を実行すると以下のようになる。

$ dart hello_manual.dill
Hello World

感覚としてはcode_builder と似ている気はする。
ファイルに書き出せるのはComponentのみのようなので、とりあえずはComponentという形にライブラリやメソッドを詰め込んでいけば良さそうではある。

まだBFからDartにトランスパイルしたコードから生成したdillファイルは確認していないので中身を見てみる。
dart:ioの依存を解決した状態のDartKernelを出さないと行けないとしたら、依存解決はどう行えば良いのか、Dartの本体を見に行く必要がありそう。

菊池紘菊池紘

特に依存解決はしていなかったので、愚直にpkg/kernelで吐き出し作業をやれば行けそうな気はする。
ランタイム部分のクラスやメソッドをkernelで書き直すのが大変。
どうにか既存のDartKernelからコピーしてくる方法はないものか。
(単純にインスタンスをそのまま使おうとするとimportUriが元ファイルのものになっていて、出力時に新しいReferenceにbindできないとか言ってコケる。一部だけreference.canonicalNameをnullに起き直してやろうとしても、今度はcore::num::+とかのメソッドが解決できなくてコケる)

菊池紘菊池紘

書き方だとかの注意

  • privateなクラスメンバを作る際には必ずそのクラスが属しているLibraryへの参照が必要
  • なので、基本的にはトップレベルのものから作っていって、addHogehoge系メソッドでクラスやProcedureを足していく
    • Library
    • Class
    • Field
    • Procedure
菊池紘菊池紘

できた!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

とりあえず動けばいいやでアドホックにコードを分割したり足したりしてたので整理はできてないけれど、こんなコードで動作するDart Kernelファイルは作れました。

https://github.com/kikuchy/bf_dart/blob/compiler/lib/compiler.dart

出来上がったdillファイルを実行した結果とかはこんな感じ。

$ dart bin/bf_compiler.dart bf_sources/helloworld.bf generated_example/helloworld.dill
$ dart generated_example/helloworld.dill
Hello World!

以下、ちょっと工夫した点。
Transpilerを作った時点では _Tape という、BFが使用するメモリの確保と使用を抽象化するクラスを作っていたのですが、pkg/kernelでクラスを作るのが億劫だった(Dartコンパイラによって自動的に足されている不可視メソッドなどがそこそこあって、それらを手作業で作るのが大変だった)ので、以下のように予めメモリを確保しておき、そこから溢れたらエラーにする戦略に変更しました。

final memory = List.filled(2048, 0);

そんなにバカスカとメモリを食うわけでもないので、まあとりあえずこれで良いかなと。

生成したdillファイルのComponentをテキスト出力したのは以下の通り。
以下は長いので見たい方だけどうぞ。
なぜか dart:io をimportしているimport delectiveがnullになっているのは謎。でもちゃんと動いてる。謎。

generated_example/helloworld.dill
main = bf::main;
library from "file:///Users/kikuchy/dev/dart/bf_dart/bf_sources/helloworld.bf" as bf {

  import "null";

  static method /* from null */ getChar() → core::int* {
    final core::String* line = io::stdin.readLineSync();
    final core::int* code = line.codeUnitAt(0);
    return code;
  }
  static method /* from null */ putChar(core::int* charCode) → void {
    io::stdout.write(core::String::fromCharCode(charCode));
  }
  static method /* from null */ main() → void {
    final core::List<core::int*>* memory = core::_List::filled(2048, 0);
    final core::int* pointer = 0;
    pointer = pointer.+(1);
    let dynamic #t1 = memory in let dynamic #t2 = pointer in #t1.[]=(#t2, #t1.[](#t2).+(1));
    let dynamic #t3 = memory in let dynamic #t4 = pointer in #t3.[]=(#t4, #t3.[](#t4).+(1));
    let dynamic #t5 = memory in let dynamic #t6 = pointer in #t5.[]=(#t6, #t5.[](#t6).+(1));
    let dynamic #t7 = memory in let dynamic #t8 = pointer in #t7.[]=(#t8, #t7.[](#t8).+(1));
    let dynamic #t9 = memory in let dynamic #t10 = pointer in #t9.[]=(#t10, #t9.[](#t10).+(1));
    let dynamic #t11 = memory in let dynamic #t12 = pointer in #t11.[]=(#t12, #t11.[](#t12).+(1));
    let dynamic #t13 = memory in let dynamic #t14 = pointer in #t13.[]=(#t14, #t13.[](#t14).+(1));
    let dynamic #t15 = memory in let dynamic #t16 = pointer in #t15.[]=(#t16, #t15.[](#t16).+(1));
    let dynamic #t17 = memory in let dynamic #t18 = pointer in #t17.[]=(#t18, #t17.[](#t18).+(1));
    while (!memory.[](pointer).==(0)) {
      pointer = pointer.-(1);
      let dynamic #t19 = memory in let dynamic #t20 = pointer in #t19.[]=(#t20, #t19.[](#t20).+(1));
      let dynamic #t21 = memory in let dynamic #t22 = pointer in #t21.[]=(#t22, #t21.[](#t22).+(1));
      let dynamic #t23 = memory in let dynamic #t24 = pointer in #t23.[]=(#t24, #t23.[](#t24).+(1));
      let dynamic #t25 = memory in let dynamic #t26 = pointer in #t25.[]=(#t26, #t25.[](#t26).+(1));
      let dynamic #t27 = memory in let dynamic #t28 = pointer in #t27.[]=(#t28, #t27.[](#t28).+(1));
      let dynamic #t29 = memory in let dynamic #t30 = pointer in #t29.[]=(#t30, #t29.[](#t30).+(1));
      let dynamic #t31 = memory in let dynamic #t32 = pointer in #t31.[]=(#t32, #t31.[](#t32).+(1));
      let dynamic #t33 = memory in let dynamic #t34 = pointer in #t33.[]=(#t34, #t33.[](#t34).+(1));
      pointer = pointer.+(1);
      let dynamic #t35 = memory in let dynamic #t36 = pointer in #t35.[]=(#t36, #t35.[](#t36).-(1));
    }
    pointer = pointer.-(1);
    bf::putChar(memory.[](pointer));
    pointer = pointer.+(1);
    let dynamic #t37 = memory in let dynamic #t38 = pointer in #t37.[]=(#t38, #t37.[](#t38).+(1));
    let dynamic #t39 = memory in let dynamic #t40 = pointer in #t39.[]=(#t40, #t39.[](#t40).+(1));
    let dynamic #t41 = memory in let dynamic #t42 = pointer in #t41.[]=(#t42, #t41.[](#t42).+(1));
    let dynamic #t43 = memory in let dynamic #t44 = pointer in #t43.[]=(#t44, #t43.[](#t44).+(1));
    let dynamic #t45 = memory in let dynamic #t46 = pointer in #t45.[]=(#t46, #t45.[](#t46).+(1));
    let dynamic #t47 = memory in let dynamic #t48 = pointer in #t47.[]=(#t48, #t47.[](#t48).+(1));
    let dynamic #t49 = memory in let dynamic #t50 = pointer in #t49.[]=(#t50, #t49.[](#t50).+(1));
    while (!memory.[](pointer).==(0)) {
      pointer = pointer.-(1);
      let dynamic #t51 = memory in let dynamic #t52 = pointer in #t51.[]=(#t52, #t51.[](#t52).+(1));
      let dynamic #t53 = memory in let dynamic #t54 = pointer in #t53.[]=(#t54, #t53.[](#t54).+(1));
      let dynamic #t55 = memory in let dynamic #t56 = pointer in #t55.[]=(#t56, #t55.[](#t56).+(1));
      let dynamic #t57 = memory in let dynamic #t58 = pointer in #t57.[]=(#t58, #t57.[](#t58).+(1));
      pointer = pointer.+(1);
      let dynamic #t59 = memory in let dynamic #t60 = pointer in #t59.[]=(#t60, #t59.[](#t60).-(1));
    }
    pointer = pointer.-(1);
    let dynamic #t61 = memory in let dynamic #t62 = pointer in #t61.[]=(#t62, #t61.[](#t62).+(1));
    bf::putChar(memory.[](pointer));
    let dynamic #t63 = memory in let dynamic #t64 = pointer in #t63.[]=(#t64, #t63.[](#t64).+(1));
    let dynamic #t65 = memory in let dynamic #t66 = pointer in #t65.[]=(#t66, #t65.[](#t66).+(1));
    let dynamic #t67 = memory in let dynamic #t68 = pointer in #t67.[]=(#t68, #t67.[](#t68).+(1));
    let dynamic #t69 = memory in let dynamic #t70 = pointer in #t69.[]=(#t70, #t69.[](#t70).+(1));
    let dynamic #t71 = memory in let dynamic #t72 = pointer in #t71.[]=(#t72, #t71.[](#t72).+(1));
    let dynamic #t73 = memory in let dynamic #t74 = pointer in #t73.[]=(#t74, #t73.[](#t74).+(1));
    let dynamic #t75 = memory in let dynamic #t76 = pointer in #t75.[]=(#t76, #t75.[](#t76).+(1));
    bf::putChar(memory.[](pointer));
    bf::putChar(memory.[](pointer));
    let dynamic #t77 = memory in let dynamic #t78 = pointer in #t77.[]=(#t78, #t77.[](#t78).+(1));
    let dynamic #t79 = memory in let dynamic #t80 = pointer in #t79.[]=(#t80, #t79.[](#t80).+(1));
    let dynamic #t81 = memory in let dynamic #t82 = pointer in #t81.[]=(#t82, #t81.[](#t82).+(1));
    bf::putChar(memory.[](pointer));
    while (!memory.[](pointer).==(0)) {
      let dynamic #t83 = memory in let dynamic #t84 = pointer in #t83.[]=(#t84, #t83.[](#t84).-(1));
    }
    pointer = pointer.+(1);
    let dynamic #t85 = memory in let dynamic #t86 = pointer in #t85.[]=(#t86, #t85.[](#t86).+(1));
    let dynamic #t87 = memory in let dynamic #t88 = pointer in #t87.[]=(#t88, #t87.[](#t88).+(1));
    let dynamic #t89 = memory in let dynamic #t90 = pointer in #t89.[]=(#t90, #t89.[](#t90).+(1));
    let dynamic #t91 = memory in let dynamic #t92 = pointer in #t91.[]=(#t92, #t91.[](#t92).+(1));
    let dynamic #t93 = memory in let dynamic #t94 = pointer in #t93.[]=(#t94, #t93.[](#t94).+(1));
    let dynamic #t95 = memory in let dynamic #t96 = pointer in #t95.[]=(#t96, #t95.[](#t96).+(1));
    let dynamic #t97 = memory in let dynamic #t98 = pointer in #t97.[]=(#t98, #t97.[](#t98).+(1));
    let dynamic #t99 = memory in let dynamic #t100 = pointer in #t99.[]=(#t100, #t99.[](#t100).+(1));
    while (!memory.[](pointer).==(0)) {
      pointer = pointer.-(1);
      let dynamic #t101 = memory in let dynamic #t102 = pointer in #t101.[]=(#t102, #t101.[](#t102).+(1));
      let dynamic #t103 = memory in let dynamic #t104 = pointer in #t103.[]=(#t104, #t103.[](#t104).+(1));
      let dynamic #t105 = memory in let dynamic #t106 = pointer in #t105.[]=(#t106, #t105.[](#t106).+(1));
      let dynamic #t107 = memory in let dynamic #t108 = pointer in #t107.[]=(#t108, #t107.[](#t108).+(1));
      pointer = pointer.+(1);
      let dynamic #t109 = memory in let dynamic #t110 = pointer in #t109.[]=(#t110, #t109.[](#t110).-(1));
    }
    pointer = pointer.-(1);
    bf::putChar(memory.[](pointer));
    pointer = pointer.+(1);
    let dynamic #t111 = memory in let dynamic #t112 = pointer in #t111.[]=(#t112, #t111.[](#t112).+(1));
    let dynamic #t113 = memory in let dynamic #t114 = pointer in #t113.[]=(#t114, #t113.[](#t114).+(1));
    let dynamic #t115 = memory in let dynamic #t116 = pointer in #t115.[]=(#t116, #t115.[](#t116).+(1));
    let dynamic #t117 = memory in let dynamic #t118 = pointer in #t117.[]=(#t118, #t117.[](#t118).+(1));
    let dynamic #t119 = memory in let dynamic #t120 = pointer in #t119.[]=(#t120, #t119.[](#t120).+(1));
    let dynamic #t121 = memory in let dynamic #t122 = pointer in #t121.[]=(#t122, #t121.[](#t122).+(1));
    let dynamic #t123 = memory in let dynamic #t124 = pointer in #t123.[]=(#t124, #t123.[](#t124).+(1));
    let dynamic #t125 = memory in let dynamic #t126 = pointer in #t125.[]=(#t126, #t125.[](#t126).+(1));
    let dynamic #t127 = memory in let dynamic #t128 = pointer in #t127.[]=(#t128, #t127.[](#t128).+(1));
    let dynamic #t129 = memory in let dynamic #t130 = pointer in #t129.[]=(#t130, #t129.[](#t130).+(1));
    let dynamic #t131 = memory in let dynamic #t132 = pointer in #t131.[]=(#t132, #t131.[](#t132).+(1));
    while (!memory.[](pointer).==(0)) {
      pointer = pointer.-(1);
      let dynamic #t133 = memory in let dynamic #t134 = pointer in #t133.[]=(#t134, #t133.[](#t134).+(1));
      let dynamic #t135 = memory in let dynamic #t136 = pointer in #t135.[]=(#t136, #t135.[](#t136).+(1));
      let dynamic #t137 = memory in let dynamic #t138 = pointer in #t137.[]=(#t138, #t137.[](#t138).+(1));
      let dynamic #t139 = memory in let dynamic #t140 = pointer in #t139.[]=(#t140, #t139.[](#t140).+(1));
      let dynamic #t141 = memory in let dynamic #t142 = pointer in #t141.[]=(#t142, #t141.[](#t142).+(1));
      pointer = pointer.+(1);
      let dynamic #t143 = memory in let dynamic #t144 = pointer in #t143.[]=(#t144, #t143.[](#t144).-(1));
    }
    pointer = pointer.-(1);
    bf::putChar(memory.[](pointer));
    pointer = pointer.+(1);
    let dynamic #t145 = memory in let dynamic #t146 = pointer in #t145.[]=(#t146, #t145.[](#t146).+(1));
    let dynamic #t147 = memory in let dynamic #t148 = pointer in #t147.[]=(#t148, #t147.[](#t148).+(1));
    let dynamic #t149 = memory in let dynamic #t150 = pointer in #t149.[]=(#t150, #t149.[](#t150).+(1));
    let dynamic #t151 = memory in let dynamic #t152 = pointer in #t151.[]=(#t152, #t151.[](#t152).+(1));
    let dynamic #t153 = memory in let dynamic #t154 = pointer in #t153.[]=(#t154, #t153.[](#t154).+(1));
    let dynamic #t155 = memory in let dynamic #t156 = pointer in #t155.[]=(#t156, #t155.[](#t156).+(1));
    let dynamic #t157 = memory in let dynamic #t158 = pointer in #t157.[]=(#t158, #t157.[](#t158).+(1));
    let dynamic #t159 = memory in let dynamic #t160 = pointer in #t159.[]=(#t160, #t159.[](#t160).+(1));
    while (!memory.[](pointer).==(0)) {
      pointer = pointer.-(1);
      let dynamic #t161 = memory in let dynamic #t162 = pointer in #t161.[]=(#t162, #t161.[](#t162).+(1));
      let dynamic #t163 = memory in let dynamic #t164 = pointer in #t163.[]=(#t164, #t163.[](#t164).+(1));
      let dynamic #t165 = memory in let dynamic #t166 = pointer in #t165.[]=(#t166, #t165.[](#t166).+(1));
      pointer = pointer.+(1);
      let dynamic #t167 = memory in let dynamic #t168 = pointer in #t167.[]=(#t168, #t167.[](#t168).-(1));
    }
    pointer = pointer.-(1);
    bf::putChar(memory.[](pointer));
    let dynamic #t169 = memory in let dynamic #t170 = pointer in #t169.[]=(#t170, #t169.[](#t170).+(1));
    let dynamic #t171 = memory in let dynamic #t172 = pointer in #t171.[]=(#t172, #t171.[](#t172).+(1));
    let dynamic #t173 = memory in let dynamic #t174 = pointer in #t173.[]=(#t174, #t173.[](#t174).+(1));
    bf::putChar(memory.[](pointer));
    let dynamic #t175 = memory in let dynamic #t176 = pointer in #t175.[]=(#t176, #t175.[](#t176).-(1));
    let dynamic #t177 = memory in let dynamic #t178 = pointer in #t177.[]=(#t178, #t177.[](#t178).-(1));
    let dynamic #t179 = memory in let dynamic #t180 = pointer in #t179.[]=(#t180, #t179.[](#t180).-(1));
    let dynamic #t181 = memory in let dynamic #t182 = pointer in #t181.[]=(#t182, #t181.[](#t182).-(1));
    let dynamic #t183 = memory in let dynamic #t184 = pointer in #t183.[]=(#t184, #t183.[](#t184).-(1));
    let dynamic #t185 = memory in let dynamic #t186 = pointer in #t185.[]=(#t186, #t185.[](#t186).-(1));
    bf::putChar(memory.[](pointer));
    let dynamic #t187 = memory in let dynamic #t188 = pointer in #t187.[]=(#t188, #t187.[](#t188).-(1));
    let dynamic #t189 = memory in let dynamic #t190 = pointer in #t189.[]=(#t190, #t189.[](#t190).-(1));
    let dynamic #t191 = memory in let dynamic #t192 = pointer in #t191.[]=(#t192, #t191.[](#t192).-(1));
    let dynamic #t193 = memory in let dynamic #t194 = pointer in #t193.[]=(#t194, #t193.[](#t194).-(1));
    let dynamic #t195 = memory in let dynamic #t196 = pointer in #t195.[]=(#t196, #t195.[](#t196).-(1));
    let dynamic #t197 = memory in let dynamic #t198 = pointer in #t197.[]=(#t198, #t197.[](#t198).-(1));
    let dynamic #t199 = memory in let dynamic #t200 = pointer in #t199.[]=(#t200, #t199.[](#t200).-(1));
    let dynamic #t201 = memory in let dynamic #t202 = pointer in #t201.[]=(#t202, #t201.[](#t202).-(1));
    bf::putChar(memory.[](pointer));
    while (!memory.[](pointer).==(0)) {
      let dynamic #t203 = memory in let dynamic #t204 = pointer in #t203.[]=(#t204, #t203.[](#t204).-(1));
    }
    pointer = pointer.+(1);
    let dynamic #t205 = memory in let dynamic #t206 = pointer in #t205.[]=(#t206, #t205.[](#t206).+(1));
    let dynamic #t207 = memory in let dynamic #t208 = pointer in #t207.[]=(#t208, #t207.[](#t208).+(1));
    let dynamic #t209 = memory in let dynamic #t210 = pointer in #t209.[]=(#t210, #t209.[](#t210).+(1));
    let dynamic #t211 = memory in let dynamic #t212 = pointer in #t211.[]=(#t212, #t211.[](#t212).+(1));
    let dynamic #t213 = memory in let dynamic #t214 = pointer in #t213.[]=(#t214, #t213.[](#t214).+(1));
    let dynamic #t215 = memory in let dynamic #t216 = pointer in #t215.[]=(#t216, #t215.[](#t216).+(1));
    let dynamic #t217 = memory in let dynamic #t218 = pointer in #t217.[]=(#t218, #t217.[](#t218).+(1));
    let dynamic #t219 = memory in let dynamic #t220 = pointer in #t219.[]=(#t220, #t219.[](#t220).+(1));
    while (!memory.[](pointer).==(0)) {
      pointer = pointer.-(1);
      let dynamic #t221 = memory in let dynamic #t222 = pointer in #t221.[]=(#t222, #t221.[](#t222).+(1));
      let dynamic #t223 = memory in let dynamic #t224 = pointer in #t223.[]=(#t224, #t223.[](#t224).+(1));
      let dynamic #t225 = memory in let dynamic #t226 = pointer in #t225.[]=(#t226, #t225.[](#t226).+(1));
      let dynamic #t227 = memory in let dynamic #t228 = pointer in #t227.[]=(#t228, #t227.[](#t228).+(1));
      pointer = pointer.+(1);
      let dynamic #t229 = memory in let dynamic #t230 = pointer in #t229.[]=(#t230, #t229.[](#t230).-(1));
    }
    pointer = pointer.-(1);
    let dynamic #t231 = memory in let dynamic #t232 = pointer in #t231.[]=(#t232, #t231.[](#t232).+(1));
    bf::putChar(memory.[](pointer));
    while (!memory.[](pointer).==(0)) {
      let dynamic #t233 = memory in let dynamic #t234 = pointer in #t233.[]=(#t234, #t233.[](#t234).-(1));
    }
    let dynamic #t235 = memory in let dynamic #t236 = pointer in #t235.[]=(#t236, #t235.[](#t236).+(1));
    let dynamic #t237 = memory in let dynamic #t238 = pointer in #t237.[]=(#t238, #t237.[](#t238).+(1));
    let dynamic #t239 = memory in let dynamic #t240 = pointer in #t239.[]=(#t240, #t239.[](#t240).+(1));
    let dynamic #t241 = memory in let dynamic #t242 = pointer in #t241.[]=(#t242, #t241.[](#t242).+(1));
    let dynamic #t243 = memory in let dynamic #t244 = pointer in #t243.[]=(#t244, #t243.[](#t244).+(1));
    let dynamic #t245 = memory in let dynamic #t246 = pointer in #t245.[]=(#t246, #t245.[](#t246).+(1));
    let dynamic #t247 = memory in let dynamic #t248 = pointer in #t247.[]=(#t248, #t247.[](#t248).+(1));
    let dynamic #t249 = memory in let dynamic #t250 = pointer in #t249.[]=(#t250, #t249.[](#t250).+(1));
    let dynamic #t251 = memory in let dynamic #t252 = pointer in #t251.[]=(#t252, #t251.[](#t252).+(1));
    let dynamic #t253 = memory in let dynamic #t254 = pointer in #t253.[]=(#t254, #t253.[](#t254).+(1));
    bf::putChar(memory.[](pointer));
  }
}

これでBFをDart VMの上で直に動くようにすることができました!

今度はLispもどきが動くようにしたい。いつできるかな。

菊池紘菊池紘

Schemaベースの単純なオレオレ言語を作ることを目標にする。

  • データ型は整数型と真偽値型のみ
    • もしできたら文字列型も入れたい
  • 動的型付け
    • 型検査はしない
  • キーワードは define lambda のみにする
  • 組み込み関数は print if =あとは四則演算
(define fact
  (lambda (n)
    (if (= n 0)
      1
      (* n (fact (- n 1)))
    )
  )
)
(print (fact 5))

とりあえずは階乗の計算ができるところが目標。

内部的には definefinal による変数宣言、 lambda がラムダ式宣言。

final fact = (n) => (n == 0) ? 1 : n * fact(n - 1);
print(fact(5));

そのうち発展型としてClojureがJavaのインスタンスメソッドを扱えるように、Dartのメソッドも扱えるようにしたい。

(.abs -120)
; -> 120

コメントも実装できると良いなぁ。

菊池紘菊池紘

Cに対するObjective-CのようにDart のスーパーセットを作っても良いのかもしれないと思い始めた。
それで開発コストが軽減できるのなら、だけど。