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の資産をシームレスに使用できる
という方向でなにか作れたら素敵。
ただし私自身に言語作成の経験が殆どないので、
- Dart VMで動く言語用のコンパイラに必要な要素はなにか検討する
- どんな文法が理想的なのか検討する
- その実装に必要な要素を検討する(型推論の方法とかとか)
ということを順々に調べながらやっていくことになりそう。
何年かかるやら。その間に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)を動かせれば良さそう。
- DartでBFのインタープリターを作る(期待したパースができているかとか確かめるためにも)
- BF -> Dartソースコード の変換をするプログラムを作る(吐いたものをDart Kernel化すれば、まずはどんな構造のDart Kernelファイルを作ればよいのかわかると思う)
- BF -> Dart Kernelコンパイラを作る
こんな順番でできればいいかな。
BFができたらLisp的な比較的シンプルめな文法の言語にトライしても良いのかもしれない(ただしLispは全然触ったこと無いので簡単にかじっておくとかはしておきたい)
BF -> Dartトランスパイラは作った。
生成された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ファイルは作れました。
出来上がった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))
とりあえずは階乗の計算ができるところが目標。
内部的には define
が final
による変数宣言、 lambda
がラムダ式宣言。
final fact = (n) => (n == 0) ? 1 : n * fact(n - 1);
print(fact(5));
そのうち発展型としてClojureがJavaのインスタンスメソッドを扱えるように、Dartのメソッドも扱えるようにしたい。
(.abs -120)
; -> 120
コメントも実装できると良いなぁ。
Kotlinを動かすのだとこの記事役に立つのかも
Cに対するObjective-CのようにDart のスーパーセットを作っても良いのかもしれないと思い始めた。
それで開発コストが軽減できるのなら、だけど。
副作用が起こるか起こらないかも型で分かった方が良いのだろうか。
IOモナドとかも良いアイデアだと思っていて、ただあれに慣れるのはハードルが高い気がしている