From feb98e1bb6c973428b94591ed5b0aed5e4137bd0 Mon Sep 17 00:00:00 2001 From: Cliff Click Date: Sat, 24 Oct 2026 15:31:01 -0700 Subject: Finish separate compilation snapshot in chapter 28b --- chapter28b/README.ja.md | 158 +++-- chapter28b/README.md | 382 +++++------- chapter28b/ROADMAP.ja.md | 451 -------------- chapter28b/ROADMAP.md | 523 ---------------- chapter28b/ainotes.txt | 4 + chapter28b/docs/25-grammar.ja.md | 175 ------ chapter28b/docs/25-grammar.md | 175 ------ chapter28b/docs/28b-grammar.ja.md | 175 ++++++ chapter28b/docs/28b-grammar.md | 175 ++++++ chapter28b/docs/Makefile | 12 - chapter28b/docs/examples/A_helloWorld.smp | 2 - chapter28b/docs/examples/BubbleSort.smp | 36 -- chapter28b/docs/examples/Capitalize.smp | 22 - chapter28b/docs/examples/Dijkstra.smp | 72 --- chapter28b/docs/examples/FileIO.smp | 50 -- chapter28b/docs/font-awesome-4.7.0.zip | Bin 669808 -> 0 bytes chapter28b/docs/ifg_trim.pdf | Bin 155190 -> 0 bytes chapter28b/docs/lattice.gv | 203 ------ chapter28b/docs/lattice.svg | 691 --------------------- chapter28b/docs/lattice2.gv | 85 --- chapter28b/docs/lattice2.svg | 260 -------- chapter28b/docs/pardoe.docx | Bin 22583 -> 0 bytes chapter28b/docs/webtcp.min.js | 65 -- chapter28b/helloWorld.exe.stackdump | 16 - chapter28b/pom.xml | 4 +- .../main/java/com/seaofnodes/simple/Parser.java | 185 +++++- .../com/seaofnodes/simple/codegen/CodeGen.java | 4 +- .../com/seaofnodes/simple/codegen/CompUnit.java | 3 +- .../java/com/seaofnodes/simple/codegen/Opto.java | 3 +- .../com/seaofnodes/simple/codegen/ParseAll.java | 13 +- .../com/seaofnodes/simple/codegen/Serialize.java | 19 +- .../com/seaofnodes/simple/node/CallEndNode.java | 2 +- .../java/com/seaofnodes/simple/node/CallNode.java | 22 +- .../main/java/com/seaofnodes/simple/node/Node.java | 1 + .../java/com/seaofnodes/simple/node/ScopeNode.java | 31 +- .../com/seaofnodes/simple/node/StopCUNode.java | 9 + .../java/com/seaofnodes/simple/node/StoreNode.java | 10 +- .../java/com/seaofnodes/simple/BoundaryTest.java | 86 +++ .../seaofnodes/simple/ChainedComparisonTest.java | 37 ++ .../java/com/seaofnodes/simple/Chapter17bTest.java | 2 +- .../java/com/seaofnodes/simple/Chapter18Test.java | 7 +- .../java/com/seaofnodes/simple/Chapter20Test.java | 7 +- .../java/com/seaofnodes/simple/Chapter21Test.java | 8 +- .../java/com/seaofnodes/simple/Chapter25Test.java | 12 +- .../seaofnodes/simple/FinalConstructionTest.java | 65 ++ .../seaofnodes/simple/SeparateCompilationTest.java | 90 +++ .../test/java/com/seaofnodes/simple/Simple.java | 25 +- chapter28b/src/test/smp/examples/A_helloWorld.smp | 2 + chapter28b/src/test/smp/examples/BubbleSort.smp | 36 ++ chapter28b/src/test/smp/examples/Capitalize.smp | 22 + chapter28b/src/test/smp/examples/Dijkstra.smp | 72 +++ chapter28b/src/test/smp/examples/FileIO.smp | 50 ++ chapter28b/src/test/smp/lazy/App.smp | 3 + chapter28b/src/test/smp/lazy/App/Main.smp | 1 + chapter28b/src/test/smp/lazy/App/Stats.smp | 1 + chapter28b/src/test/smp/lazy/App/Tables.smp | 4 + chapter28b/src/test/smp/separate/client/Main.smp | 6 + .../src/test/smp/separate/library/Counters.smp | 12 + .../reference-assets/font-awesome-4.7.0.zip | Bin 0 -> 669808 bytes docs/appendices/reference-assets/ifg_trim.pdf | Bin 0 -> 155190 bytes docs/appendices/reference-assets/lattice.gv | 203 ++++++ docs/appendices/reference-assets/lattice.svg | 691 +++++++++++++++++++++ docs/appendices/reference-assets/lattice2.gv | 85 +++ docs/appendices/reference-assets/lattice2.svg | 260 ++++++++ docs/appendices/reference-assets/pardoe.docx | Bin 0 -> 22583 bytes docs/appendices/reference-assets/webtcp.min.js | 65 ++ docs/roadmap.ja.md | 455 ++++++++++++++ docs/roadmap.md | 533 ++++++++++++++++ 68 files changed, 3642 insertions(+), 3236 deletions(-) delete mode 100644 chapter28b/ROADMAP.ja.md delete mode 100644 chapter28b/ROADMAP.md delete mode 100644 chapter28b/docs/25-grammar.ja.md delete mode 100644 chapter28b/docs/25-grammar.md create mode 100644 chapter28b/docs/28b-grammar.ja.md create mode 100644 chapter28b/docs/28b-grammar.md delete mode 100644 chapter28b/docs/Makefile delete mode 100644 chapter28b/docs/examples/A_helloWorld.smp delete mode 100644 chapter28b/docs/examples/BubbleSort.smp delete mode 100644 chapter28b/docs/examples/Capitalize.smp delete mode 100644 chapter28b/docs/examples/Dijkstra.smp delete mode 100644 chapter28b/docs/examples/FileIO.smp delete mode 100644 chapter28b/docs/font-awesome-4.7.0.zip delete mode 100644 chapter28b/docs/ifg_trim.pdf delete mode 100644 chapter28b/docs/lattice.gv delete mode 100644 chapter28b/docs/lattice.svg delete mode 100644 chapter28b/docs/lattice2.gv delete mode 100644 chapter28b/docs/lattice2.svg delete mode 100644 chapter28b/docs/pardoe.docx delete mode 100644 chapter28b/docs/webtcp.min.js delete mode 100644 chapter28b/helloWorld.exe.stackdump create mode 100644 chapter28b/src/test/java/com/seaofnodes/simple/BoundaryTest.java create mode 100644 chapter28b/src/test/java/com/seaofnodes/simple/ChainedComparisonTest.java create mode 100644 chapter28b/src/test/java/com/seaofnodes/simple/FinalConstructionTest.java create mode 100644 chapter28b/src/test/java/com/seaofnodes/simple/SeparateCompilationTest.java create mode 100644 chapter28b/src/test/smp/examples/A_helloWorld.smp create mode 100644 chapter28b/src/test/smp/examples/BubbleSort.smp create mode 100644 chapter28b/src/test/smp/examples/Capitalize.smp create mode 100644 chapter28b/src/test/smp/examples/Dijkstra.smp create mode 100644 chapter28b/src/test/smp/examples/FileIO.smp create mode 100644 chapter28b/src/test/smp/lazy/App.smp create mode 100644 chapter28b/src/test/smp/lazy/App/Main.smp create mode 100644 chapter28b/src/test/smp/lazy/App/Stats.smp create mode 100644 chapter28b/src/test/smp/lazy/App/Tables.smp create mode 100644 chapter28b/src/test/smp/separate/client/Main.smp create mode 100644 chapter28b/src/test/smp/separate/library/Counters.smp create mode 100644 docs/appendices/reference-assets/font-awesome-4.7.0.zip create mode 100644 docs/appendices/reference-assets/ifg_trim.pdf create mode 100644 docs/appendices/reference-assets/lattice.gv create mode 100644 docs/appendices/reference-assets/lattice.svg create mode 100644 docs/appendices/reference-assets/lattice2.gv create mode 100644 docs/appendices/reference-assets/lattice2.svg create mode 100644 docs/appendices/reference-assets/pardoe.docx create mode 100644 docs/appendices/reference-assets/webtcp.min.js create mode 100644 docs/roadmap.ja.md create mode 100644 docs/roadmap.md diff --git a/chapter28b/README.ja.md b/chapter28b/README.ja.md index 4feaee93..d04e9ccb 100644 --- a/chapter28b/README.ja.md +++ b/chapter28b/README.ja.md @@ -1,110 +1,108 @@ -# 第25章: モジュール、分割コンパイル、SSA 構築 +# 第28b章: 分離コンパイル [English](README.md) | 日本語 -この文書は [原文](README.md) の日本語訳です。 +[Previous: Chapter 28a](../chapter28a/README.ja.md) -[前の章: 第24章](../chapter24/README.ja.md) | -[章の一覧](../README.ja.md#各章) +前の章では、見つかったソースを一度にコンパイルしました。この章ではライブラリと +クライアントを別々にコンパイルします。クライアントにはライブラリのオブジェクト +ファイルが必要ですが、そのソースは不要です。 -この章では Simple のソースファイルを再利用可能なオブジェクトファイルへコンパイルし、その型と理想 IR を後のコンパイルに読み込み、別に構築したシステムライブラリとネイティブプログラムをリンクします。また、不完全な情報を扱うため、パーサー、型、メモリ SSA を大幅に再設計します。 +## オブジェクトに理想 IR を保存する -この番号付きスナップショットは比較用に残しています。章の分割は進行中で、型未確定時の SSA 構築、オブジェクトの構築、エスケープ解析、モジュールを名前付きの章に分けました。[分割計画](../docs/chapter-split.md) と [バックポート待ち一覧](../docs/chapter-backports.md) を参照してください。 +通常の ELF オブジェクトには機械語、データ、シンボル、再配置情報があります。 +Simple はさらに `.simple` セクションへ型と理想 IR を保存します。クライアントは +宣言を読み込んで型を検査し、関数本体も読み込んで SCCP やインライン化に使います。 +残った呼び出しは、ネイティブリンクでライブラリの機械語につなぎます。 -第21〜24章のメモリ処理はここにも引き継ぎます。Load 検索は読み取りをループ外へ移す前にマージの全枝を証明し、Phi の因数分解はメモリ破壊を確認し、スケジューリングはメモリ集合体を通じてエイリアスをたどります。検索は `EscapeNode` から非公開または公開メモリへ進み、未解決の Store エイリアスを待ちます。配列長の読み取りには要素の境界検査がなく、配列要素の読み取りは制御を保持します。整数値の Phi は、既存の型付き変換機構で、ループの拡大を通じてもロード幅を保持します。New は引き続き非公開のコンストラクタメモリを生成し、公開は Escape が扱います。以前の章の割り当て入力設計は、これを置き換えません。 +宣言型と解析中の型は別々に保存します。ある時点でフィールドの値が 0 でも、 +その宣言を定数 0 に変えてはいけません。引数の型の上限、数値演算のモード、 +Store の幅、元のソース位置も保存します。入れ子の構造体には、関数本体だけでなく +割り当て関数とコンストラクタの宣言も必要です。 -[直線的な履歴](https://github.com/SeaOfNodes/Simple/tree/linear) で [この章](https://github.com/SeaOfNodes/Simple/tree/linear-chapter25) を読み、[第24章と比較](https://github.com/SeaOfNodes/Simple/compare/linear-chapter24...linear-chapter25) することもできます。 +別々のコンパイルで同じ番号になったエイリアスや関数は、同じものとは限りません。 +`GlobalBits` は定義元のファイルとファイル内の番号を保存し、インポート時にその +組み合わせを今回の番号へ写します。型とノードに同じ写像を使い、複数ファイルを +またぐ再帰型も復元します。 -この章の[完全な言語文法](docs/25-grammar.ja.md)はこちらです。 +読み込みの単位は現在オブジェクトです。無関係なオブジェクトは読み込まずに済みますが、選ばれた +オブジェクトの保存済み IR は全体を復元し、記録された依存先も読み込みます。`sys.io.p` だけを +呼ぶ場合でも、`sys.o` にまとめられた十個の単位をすべて読み込み、`aryu8` と `aryi64` も含みます。 +必要なメンバーだけの読み込みは今後の目標です。IR の読み込みだけでクラスが初期化されたり、 +その本体がクライアントの出力にコピーされたりするわけではありません。元のソースの解析は省けますが、 +インポートしたグラフも新しい呼び出し元とともに最適化し、型検査します。 -## コンパイル単位と名前 +## 実行できる例 -`CompUnit` はソースまたはオブジェクトファイルを表します。`ParseAll` は依存関係を発見し、必要なソースを解析し、以前コンパイルした単位を読み込みます。ソースツリーとビルドツリーは対応する相対パスを使い、クラス名はドット区切りのパスを使います。たとえば `a/b/foo.smp` は名前空間 `a.b.foo` を供給します。 +英語版の例は次の二つのソースルートにあります。 -各単位は Start/Stop ノードを持ちます。関数がコンパイル単位に所有されることと、未知の外部呼び出し側を表す辺とは別です。出力のためにコードを保持することが、任意の呼び出し側から到達できることを意味してはいけません。 - -ドライバは入力パスからプロジェクトルートを推定し、出力の `-o` と外部 Simple オブジェクト検索パスの `-L` を受け付けます。検索パスにはオブジェクトファイルやディレクトリを指定できます。ヘルプには `--root` もありますが、この番号付きスナップショットでは未実装です。名前付きのモジュール章では使用できます。コンパイラはネイティブリンク用の外部 C シンボルも解決します。`_` で始まる名前と外側の名前は、未知の呼び出し元に公開するインターフェースを決めます。 - -明示的な数値型の C 宣言は、可変のネイティブ記憶領域へ直接束縛します。 - -```java -i32 counter = "C"; -counter += 1; -return counter; +```text +src/test/smp/separate/library/Counters.smp +src/test/smp/separate/client/Main.smp ``` -ネイティブリンカが `counter` を解決します。読み書きはその C 変数にアクセスし、宣言はコピーも初期化もしません。繰り返した宣言とモジュールインポートは同じ記憶領域エイリアスを共有します。整数と浮動小数点データの束縛をサポートし、ポインタと集合体のデータ束縛はまだサポートしません。外部フィールドは記憶領域フラグを持ち、宣言元クラス内でバイトを占めません。配置はフィールドオフセットを `ExternOffset` シンボルへ解決し、命令選択はクラス先頭+オフセットをネイティブシンボルアドレスへ置き換えます。ネイティブオブジェクト出力は既存の AMD64 ELF ライタを使い、ARM と RISC-V はメモリ内リンカを通じてこれらのアドレスをサポートします。スレッドローカル変数と C マクロにはアクセサ関数が必要です。システムライブラリは小さなネイティブランタイムアクセサを通じ、`libc.errno()` を公開します。 - -## オブジェクトファイルは理想 IR を含む - -ELF ライタは、ネイティブコードと、正規化された型、理想グラフノード、依存関係を含む `.simple` セクションを保存します。リーダはそのグラフを再構築し、インポートした関数をインライン化などの最適化に参加させます。インライン化せず残った呼び出しは、ネイティブリンクで解決します。 - -`GlobalBits` はファイルの同一性とファイルごとのインデックスを、エイリアス、関数対象、戻り位置の局所的な密なインデックスへ対応付けます。独立したコンパイルの等しい局所番号を、等しい同一性と取り違えてはいけません。読み込み後に型を閉じて更新し、単位をまたぐ循環参照も扱います。 - -シリアライズは、宣言型を精密化されたフロー型とは別に保持します。意味を持つすべてのノード/型のフィールドには、対応する読み書きサポートが必要です。ソースにある高コストなシリアライズの全単射検査は現在無効で、より大きな増分再ビルドテスト `testModule0` は無視されています。どちらも有効な検証保証ではありません。 - -外部フィールドのフラグと記号的オフセットは、シリアライズされた配置を変更します。マジックは `C0DE` のままで、独立した形式バージョンはまだありません。このコンパイラへインポートする前に、すべての Simple オブジェクトファイルを再ビルドしてください。 - -## 型が完成する前の SSA 構築 +ライブラリは、ループで final フィールドを計算する `Counter` と共有カウンタを +公開します。クライアントの `run(3)` は最初に 107 を返します。同じプロセスで +続けて `run(5)` を呼ぶと 231 になります。インスタンスは別々ですが、クラスの +カウンタは共有されます。`run(0)` はライブラリを使わずに戻ります。 -Simple は引き続き AST を介さず直接 SSA に解析します。前方参照により、解析時点では式の最終的な型が利用できない場合があります。そのため構文と解決済みの字句的束縛でトポロジーを選び、後から型でグラフを精密化、最適化、検証します。 +このディレクトリでライブラリをコンパイルします。 -- 算術ノードは整数モードか浮動小数点モードかの選択を延期し、SCCP 後の再帰的グラフ成分を通じた解決も扱います。 -- Call は呼び出し先の種類が決まる前に、構文上のレシーバスロットを保持します。記号的なフィールド情報は配置依存の判断を延期します。 -- Load と通常の Phi は、パーサーが供給した下限型を持たなくなります。 -- `TypeScalar` は整数、浮動小数点、メモリポインタ、関数ポインタ値を、大域的な制御/メモリのボトムと区別して表します。 -- `TypeStruct._open` は不完全なフィールド集合を記述し、`_fref` は権威ある定義の欠如を記録します。フィールドを発見したことは、型を定義したことではありません。 -- ガードは入力の種類がわかる前に、分岐が証明したゼロ/非ゼロの事実を運びます。`FunPtrNode` は関数の戻りグラフへの明示的な辺を保持します。 - -ドライバはシリアライズとマシン選択の前に、解析、悲観的反復、SCCP、最終型検査を行います。単純でないインライン化は、常に即時のピープホール最適化として行うのではなく、反復と調整します。 - -## メモリと構築 - -パーサーは通常のバルクメモリを保持します。最適化器は `MemMerge`、`MemPhi`、`BulkMemPhi` で正確なエイリアスを復元します。バルク Phi は、並列の正確な Phi で表す除外分以外のすべてのエイリアスを覆います。各スライスはちょうど1回だけ覆われなければなりません。 - -ユーザーコンストラクタは次のように宣言し、呼び出します。 - -```java -struct Box { - i64[] values; - new Box = { i64[] initial -> values = initial; }; -}; -return new Box(new i64[1]); +```sh +make lib +make build/classes/test/.ttag +java -ea -cp "build/classes/main:build/classes/test:lib/*" \ + com.seaofnodes.simple.Simple --norun -o build/separate-example/lib/ \ + src/test/smp/separate/library/Counters.smp ``` -宣言で割り当て補助関数を生成します。これは割り当てを行い、隠れた `` とユーザーコンストラクタを順に呼び、`EscapeNode` を通じて初期化済みの非公開メモリを公開します。パーサーの `Var` メタデータは、早すぎるフィールド読み取りやコンストラクタ出口での未初期化を検出します。Store の幅は保存する値ではなく、対象の宣言から得ます。 +次にオブジェクトを使ってクライアントを評価します。 -ファイルレベルのコードは、インスタンス初期化とは異なるクラス初期化子(``)で表します。遅延初期化と循環検査については[英語版の説明](README.md#lazy-class-initialization)を参照してください。今後の計画は[英語版ロードマップ](ROADMAP.md#class-initialization-and-compiler-follow-ups)にあります。 - -## システムライブラリと例 - -以前の単一の `sys.smp` ライブラリは、libc 束縛、I/O、文字、スキャナ、配列、伸長可能なバッファ、ビット集合の単位に整理されました。ネイティブドライバは実際のプログラム引数をサポートします。`docs/examples` の例には Bubble Sort、Capitalize、Dijkstra、FileIO があります。 +```sh +java -ea -cp "build/classes/main:build/classes/test:lib/*" \ + com.seaofnodes.simple.Simple --eval \ + -L build/separate-example/lib/Counters.o \ + src/test/smp/separate/client/Main.smp 3 +``` -`Chapter25Test` は、意図的にインライン化せず残す Hello World 呼び出しを含め、ライブラリ読み込みとネイティブリンクを検証します。そのテストは `sys.o` とリンクする前に、クライアントの外部シンボルを確認します。ほかのテストは前方コンストラクタ、呼び出し経由のフィールド更新、リテラルのエスケープ、縮小したコンパイラ失敗を検証します。独立した回帰テストは以前の章へ移す候補です。 +結果は `107` です。Windows のクラスパス区切りには `;` を使います。クライアントの +ソースルートには `Counters.smp` がありません。`SeparateCompilationTest` はさらに +二つのオブジェクトを C ドライバとリンクし、繰り返し呼び出す動作を検査します。 -## ビルドと確認 +## 解析とコードの所有者 -このディレクトリで `make lib` は Java テスト依存関係を用意し、`make tests` は章の生のスイート、独立スイート、システムテスト、ファザー回帰テストを実行します。`make release` はコンパイラ jar とネイティブライブラリ成果物を構築し、`make tags` はエディタ用タグを構築します。ネイティブツールと選択した CPU/ABI は環境と一致する必要があります。Makefile は現在、既定で x86-64/win64 を使います。 +インポートした本体は解析に参加しても、クライアントの出力には属しません。 +`Serialize` は `Lower` がクラス初期化を展開する前に理想 IR を保存します。 +`Unlink` は機械語生成に向けてインポートした本体と解析用の呼び出し辺を切り離します。 +インライン化でクライアントへコピーされたコードは、クライアント自身の本体として +出力されます。 -シリアライズ IR は `C0DE` ヘッダを使います。ポインタ型は独立した読み取り専用アクセスビットを含みます。形式にはまだバージョン番号がないため、形式を変更したらオブジェクトファイルを再ビルドしてください。現在、後方互換性は保証していません。 +初期化規則は前の章と同じです。型のインポートだけでは初期化しません。能動的な使用は +`CLInit` を通して初期化を要求し、ライブラリが持つクラスオブジェクトとフラグを使います。 +依存関係の検査にはインポートした本体も含めます。ネイティブコードへ渡した関数の +未知の呼び出し元も保持します。 -コンパイラ変更は `sys.o` のシリアライズ IR とネイティブコードの両方を無効にする場合があります。リンクしたプログラムのテスト結果を解釈する前に再ビルドしてください。ソースだけの部分集合は、この章の完全な `make tests` と同等ではありません。 +コンストラクタのフィールド更新はローカル値と Phi のままで、ヘルパーの出口に Store を +置きます。未完成のオブジェクトでも初期化済みフィールドは読めます。 +アンダースコアは公開インターフェースの選択に使いますが、ソースのアクセス制限は +[レビュー待ち](../docs/chapter-backports.md)です。 -## RegAlloc の改良: 生存区間の面積と分割コスト +## 検証と今後 -第24章はループ Phi の高頻度辺を分割する前に、低頻度のコピーを試しました。この章ではさらに、スピルがスケジュール済みコードのどれだけをレジスタ圧力から解放するかを推定し、新しいコピーの推定コストで割ります。callee-save 区間は関数全体を覆います。複製可能な定数は使用の近くで再構築できます。ループ内のコピーは高コストなので、`8^loopDepth` で重み付けします。特に多数の使用を持つ値については、低コストな近似です。 +リポジトリのルートから次を実行します。 -複数の固定レジスタ使用を直接分割する規則や、一部の複数定義区間をより深く分割する規則など、第25章のほかの衝突処理はここに残します。サイズのしきい値はヒューリスティックであり、最初の割り当て器へバックポートすべき一般的不変条件ではありません。共有される合法性修正は、引き続き最も早い該当章から始めます。最終監査は第20〜25章の固定隣接ノードの色バイアス、第20〜21章の狭いストアマスク、第21〜25章の ARM レジスタバンク/浮動小数点メモリエンコーディングを修正しました。 +```sh +make tests CHAPTERS=chapter28b +``` -第21章の隣接コピー転送も引き継ぎます。次の命令だけで使うコピーは、オペランドがコピー元レジスタを受け入れ、命令の結果に結び付けられていなければ除去します。 +保存したコンストラクタ、インポートをまたぐ初期化循環、共有データ、ネイティブ関数の +サンク、ライブラリとクライアントの実行を検査します。Make はテスト用の `sys` も +オブジェクトにします。`make release` は jar と標準ライブラリを作り、`make view` は +共通のグラフビューアーを起動します。 -現在の比較は、固定したテスト群を行、コンパイラの章を列にした -[英語版の測定表](README.md#regalloc-improvements-live-range-area-and-split-cost) を参照してください。 -各セルは ARM/RISC-V の実行命令数、そのうち割り当て器が生成したコピーなどの命令数、 -x86 のループ重み付き移動数を示します。これらは異なる指標です。 -対象、入力、除外項目は [測定方法](../docs/regalloc-spills.md) にあります。 -古い測定群の集計値と混ぜて比較しないでください。 +保存形式は `C0DE` 以外のバージョン番号をまだ持ちません。コンパイラや形式を変えたら +オブジェクトを再構築してください。高コストの往復一致検査は無効のままで、古い増分 +ビルドの実験 `testModule0` も実行対象外です。 -クラス初期化、インライン化、エスケープ解析、ライブラリの変更もグラフを変えます。 -章をまたぐ差を割り当て器だけの品質差と解釈せず、同じ入力とコンパイラで -ヒューリスティックを比較してください。 +[分割計画](../docs/chapter-split.md)の主要な七つのスナップショットはこれで揃います。 +ネイティブライブラリの構築と最適化の調整は[付録](../docs/appendices/README.md)にまとめています。 diff --git a/chapter28b/README.md b/chapter28b/README.md index d6ab5666..189f2b7b 100644 --- a/chapter28b/README.md +++ b/chapter28b/README.md @@ -1,267 +1,177 @@ -# Chapter 25: Modules, Separate Compilation, and SSA Construction +# Chapter 28b: Separate Compilation English | [日本語](README.ja.md) -[Previous: Chapter 24](../chapter24/README.md) | -[Chapter index](../README.md#chapters) +[Previous: Chapter 28a](../chapter28a/README.md) -This chapter compiles Simple source files into reusable object files, loads -their types and ideal IR into later compilations, and links native programs -against a separately built system library. It also contains a substantial -parser, type, and memory-SSA redesign to support incomplete information. +The previous chapter compiled every discovered source file together. This +chapter lets a library and other code compile separately, and have full type +information. The client needs the library's *object* file, but not its source. +In spirit this is similar to Java's *class* file, with its full execution and +type semantics stored in the file; we happen to be using an ELF file for the +same reason. The ahead-of-time compiled code is *also* available for the +linking step. -You can also read [this chapter](https://github.com/SeaOfNodes/Simple/tree/linear-chapter25) -in the [linear history](https://github.com/SeaOfNodes/Simple/tree/linear) and -[compare it with Chapter 24](https://github.com/SeaOfNodes/Simple/compare/linear-chapter24...linear-chapter25). +An ordinary native object contains machine code, data, symbols, and +relocations. Simple adds a `.simple` section with types and the ideal IR. +Importing `.simple` lets the client check types and optimize calls into the +library. Calls that remain out of line use the library's machine code at +native link time. -Here is the [complete language grammar](docs/25-grammar.md) for this chapter. +## A library and a client -## Compilation units and names +The runnable example has two separate source roots: -`CompUnit` represents a source or object file. `ParseAll` discovers dependencies, -parses needed sources, and loads previously compiled units. Source and build -trees use corresponding relative paths; class names use dotted paths. For -example, `a/b/foo.smp` supplies the namespace `a.b.foo`. - -Each unit has Start/Stop nodes. A function's ownership by a compilation unit is -distinct from an edge representing unknown external callers: retaining code -for emission must not imply that arbitrary callers can reach it. +```text +src/test/smp/separate/library/Counters.smp +src/test/smp/separate/client/Main.smp +``` -The driver infers the project root from the input path and accepts `-o` for -output and `-L` for external Simple object search paths, including an object -file or a directory. Its help advertises `--root`, but this numbered snapshot -does not yet parse that option; the named modules snapshot does. -The compiler also resolves external C symbols for native linking. Names beginning -with `_` control the public interface; enclosing names also affect which -entries are exposed to unknown callers. +`Counters.smp` declares shared state and an instance constructor: -Explicit numeric C declarations bind directly to mutable native storage: +```simple +int calls=0; +val next_noInline = { -> calls++; return calls; }; -```java -i32 counter = "C"; -counter += 1; -return counter; +struct Counter { + val value=1; + new Counter = { int n -> + value=0; + for( int i=0; i value; }; +}; ``` -The native linker resolves `counter`. Reads and writes access that C variable; -the declaration neither copies nor initializes it. Repeated declarations and -module imports share the same storage alias. Integer and floating-point data -bindings are supported; pointer and aggregate data bindings are not yet supported. -External fields carry a storage flag and occupy no bytes in their declaring -class. Layout resolves their field offsets to `ExternOffset` symbols; instruction -selection replaces class-base-plus-offset with the native symbol address. -Native object output uses the existing AMD64 ELF writer; ARM and RISC-V support -these addresses through the in-memory linker. Thread-local variables and C macros -need accessor functions: the system library exposes `libc.errno()` through a small -native runtime accessor. - -Native function pointers still occupy four bytes. A native library can live -above that address range, so the AMD64 ELF writer gives each address-taken -native function a small entry in Simple's low-address code. The entry tail-jumps -through the native symbol's PLT entry; arguments and the return address pass -through unchanged. Direct calls still use the native symbol directly. - -Static class fields and addresses computed in code both refer to that entry. -Its stable weak symbol, `__simple_native$`, lets separately compiled -objects agree on one pointer when linked into an executable. The class image -uses a four-byte relocation to this defined entry, instead of a four-byte -relocation to a dynamic native symbol in writable data, which GNU ld rejects. -Constant field Stores can still fold away. The entry is a Simple function -identity; it need not equal the raw address obtained by native code. - -`StaticDataTest.testNativeFunctionIdentity` reads two separately compiled class -images before their initializers run, compares their stored and computed -addresses, and calls the native function. It checks both object-link orders. - -## Object files contain ideal IR - -The ELF writer stores native code and a `.simple` section containing canonical -types, ideal graph nodes, and dependencies. The reader reconstructs that graph -so imported functions can participate in optimization, including inlining. -Calls that remain out of line are resolved by native linking. - -`GlobalBits` maps file identities and per-file indices to local dense indices -for aliases, function targets, and return points. Equal local numbers from -independent compilations must not be mistaken for equal identities. Types are -closed and upgraded after loading, including cross-unit cyclic references. - -Serialization preserves declaration types separately from sharpened flow types. -Every semantic node/type field needs matching read/write support. The source's -expensive serialization bijection check is currently disabled, and the larger -incremental-rebuild test `testModule0` is ignored. Neither is an active -validation guarantee. - -The external-field flag and symbolic offsets change the serialized layout. -The magic remains `C0DE`; there is no separate format version yet. Rebuild all -Simple object files before importing them with this compiler. - -## Constructing SSA before types are complete - -Simple still parses directly to SSA without an AST. Forward references mean an -expression's eventual type may be unavailable while parsing it. Syntax and -resolved lexical binding therefore choose topology; types subsequently refine, -optimize, and validate the graph. - -- Arithmetic nodes defer integer versus floating-point mode selection, including - resolution through recursive graph components after SCCP. -- Calls preserve their syntactic receiver slot before the callee kind is settled. - Symbolic field information defers layout-dependent decisions. -- Loads and ordinary Phis no longer carry parser-supplied lower-bound types. -- `TypeScalar` represents integer, float, memory-pointer, and function-pointer - values separately from global control/memory bottom. -- `TypeStruct._open` describes an incomplete field set; `_fref` records the - absence of an authoritative definition. Discovering fields does not define a type. -- Guards carry branch-proven zero/nonzero facts before the input family is known. - `FunPtrNode` retains an explicit edge to its function's return graph. - -The driver separates optimization from lowering: +`Main.smp` uses both parts of the library: -```text -Parse -> Iter -> Opto -> IterPostOpto -> FinalizeIR -> TypeCheck - -> Serialize (when producing an object) -> Lower -> LoopTree - -> Unlink -> Select -> Schedule -> LocalSched -> RegAlloc -> Encoding +```simple +val run = { int n -> + if( !n ) return 0; + val c = new Counters.Counter(n); + return c.get()+100*Counters.next_noInline(); +}; +return run(arg); ``` -`Opto` runs SCCP and resolves numeric modes. `IterPostOpto` applies peepholes -and inlining using those results; `FinalizeIR` settles field layouts and offsets. -Type checking sees the optimized ideal graph. Serialization saves that graph -before lowering introduces implementation details such as initialization guards. -For machine compilation, `Unlink` detaches imported function bodies before -instruction selection; calls retain the symbols needed for linking. Ideal-IR -evaluation keeps those bodies available and skips machine selection. +At runtime, `run(0)` returns without reaching or initializing `Counters`. -## Memory and construction +For `run(3)`, `Counters` initializes, the constructor computes 7 and +`calls`==1, so we get `(7+100*1)` or 107. -The parser carries ordinary bulk memory. The optimizer recovers precise aliases -using `MemMerge`, `MemPhi`, and `BulkMemPhi`. A bulk Phi covers all aliases -except its exclusions, represented by parallel precise Phis. Every slice must -be covered exactly once. +Calling `run(3)`, then `run(5)`, in one process increments the shared `calls` +twice. The first call gives `(7+100*1)`, or 107; the second gives +`(31+100*2)`, or 231. -User constructors are declared and called as follows: +(The `_noInline` suffix prevents inlining, so the example exercises native +linking as well as imported IR.) -```java -struct Box { - i64[] values; - new Box = { i64[] initial -> values = initial; }; -}; -return new Box(new i64[1]); +From this chapter directory, build the compiler and compile the library: + +```sh +make lib +make build/classes/test/.ttag +java -ea -cp "build/classes/main:build/classes/test:lib/*" \ + com.seaofnodes.simple.Simple --norun -o build/separate-example/lib/ \ + src/test/smp/separate/library/Counters.smp +``` + +Then compile and evaluate the client using that object: + +```sh +java -ea -cp "build/classes/main:build/classes/test:lib/*" \ + com.seaofnodes.simple.Simple --eval \ + -L build/separate-example/lib/Counters.o \ + src/test/smp/separate/client/Main.smp 3 ``` -An allocation helper is generated at the declaration. It allocates, calls the -hidden `` and then the user constructor, and publishes initialized private -memory through `EscapeNode`s. Parser `Var` metadata detects early field reads -and missing initialization on constructor exits. Store widths come from target -declarations, not from the values being stored. -## Lazy class initialization +## What crosses the separate compilation boundary -File-level code is represented by a class initializer (``), distinct -from instance initialization. An active class-field access ensures that the -class is initialized. Taking a class reference is passive: it identifies the -class without running its body. Initialization runs once, on the path that -first needs it, and a parent initializes before its child. +The optimized IR owned by the object is compactly encoded in the `.simple` +section and fully reconstructed when read back in. The saved state includes +canonical declarations as well as optimized flow types. E.g. `int x=7` has +declared type `int` and initial value `7`. Struct field types (both declared +and optimized), function argument types (both declared and optimized), numeric +modes, store widths, and source locations also survive serialization. -For example, if `B.smp` computes `value`, then this code initializes B only -when `take` is true; the second access reuses the initialized class: +Each loaded `.simple` section restores its units into the shared `CompUnit` +tree, mirroring the original code layout. A dependency shared by several +objects uses the same `CompUnit`. Loaded aliases and function indices are +renumbered to avoid collisions; all the dense indices end up in the same +namespace. `GlobalBits` has the mapping from the imported file indices to the +local compilation indices; this remapping extends everywhere through the loaded +code, including recursive types that span several files. Importing skips +parsing the original source, but it still analysed and type checked with its +new callers. -```java -return take ? B.value + B.value : 0; -``` +`ParseAll` is the workhorse that discovers source and object dependencies. It +tracks missing symbol references, looking them up in the search path one by one, +and loading the matching files. + +The end result combines locally parsed and imported IR in one graph, while +keeping their separate `CompUnit`s. This combined compilation can take +advantage of e.g. constants in the library, or inline library code using the +normal inlining heuristics. The combined graph goes through the normal +compilation phases, including peepholes, Opto and TypeCheck. + +Dependencies between `CompUnit`s are recorded. An explicitly requested source +file is always compiled. Other source files are recompiled if their object is +missing, their source is newer, or a recorded dependency's object in the build +directory is newer. These timestamp checks are not yet a complete incremental +build system, there is some modest future work needed to finish this. + +Loading currently works at the object granularity. Unrelated objects can stay +unloaded, but selecting an object loads its entire saved graph and follows its +recorded dependencies. Future work will look at loading sub-parts more +incrementally. + + + +## Analysis, ownership, and initialization + +An imported function can participate in analysis without belonging to the +client's output. Loading the `io` library, with its `p` print function, means +that `p` is part of the analysis - but when writing out the `helloWorld` app, +`p` will not end up in the `helloWorld.o` file directly. It might be inlined +fully, or called out of line, but there won't be a stand-alone copy of it. + +After optimization, `Serialize` saves ideal IR before `Lower` expands class +initialization. `Unlink` then detaches imported bodies for machine compilation +and removes analysis call edges. The client emits its own bodies and any code +copied into them by inlining; the +remaining calls refer to symbols supplied by the library object. + +Class initialization follows the previous chapter's rules. Importing a type +does not initialize its class. Active uses retain `CLInit` checks until +lowering (unless optimization clears them out). The library supplies its +shared class object and flag. Initialization checks appear at all the active-touch +locations, whether local or remote; including source locations for error +reporting. -The compiler represents the obligation with an opaque `CLInit` node. It carries -control, whole-memory effects, the class pointer, and a load of the hidden -`$init` flag. Its results include a memory slice where that flag is known true. -Ordinary memory SSA and load simplification can therefore remove repeated -checks, including after a merge when every incoming path has initialized the -class. Calls conservatively account for arbitrary memory effects. - -After optimization, the compiler builds a graph containing function calls, -class touches, and parent requirements. A strongly connected component with -more than one class initializer is an error. Ordinary recursion and helper -cycles involving just one initializer are allowed. Checking after optimization -means eliminated branches and call targets do not create false dependencies. -Diagnostics show the cyclic edges and their source locations, including calls -through helpers and imported code. - -Object files preserve opaque initialization nodes and their source locations. -Imported ideal bodies participate in the combined cycle check before lowering. -Lower then expands each remaining obligation into a flag test, a conditional -initializer call, and control/memory merges. The initializer owns the flag store; -the store is at body entry to support permitted same-class reentry. Cross-class -cycles have already been rejected. This is a single-threaded protocol. - -The selected entry class receives the current integer `arg`; other initializers -receive zero. Planned argument arrays and further initialization optimizations -are described in the [roadmap](ROADMAP.md). - -## System library and examples - -The former single `sys.smp` library is organized into units for libc bindings, -I/O, characters, scanners, arrays, growable buffers, and bitsets. The native -driver supports real program arguments. Examples in `docs/examples` include -Bubble Sort, Capitalize, Dijkstra, and FileIO. - -`Chapter25Test` exercises library loading and native linking, including a Hello -World call deliberately kept out of line. That test checks the client's external -symbol before linking against `sys.o`. Other tests cover forward constructors, -field updates through calls, literal escapes, and reduced compiler failures. -Independent regressions are candidates for earlier chapters. ## Building and checking -From this directory, `make lib` supplies Java test dependencies and `make tests` -runs the raw chapter suites, standalone suites, system tests, and fuzzer -regressions. `make release` builds the compiler jar and native library artifacts; -`make tags` builds editor tags. Native tools and the selected CPU/ABI must match -the environment; the Makefile currently defaults to x86-64/win64. - -Serialized IR uses the `C0DE` header; pointer types include an independent -read-only access bit. The format is not versioned yet, so rebuild object files -after format changes. Backward compatibility is not currently supported. - -Compiler changes can invalidate both serialized IR and native code in `sys.o`. -Rebuild it before interpreting linked-program test results. A source-only subset -is not equivalent to this chapter's full `make tests`. - -## RegAlloc improvements: live-range area and split cost - -Chapter 24 tried cold copies before splitting a loop Phi's hot edges. This -chapter also estimates how much scheduled code a spill frees from register -pressure, divided by the estimated cost of the new copies. Callee-save ranges -cover a whole function. Cloneable constants can be rebuilt nearer their uses. -Copies inside loops cost more: the estimate weights them by `8^loopDepth`. -These are inexpensive approximations, especially for values with many uses. - -A single-use function address in the same block gets priority for -rematerialization when it is separated from its use. Moving that address -calculation next to the use adds no instruction and avoids preserving a -callee-save register merely to hold the constant. Adjacent uses and multi-use -addresses retain the area/cost ranking. - -Rows are fixed test cohorts; columns are compiler chapters. Each cell gives -**Ops / RA / X**: executed ARM+RISC-V instructions, the subset emitted for -allocator copies/rematerializations, and x86's loop-weighted split-move estimate. -**Cases D / X** counts measured dynamic program/target cases and x86 compilations; -membership and inputs stay fixed across columns. Native-library work is excluded. -Chapter 20 has no encoder, hence no dynamic counts. Lower is better within each -metric; see the [measurement details](../docs/regalloc-spills.md) for coverage. - - -| Test cohort | Cases D / X | Ch 20: Ops / RA / X | Ch 21: Ops / RA / X | Ch 22: Ops / RA / X | Ch 23: Ops / RA / X | Ch 24: Ops / RA / X | Ch 25: Ops / RA / X | -|---|---:|---:|---:|---:|---:|---:|---:| -| Ch 20 | 22 / 13 | — / — / 161 | 55,173 / 5,407 / 174 | 58,751 / 9,099 / 175 | 58,736 / 9,084 / 184 | 58,720 / 9,068 / 183 | 58,965 / 9,076 / 208 | -| Ch 21 | 20 / 18 | | 6,207 / 261 / 461 | 6,324 / 379 / 475 | 6,326 / 381 / 475 | 6,325 / 380 / 470 | 6,196 / 219 / 534 | -| Ch 22 | 14 / 8 | | | 198 / 60 / 7 | 194 / 56 / 7 | 194 / 56 / 7 | 252 / 92 / 11 | -| Ch 23 | 14 / 8 | | | | 630 / 160 / 36 | 630 / 160 / 36 | 864 / 358 / 36 | -| Ch 24 | 36 / 20 | | | | | 4,923 / 1,341 / 790 | 4,646 / 1,335 / 609 | -| Ch 25 | 2 / 12 | | | | | | 20 / 0 / 1,856 | - - - -Chapter 25 introduces several features, which when run on the older tests -generate a lot more code, which in turn generates more spills. - -Class initialization, inlining, escape analysis, and library adaptations -all change the graphs. To help with this, we adjust the inlining -heuristics to try to inline and optimize the boilerplate. +From the repository root: + +```sh +make tests CHAPTERS=chapter28b +``` +The suite includes the preceding constructor and escape regressions, imported +constructors, initialization cycles across objects, shared static data, native +function thunks, and native library/client execution. Make also builds the +modular `sys` object used by the library tests. Clients can import that object +with `-L`; they do not need to parse the standard library's source again. +`make release` builds the launcher jar and standard library; `make view` +starts the shared graph viewer. + +The serialized format is internal and currently unversioned beyond its `C0DE` +magic. Rebuild Simple objects when the compiler or layout changes. The expensive +serialization bijection check remains disabled, and `testModule0`, the older +incremental-rebuild experiment, remains ignored. They are not validation +guarantees for this snapshot. + +This completes the seven main snapshots in the [approved split](../docs/chapter-split.md). +See the appendices on [native libraries](../docs/appendices/native-libraries.md) +and [optimizer/backend tuning](../docs/appendices/optimizer-tuning.md). diff --git a/chapter28b/ROADMAP.ja.md b/chapter28b/ROADMAP.ja.md deleted file mode 100644 index 222f228a..00000000 --- a/chapter28b/ROADMAP.ja.md +++ /dev/null @@ -1,451 +0,0 @@ -# ロードマップ - -[English](ROADMAP.md) | 日本語 - -この文書は [ROADMAP.md](ROADMAP.md) の日本語訳です。原文の設計案と未解決の問いを、そのまま設計案として記しています。 - -## 分割コンパイル - -未知の前方参照をどう扱うか? H-M は使わないので、単一化も行わない。 -関数以外の前方参照を認めないことにする……関数なら、定義した時点ですぐにシグネチャを提供できる。 - -案 A:FRefNode を削除し、すべてのバグを直す。 -案 A の問題:相互再帰を使えるようにしたい。 -例:`val even = { int x -> x ? odd(x-1) : true; }; val odd = { int x -> x ? even(x-1) : false; };` - -案 B:型は順序どおりに定義する必要があるが、それ以外の関数には順序を要求しない。 -`new T` ならエラーにできるが、`fref.field`、`fref()`、`fref op fref`、`fref[]` ではできない。 - -あらゆる場所で Type.BOTTOM をパーサーの要件に合わせて「引き上げる」必要がある。 -FRef からフィールドをロードするには、FREF を FIELD のある TSTRUCT への TMP に引き上げる必要がある……。 -実際には、FREF が正しくなると局所的に仮定するだけだ。型は任意のコードから来るので、 -アクセスできず、引き上げられない。TMP は nullable かもしれない(後でエラーにすべき)。 -TSTRUCT は無名にでき、無名になるだろう。これは、すべての TSTRUCT を無名にすることを意味する。 - -問題は、未知・遠隔・外部・前方の参照にある。 - -FRef を*少しでも*認めると、すべての処理が FRef 型に遭遇することを考慮しなければならない。 -同じスコープの関数で認めると、上の odd/even の例が使える。 -同じスコープの構造体で認めると、相互再帰的な構造体が使える。 -スコープの外へ昇格させる際には外部の検索を試み、見つからなければ失敗する。 - -任意の使い方の例:`sys.fld`。`sys` の検索に失敗したら、次のどちらかを推測しなければならない。 -前方参照で問題なく、間もなく定義されるのか……それとも今すぐ外部を検索するのか。 -さらに、使い方によっては問題の発覚が遅れる。 -```java -// Extern or Future `sys` being returned. -val foo { -> return sys; } - -// foo() returns FRef, so Bottom, so the `.bar` has no type -// to do field lookups -val main { arg -> foo().bar } - -// HERE: Parser finds `sys` OR NOT?!?!?! -val sys??? = user_stuff....; - -``` - -行き着く先は、パーサーが一切エラーを出さず、盲目的な AST のように SSA を構築し、 -不適切な型だらけのグラフを結線するだけになることだ。 -必要なこと:パーサーを導く型をなくす! 構文だけを使う! - -(明らかな小さな問題:浮動小数点数へ拡張するかどうか。) -修正:たとえば整数演算を挿入する。両方の入力が isa-Int であり、isa-Float に引き上げられなくなるまでは、 -戻り値の型を Int と Float の MEET とする。 - -メソッド呼び出しで起こり得る問題: -`UNKNOWN_STRUCT_BOT.UNKNOWN_FIELD ( ARGS ); // Insert SELF OR NOT?` -— SELF を挿入するか? -修正案:常に SELF 引数があると仮定し、静的と証明できる場合は null にする。 -最適化:定数パラメータをシグネチャから削除するか? *定数*パラメータは、 -*パーサー*の時点で定数でなければならない。そうでなければ未知の呼び出し元がないことが必要になる -(したがって局所的な最適化になる)。 -修正案:SELF 引数を*最初*ではなく*最後*に置くと、不要になった場合に削除しやすいか? - -Load は ConFldOff を捨て、名前を保持する。 -Load はスケーリング前の添字を保持し、添字入力を持つ。構造体ではこの入力は null。 -Ptr Base が*確定*した後で基底の配置を行い、添字の計算を畳み込める。 - -- `Load(ctrl, base, null );` — フィールド名は内部に持つ。 -- `Load(ctrl, base, index_math );` — フィールド名は `[]`。 -- `Store(ctrl, base, null , val);` - -問題:エイリアス情報がない! - -案 C:直接呼び出し `odd()` と型では FRef を認める。それ以外はすべて*引き上げ*が必要。 - -## 構造体と配列の統合 - -構造体のフィールドは名前で索引付けされ、配列の要素は数値で索引付けされる。 -この2つの考え方は両立する、という発想です。 -C 言語では古くからこの考え方を使っています。通常の C の構造体の後に配列を続け、 -通常の配列構文で索引アクセスできます。 - -別の方法として、配列へのポインタをフィールドに保持すると、間接参照が1つ増える代わりに柔軟性が得られます。 -特に、配列を(通常はより大きな配列に)交換できます。 -これは、広く使われる汎用コンテナ `Vector` や `ArrayList` の基礎です。 - -```java -struct str { - int hash; // A cache of the strings hash code - u32 #; // The array length - u8 []; // Array of bytes -}; - -str X = "abc"; -print(X.hash); // Read the hash field -X[0]=='a'; // Read array element 0 -X#; // Length of the array - -``` - -ここでは、`#` というフィールドが配列の長さを保持し、`[]` というフィールドが実際の配列です。 -メモリ内では、この配列がほかのフィールドの直後に続きます。 -可変長配列の別の例を示します。 - -```java -struct vecInt { - u32 size; // Actual number of elements - u32 #; // The array length or capacity - int []; // Array of integers. -}; -``` - -明らかな制約として、配列のサイズを直接変更することはできません。 -先頭のフィールドと同じメモリブロックに実際に配置されているからです。 -このような `vecInt` を、より大きい新しい `vecInt` に*再割り当て*することはできますが、 -元の `vecInt` は解放されます。同じ `vecInt` の参照を永遠に使い続けることはできません。 - -名前付きフィールドはいくつあってもかまいません。 - -```java -struct Class { - !str !className; - !str !professor; - int time; - int credits; - !Class !prerequisite; - u16 #; // Limit of 65535 students per class - Student []; -}; -``` - -自己参照も使えます。 - -```java -struct NTree { - Some val; - u8 #; // Length is 0-255 - NTree []; // More NTrees -}; -``` - -構文規則は次のとおりです。 - -- 最後のフィールドの名前は `[]` で、どの型でもよい。 -- 最後から2番目のフィールドの名前は `#` で、配列の最大長を表す符号なし整数型でなければならない。 -- ` []` の前に空白が必要になるかもしれない。 - -### コンストラクタと配列 - -割り当てには配列の長さを含め、コンストラクタも含められます。 -`new NTree{val=17;}[2];` - -コンストラクタは省略できますが、配列の長さは省略できません。 - -配列を初期化するための任意の関数を使うと、一度だけ書き込む final 配列を作れます。 -`new u8[buffer#,{ u32 idx -> buffer[idx].toUpperCase() }]` - -### 配列の最大長の変更 - -範囲チェックのある小さな配列を大量に使う場合、配列の長さのために丸々4バイトを確保すると、 -配列のオーバーヘッドが大きく増えることが問題になります。 -Simple では最大長を小さくできます。ただし、最大長が異なる配列は別の型として扱います。 - -```java -struct x0 { u8 #; u8[]; }; // Array limited to 0-255 length -struct x1 { u16 #; u8[]; }; // Array limited to 0-65535 length -struct x2 { u32 #; u8[]; }; // -struct x3 { u64 #; u8[]; }; // - -x0 x = "abc"; // 4 bytes total: [3, 'a', 'b', 'c'] -x1 y = "def"; // 6 bytes total: [3, 0 , 'd', 'e', 'f', 0,]; 1 pad byte to acheieve 2-byte alignment -x = y; // ERROR, "x1 is not x0", no auto-widening -x += y; // OK, 7 bytes total: [6, 'a', 'b', 'c', 'd', 'e', 'f'] -y += x; // OK, 8 bytes total: [6, 0 , 'd', 'e', 'f', 'a', 'b', 'c'] - -x += "VeryLongString.... ....255_chars"; // Runtime RangeCheck - -// Explicit conversion to widen string -y = "" + x; -``` - -### 拡張可能な配列・文字列の2つの形:間接参照を増やすかどうか - -間接参照を1つ増やすと、Java の `ArrayList` や C++ の `Vector` のようになります。 - -増やさない場合、拡張可能な配列を伸ばす呼び出しは、新しいオブジェクトを返す可能性があります。 -拡張は必要な場合だけ行います。 - -```java -val vec1 = new vecInt[0].add(2); // len=1, capacity=1 -val vec2 = vec1.add(3); // NEW !vecInt !returned, only is deleted; len=2; capacity=2; -vec1[0]; // ERROR, vec1 has been freed by call to `vec1.add(3)` -vec2[0]; // OK -vec2[1]; // OK -vec2[2]; // Runtime error, AIOOBE -``` - -## 文字列の実装 - -既定の文字列は「str」「cstr」「ustr」などの名前を持ちます。 - -常に unicode8 を使い、u8 を明示的に操作します。 -Unicode の「文字」は、基礎となる実装の上に関数呼び出しとして提供します。 -おそらく別の文字列クラスで実装することになります。 - -## 既定の文字列 - -連結によって効率的に拡張でき、さまざまな IO/printf 関数をサポートします。 -明示的に要求すれば、基礎となる配列を可変な状態で共有できます。 -既定では常に、非共有時は可変、共有時は読み取り専用です。 - -```java -struct str { - - // Add a string to the string, possibly growing - val add = { str str -> - val self = this; - for( int i=0; i - if( len >= # ) return copy(# ? #*2 : 1).add(e); - [size++] = e; - return this; - }; - - // Copy 'this' to a new larger size - val copy = { int sz2 -> - val v2 = new str[sz2]; - for( int i=0; i sys.libc.write(1/*stdout*/,[]/*array base as argument to C*/,len); return this; } - - u32 len; // In-use size - u32 #; // Max length is 4Gig, although variants can request smaller lengths - u8 []; // Character data -}; -``` - -### Final な文字列 - -**不変**な文字列を意図しており、**安全な**文字列の基礎にも使えるかもしれません。 -一度に全体を作成する必要があり、おそらく防御的コピーも必要になります。 - -```java -struct sstr { - // Possible static call syntax; no references to "this" - val make { str str -> new sstr[str#,str.at] }; - - // Array contents are immutable. - // Still figuring out good syntax for this. - u8 #; - u8 [~]; // Middlin '~'? Makes primitive array contents *immutable* and requires constructor syntax -}; - -// Construction requires a function that produces the array contents. -// Here we are defining a defensive copy over `buf`. -sstr safe = new sstr[buf.len,{ int idx -> buf[idx]; }]; -sstr safe = sstr.make("abc"); // Defensive copy is made -``` - -### 拡張可能な文字列(StringBuilder または StringBuffer) - -この API は `StringBuilder` スタイルの代替としてそのまま使えることを意図しており、 -使うたびに間接参照が1つ増えます。 - -```java -struct xstr { - !str !_str; // The extra indirection is here - val add = { str str -> _str = str.add2(str); }; - val write = { int fd -> _str.write(fd); }; -}; -``` - -### Unicode 文字列 - -この API は、通常の `str` の上で Unicode の文字を操作できるようにすることを意図しています。 - -```java -struct ustr { - // Assuming idx is at the start of a character, return the character - // as a 32b integer. Returns junk integer if not at a character start. - // For all ASCII strings this will amount to a simple byte load. - // For bytes with high order bits set, this may read 1-4 characters. - val at = { int idx -> ... }; -}; -// Unicode character iterator -struct ucharator { -// Return successive unicode character codes -}; -``` - -### 「C」文字列 - -ゼロ終端の文字列ですが、長さを直接取得できる必要があります。 - -```java -struct cstr { - u8 #; // length including the trailing zero - u8[]; // always ends in a zero byte; suitable for direct passing to C string functions -}; -``` - -### 「german string」:レジスタに格納できる非常に短い文字列 - -メモリ内では、長さを表す1バイト(3ビット?)に続いて0〜7文字を格納し、最大8文字です。 -64ビットのレジスタに収まります。 - -```java -struct gstr { // aka germanString, or blend string and register "streg" - u3 #; // Size is 0-7 bytes??? - u8 []; // Up to 7 bytes -} -// Using inlined object (see below). All these strings are short and are -// represented as packed integers in a 64b register. -*gstr prize1 = "gold"; -*gstr prize2 = "silver"; -*gstr prize3 = "bronze"; - -``` - -### Main は `val main = { str[] args -> ...}` になる - -## 構造体のインライン化 - -構造体は通常、参照として扱いますが、「内容(contents of)」と読む `*` 演算子を使って -値として扱う形へ変換できます(この名前は、たとえば `inline` に変えるかもしれません)。 - -これは名前空間の変更だけです。内部の構造体の寿命を完全に消費しない限り、そのアドレスは取得できません。 -「外部への流出」は認めません。 - -```java -// 2 64-bit words, no other overheads -struct Complex { f64 x,y; val len = { ->Math.sqrt(x*x+y*y); }; }; - -// Current Simple rules: always by-reference -struct ByRef { - !Complex !c; // 4-byte pointer to a Complex -}; -print(new ByRef.c.y); // Lookup requires 1 extra memory load from ref to c - -// New behavior: by value (inlining a struct) -// The '*' syntax indicator can be something else, e.g. a keyword "inline" -// I am pronouncing '*' as "contents of" -struct ByValue { - *!Complex !c; // c is inlined, full 16 bytes into ByValue -}; -print(new ByValue.c.y); // x,y inlined into ByValue, no extra memory load - -// Mixing Refs and Struct Values. Basically, a ref can be converted -// to a value by taking the "contents of" the ref, and values cannot -// be *converted* to a ref, although they can be copied over a ref. -ref. c = val.c; // Error, mixing refs and values -ref.*c = val.c; // Allowed, whole structure copy. Does not allocate, requires ref.c not-null -val. c = ref.c; // Error, mixing refs and values -val. c = *ref.c; // Allowed, whole structure copy -ref. c = ref.c; // Allowed, pointer copy -val. c = val.c; // Allowed, whole structure copy. -val *c = val.c; // Error, cannot take "contents of" a value - -// Alternative syntax, to avoid the "contents of" being on LHS and field applying to being on RHS: -ref.c = val.*c; // Assign into ref.c the "contents of" val.c - -// Arrays of inlined structures -var ary = new *Complex[99]; // Array of 99 !Complex !objects, inlined - -// Calling methods has the same syntax -ref.c.len(); -val.c.len(); - -// Function arguments use the same typing, so can pass-by-value -val math.sin = { *Complex c -> ... }; // Passes a complex by value -math.sin(ref.*c); // Requires de-reference to pass by value -math.sin(val. c); // Pass by value - -``` - -## ほかの章のロードマップ - -`&&` と `||`。 -`int` を `i32` に縮小する。 -`TypeMemPtr` を4バイトに縮小する。`mmap` を使い、ヒープを下位4Gの領域に置く。 -パーサーの既定の for ループ構築、または部分的なループ剥離。 -`for( init; test; next ) body` は、次のようになる。 -```java -{ init; // Normal scope entry to bound lifetime of index variable -if( !test ) { // Zero-trip count test - do { - body; - next; - } while( test ); // Exit test at loop bottom by default -} }; -``` - -## `&&` と `||` - -論理演算子 &&(AND)と ||(OR)は短絡評価を行います。 -最初の条件だけで結果が決まるときは、第2の条件の評価を省略できます。 - -- `&&` は最初のオペランドが偽なら評価を止めます。 -- `||` は最初のオペランドが真なら評価を止めます。 - -これらは制御フローを読みやすくする糖衣構文であり、実行モデルに新しいノードを作りません。 - -`&&` と `||` の構文は、制御フローだけを変える単純な糖衣構文であり、新しいノードを導入しません。 - -次の例を考えます。 -```java -int a = 1; -int b = 0; - -if(a++ || b++ ) { - if(b == 0 && a == 2) { - sys.io.p("Or"); - } -} else{ - sys.io.p("And"); -} -return 0; -``` - -- `a++` は1(真)と評価されるので、`b++` は評価されません。 -- その結果、`b` は0のままで、`a` は2になり、「Or」が表示されます。 - -```java -int a = 1; -int b = 1; - -int x=1; -int y=1; -int z=0; - -int g = x++ && y++ && z++; -... -``` - -この例では、次のようになります。 - -- `x++` は真(1)なので、`y++` を評価します。それも真です。 -- 続いて `z++` を評価します。これは偽(0)です。 -- `&&` はすべての条件が真であることを要求するため、最終結果 `g` は0になります。 -- 偽になるオペランドまでのすべてのオペランドを評価するため、`x`、`y`、`z` はすべてインクリメントされます。 diff --git a/chapter28b/ROADMAP.md b/chapter28b/ROADMAP.md deleted file mode 100644 index b5647587..00000000 --- a/chapter28b/ROADMAP.md +++ /dev/null @@ -1,523 +0,0 @@ -## Separate Compilation - -English | [日本語](ROADMAP.ja.md) - - -How to handle unknown forward ref? -No H-M, so no unification. -Demand no forward refs beyond functions... which will provide immediate signatures when def'd. - -Plan A: Remove FRefNode; fix all my bugs. -Fail A: I want mutual co-recurusion to work -Example: `val even = { int x -> x ? odd(x-1) : true; }; val odd = { int x -> x ? even(x-1) : false; };` - -Plan B: Require types ordered, but not any other fcn. `new T` can complain, -but not `fref.field` or `fref()` or `fref op fref` or `fref[]` - -Requires "lifting" Type.BOTTOM to the parser requirements everywhere. -So loading a field from an FRef requires: lift the FREF to a -TMP-to-TSTRUCT-with-FIELD... actually, just locally assume FREF will become -correct. Can't Lift it, no access, since type comes from random code. -TMP might be nullable (should error later). -TSTRUCT can/will be unnamed. Implies ALL TSTRUCT is unnamed. - -Issue is some unknown/remote/external/forward-ref. - -Allowing an FRef *at all* means everybody has to deal with seeing an FRef Type. -Allowing it for functions in same scope allow the above odd/even case . -Allowing it for structs in the same scope allows for co-recursive structs. -Promoting out-of-scope attempts the external lookup, then fails. - -Random junk usage: `sys.fld`. Looking up `sys` fails, now has to -guess: fref is ok, will be defined shortly... OR extern lookup now. -Then some usage delays trouble: -```java -// Extern or Future `sys` being returned. -val foo { -> return sys; } - -// foo() returns FRef, so Bottom, so the `.bar` has no type -// to do field lookups -val main { arg -> foo().bar } - -// HERE: Parser finds `sys` OR NOT?!?!?! -val sys??? = user_stuff....; - -``` - -Which gets to: parser never complains, builds SSA like a blind AST, -just wires up a graph with bad types all around. Requires: No Types -to guide parser! Just Syntax! - - (Obvious minor fail: widen floats- or-not) Fix: insert e.g. int-oper, return - type is MEET of Int,Float until both inputs are isa-Int and cannot lift to be - isa-Float - - Possible method call fail: - UNKNOWN_STRUCT_BOT.UNKNOWN_FIELD ( ARGS ); // Insert SELF OR NOT? - Possible fix: always assume a SELF arg, which is null for provable statics. - Optimization: constant parms get dropped from sig? *Constant* parms - must be constant from *Parser*, or else no unknown callers (so local opts). - Possible fix: SELF arg is *last* not *first*, easier to drop if dead? - - Load drops ConFldOff, keeps name. - Load keeps index unscaled, has index input, which is null for structs. - After Ptr Base is *closed*, base layout can happen, can fold index math. - - Load(ctrl, base, null ); // field name internal - - Load(ctrl, base, index_math ); // field name=='[]' - - Store(ctrl, base, null , val); - - FAIL: No Alias Info! - - -Plan C: - FRefs allowed for direct calls `odd()`, and for Types. - All other cases must *lift*. - - -## Unifying Structs and Arrays - -The idea is that structs have fields indexed by names, and arrays have fields -indexed by numbers, and these ideas are compatible with each other. This idea -has been used by the C language for a long time - an array can follow a normal -struct C and can index it with the usual array syntax. - -The alternative, using a field to hold a pointer to an array, exchanges some -flexibility for an extra indirection. The obvious flexibility allows swapping -the array out (generally for a larger one) and this is the basis of very common -`Vector` or `ArrayList` generic containers. - - -```java -struct str { - int hash; // A cache of the strings hash code - u32 #; // The array length - u8 []; // Array of bytes -}; - -str X = "abc"; -print(X.hash); // Read the hash field -X[0]=='a'; // Read array element 0 -X#; // Length of the array - -``` - -Here, the field named `#` holds the array length and the field named `[]` is -the actual array, which follows the other fields directly in memory. -Here is another example for variable length array: - -```java -struct vecInt { - u32 size; // Actual number of elements - u32 #; // The array length or capacity - int []; // Array of integers. -}; -``` - -The obvious limit here is that the array cannot be directly resized; it is -literally in the same memory block as the leading fields. Such a `vecInt` can -be *re-allocated* to a new larger `vecInt`, but the original `vecInt` will be -reclaimed - you cannot use the same `vecInt` reference forever. - -Any number of named fields are allowed: - -```java -struct Class { - !str !className; - !str !professor; - int time; - int credits; - !Class !prerequisite; - u16 #; // Limit of 65535 students per class - Student []; -}; -``` - -Or self-reference: - -```java -struct NTree { - Some val; - u8 #; // Length is 0-255 - NTree []; // More NTrees -}; -``` - -The syntax rules are: -- the last field is named `[]` and can be of any type. -- the second-to-last field is named `#` and must be some unsigned integer type - representing the maximum array length. -- may require a leading space in front of ` []` - - - -### Constructors and Arrays - -The allocation includes the array length, and can include a constructor: -`new NTree{val=17;}[2];` - -The constructor is optional, the array length is not. - -Optional function for initializing arrays, allows for write-once final arrays: -`new u8[buffer#,{ u32 idx -> buffer[idx].toUpperCase() }]` - - - -### Changing array max length - -An issue for large numbers of range-checked small arrays is that reserving a -full 4 bytes for array length can substantially increase the array overhead. -Simple allows for arrays to have smaller max lengths, although these are -treated as a different type than arrays with different max lengths. - -```java -struct x0 { u8 #; u8[]; }; // Array limited to 0-255 length -struct x1 { u16 #; u8[]; }; // Array limited to 0-65535 length -struct x2 { u32 #; u8[]; }; // -struct x3 { u64 #; u8[]; }; // - -x0 x = "abc"; // 4 bytes total: [3, 'a', 'b', 'c'] -x1 y = "def"; // 6 bytes total: [3, 0 , 'd', 'e', 'f', 0,]; 1 pad byte to acheieve 2-byte alignment -x = y; // ERROR, "x1 is not x0", no auto-widening -x += y; // OK, 7 bytes total: [6, 'a', 'b', 'c', 'd', 'e', 'f'] -y += x; // OK, 8 bytes total: [6, 0 , 'd', 'e', 'f', 'a', 'b', 'c'] - -x += "VeryLongString.... ....255_chars"; // Runtime RangeCheck - -// Explicit conversion to widen string -y = "" + x; -``` - - -### Two flavors of extendable arrays/strings: an extra indirection or not - -With an extra indirection you get e.g. Java `ArrayList` or C++ `Vector`. - -Without, then any call which extends the extendable array return a potentially -new object, only growing as needed. - -```java -val vec1 = new vecInt[0].add(2); // len=1, capacity=1 -val vec2 = vec1.add(3); // NEW !vecInt !returned, only is deleted; len=2; capacity=2; -vec1[0]; // ERROR, vec1 has been freed by call to `vec1.add(3)` -vec2[0]; // OK -vec2[1]; // OK -vec2[2]; // Runtime error, AIOOBE -``` - - -## A String Implementation - -Default strings have names like "str", "cstr", "ustr" or such. - -Always unicode8 with explicit u8 manipulations. Unicode "characters" will come -as function calls over the base implementation, probably in another string class. - -## Default string - -Efficiently growable via concantenation. Supports a variety of IO/printf functions. -The underlying array can be shared mutable if you ask for this. -The defaults will always be private mutable and read-only shared. - -```java -struct str { - - // Add a string to the string, possibly growing - val add = { str str -> - val self = this; - for( int i=0; i - if( len >= # ) return copy(# ? #*2 : 1).add(e); - [size++] = e; - return this; - }; - - // Copy 'this' to a new larger size - val copy = { int sz2 -> - val v2 = new str[sz2]; - for( int i=0; i sys.libc.write(1/*stdout*/,[]/*array base as argument to C*/,len); return this; } - - u32 len; // In-use size - u32 #; // Max length is 4Gig, although variants can request smaller lengths - u8 []; // Character data -}; -``` - - -### A Final String - -Intended to be a **immutable** string, possibly used as a base for a **secure** -string. This needs to be created all at once, and probably requires a -defensive copy. - -```java -struct sstr { - // Possible static call syntax; no references to "this" - val make { str str -> new sstr[str#,str.at] }; - - // Array contents are immutable. - // Still figuring out good syntax for this. - u8 #; - u8 [~]; // Middlin '~'? Makes primitive array contents *immutable* and requires constructor syntax -}; - -// Construction requires a function that produces the array contents. -// Here we are defining a defensive copy over `buf`. -sstr safe = new sstr[buf.len,{ int idx -> buf[idx]; }]; -sstr safe = sstr.make("abc"); // Defensive copy is made -``` - - -### A Extendable String (aka StringBuilder or StringBuffer) - -This API is intended to be a drop-in for a `StringBuilder` style, and takes an -extra indirection with each usage. - -```java -struct xstr { - !str !_str; // The extra indirection is here - val add = { str str -> _str = str.add2(str); }; - val write = { int fd -> _str.write(fd); }; -}; -``` - -### A Unicode String - -This API is intended to support unicode character manipulation over a plain `str` - -```java -struct ustr { - // Assuming idx is at the start of a character, return the character - // as a 32b integer. Returns junk integer if not at a character start. - // For all ASCII strings this will amount to a simple byte load. - // For bytes with high order bits set, this may read 1-4 characters. - val at = { int idx -> ... }; -}; -// Unicode character iterator -struct ucharator { -// Return successive unicode character codes -}; -``` - -### A "C" string - -A zero-terminated string, but the length has to be available directly - -```java -struct cstr { - u8 #; // length including the trailing zero - u8[]; // always ends in a zero byte; suitable for direct passing to C string functions -}; -``` - -### A "german string": a very short string that can exist in a register - -Length in memory is 1 byte (3 bits?) of length, then 0-7 chars; max 8 chars. -Fits in a 64 bit register. - -```java -struct gstr { // aka germanString, or blend string and register "streg" - u3 #; // Size is 0-7 bytes??? - u8 []; // Up to 7 bytes -} -// Using inlined object (see below). All these strings are short and are -// represented as packed integers in a 64b register. -*gstr prize1 = "gold"; -*gstr prize2 = "silver"; -*gstr prize3 = "bronze"; - -``` - -### Main becomes `val main = { str[] args -> ...}` - - -## Structs can be inlined - -Structs are normally by-reference, but can be converted to by-value by using -the `*` operator, pronounced "contents of" (this name might be changed to -e.g. `inline`). - -This is a name-space change only, you cannot take the address of the internal -struct without entirely consuming its lifetime. No "escaping". - -```java -// 2 64-bit words, no other overheads -struct Complex { f64 x,y; val len = { ->Math.sqrt(x*x+y*y); }; }; - -// Current Simple rules: always by-reference -struct ByRef { - !Complex !c; // 4-byte pointer to a Complex -}; -print(new ByRef.c.y); // Lookup requires 1 extra memory load from ref to c - -// New behavior: by value (inlining a struct) -// The '*' syntax indicator can be something else, e.g. a keyword "inline" -// I am pronouncing '*' as "contents of" -struct ByValue { - *!Complex !c; // c is inlined, full 16 bytes into ByValue -}; -print(new ByValue.c.y); // x,y inlined into ByValue, no extra memory load - -// Mixing Refs and Struct Values. Basically, a ref can be converted -// to a value by taking the "contents of" the ref, and values cannot -// be *converted* to a ref, although they can be copied over a ref. -ref. c = val.c; // Error, mixing refs and values -ref.*c = val.c; // Allowed, whole structure copy. Does not allocate, requires ref.c not-null -val. c = ref.c; // Error, mixing refs and values -val. c = *ref.c; // Allowed, whole structure copy -ref. c = ref.c; // Allowed, pointer copy -val. c = val.c; // Allowed, whole structure copy. -val *c = val.c; // Error, cannot take "contents of" a value - -// Alternative syntax, to avoid the "contents of" being on LHS and field applying to being on RHS: -ref.c = val.*c; // Assign into ref.c the "contents of" val.c - -// Arrays of inlined structures -var ary = new *Complex[99]; // Array of 99 !Complex !objects, inlined - -// Calling methods has the same syntax -ref.c.len(); -val.c.len(); - -// Function arguments use the same typing, so can pass-by-value -val math.sin = { *Complex c -> ... }; // Passes a complex by value -math.sin(ref.*c); // Requires de-reference to pass by value -math.sin(val. c); // Pass by value - -``` - - - -## RoadMap for other chapters - -`&&` and `||` -Drop `int` to `i32`. -Drop `TypeMemPtr` to 4 bytes; using `mmap` to make heap in low 4G. -Default parser for-loop construction, or partial peel. - `for( init; test; next ) body` -becomes: -```java -{ init; // Normal scope entry to bound lifetime of index variable -if( !test ) { // Zero-trip count test - do { - body; - next; - } while( test ); // Exit test at loop bottom by default -} }; -``` - -## `&&` and `||` - -The logical operators && (AND) and || (OR) are short-circuiting, meaning they may skip evaluating the second condition if the first one already determines the result: - -- `&&` stops if the first operand is false. -- `||` stops if the first operand is true. - -They are syntactic sugar—used for cleaner control flow—but they don't create new nodes in the execution model. - -The `&&` and `||` constructs are simple syntactic sugars that only modify the control flow and do not -introduce new nodes. - -Consider this example: -```java -int a = 1; -int b = 0; - -if(a++ || b++ ) { - if(b == 0 && a == 2) { - sys.io.p("Or"); - } -} else{ - sys.io.p("And"); -} -return 0; -``` -- `a++` evaluates to 1 (true), so `b++` is not evaluated. -- As a result, `b` stays 0, `a` becomes 2, and "Or" is printed. - -```java -int a = 1; -int b = 1; - -int x=1; -int y=1; -int z=0; - -int g = x++ && y++ && z++; -... -``` -Here: -- `x++` is true (1), so it evaluates `y++`, which is also true. -- Then it evaluates `z++`, which is false (0). -- Since `&&` requires all conditions to be true, the final result `g` is 0. -- All operands up to the false one are evaluated, so `x`, `y`, and `z` are all incremented. - -## Class initialization and compiler follow-ups - -### Entry arguments - -Replace the integer initializer argument with an argument array. The selected -entry class receives a non-null array, empty when there are no arguments; -other class initializers receive null. Coordinate the parser, entry signature, -runtime driver, and separately compiled interfaces. - -### Pre-initialize classes from ELF data - -Prove when a class's entire initialization can be represented by ELF static -data and relocations, with no remaining runtime effects. Emit its initial -contents and start its `$init` flag as true, so no initializer call is needed. -Carry that fact through separate compilation so importing compilers can remove -checks too. A constant field alone is not proof that the whole class can be -pre-initialized; I/O, argument-dependent work, and other observable effects -still require execution. Preserve any dynamic parent requirement, and do not -let cyclic dependencies justify their own pre-initialization. - -Mutable fields may have static initial contents without becoming constants. -Choose read-only storage only when no runtime writes remain. Static reference -cycles can use relocations without requiring a dynamic initialization cycle. - -For a wholly immutable, pre-initialized class, eliminate the mutable `$init` -state as well as the checks so the class image can reside in ROM. The native -function thunks preserve static initialization of function fields. - -### Compact code and data arenas - -Keep four-byte Simple references into bounded code and data arenas; the arenas -need not overlap or live near zero. Choose absolute addresses versus offsets -from an arena base when implementing placement and indirect calls. Native -function thunks can occupy the code arena while native libraries live elsewhere. -The current thunk implementation uses the existing low-address executable; -ordinary data pointers still occupy eight bytes. - -Give full-width native pointers separate types and foreign lifetime contracts. -Opaque device addresses may need to be passed through without CPU dereference. -Simple object lifetimes should be managed automatically without a GC; -ownership, borrowing, cycles, and native retention still need design. Compact -storage alone does not establish those rules. Preserve static class images and -explicit native boundary conversions when choosing the arena representation. - -### CFG frequency estimates - -After lowering and loop-tree construction, estimate block frequencies for GCM -and code layout. Treat initialization and known-failure paths as rare; use -bounded loop-trip estimates and branch probabilities when no profile is -available. Keep estimates consistent with control flow and shared between -scheduling and layout. These are backend estimates, not ideal-IR types. - -### Constant instance-field storage - -When a final instance field has the same constant value in every instance, -fold accesses or store the value on the class object and omit the instance -slot. Preserve field-access semantics and public function reachability: -externally accessible function fields remain callable regardless of storage. diff --git a/chapter28b/ainotes.txt b/chapter28b/ainotes.txt index 625acddc..c0b03a4d 100644 --- a/chapter28b/ainotes.txt +++ b/chapter28b/ainotes.txt @@ -1,4 +1,8 @@ +Historical design notes from the former combined Chapter 25, now Chapter 28b. +Current status and remaining work are in ../docs/stage-audit.md and +../docs/chapter-backports.md. The original intent below is preserved. + Meta-info: I intend to keep extending and re-editing this "ainotes.txt" file so I can reprompt the you (the AI) between AI restarts, As such this file will contain a mix of high-level design decisions, goals, intents and wisdom, and diff --git a/chapter28b/docs/25-grammar.ja.md b/chapter28b/docs/25-grammar.ja.md deleted file mode 100644 index 9e9fb820..00000000 --- a/chapter28b/docs/25-grammar.ja.md +++ /dev/null @@ -1,175 +0,0 @@ -# 第25章の文法 - -[English](25-grammar.md) | 日本語 - -```antlrv4 -grammar SimpleLanguage; - -// Name lookup, assignable operands, type compatibility, and access permissions -// are checked by the compiler in addition to these syntax rules. -// A file is a compilation unit; its path supplies its namespace. -// Qualified names resolve nested types and other units without an import keyword. -program : statement* EOF ; - -block : '{' statement* '}' ; - -statement - : block - | returnStatement - | ifStatement - | whileStatement - | forStatement - | breakStatement - | continueStatement - | structDeclaration - | declaration ';' - | assignment ';' - | ';' - ; - -returnStatement : 'return' assignment ';' ; -ifStatement : 'if' '(' assignment ')' statement ('else' statement)? ; -whileStatement : 'while' '(' assignment ')' statement ; -breakStatement : 'break' ';' ; -continueStatement : 'continue' ';' ; - -forStatement - : 'for' '(' (declaration | assignment)? ';' assignment? ';' assignment? ')' statement - ; - -structDeclaration : 'struct' IDENTIFIER '{' structMember* '}' ';' ; -structMember : constructorDeclaration | methodDeclaration | statement ; - -// The constructor name must match the enclosing struct's name. -constructorDeclaration : 'new' IDENTIFIER '=' functionExpression ';' ; - -// A method is an ordinary fixed function binding in a struct definition. -// The compiler supplies self; it is not written in parameterList. -// Function types and expressions both receive their implicit receiver here. -methodDeclaration : 'val' bindingModifier? IDENTIFIER '=' functionExpression ';' ; - -declaration : declarationType binding (',' binding)* ; -declarationType : type | 'var' | 'val' ; -binding : bindingModifier? IDENTIFIER ('=' initializer)? ; -bindingModifier : '!' | '~' ; -// A declaration initializer consisting of the string "C" declares an extern -// symbol: a function, or explicit numeric native storage. Ordinary strings -// elsewhere are array-valued expressions. -initializer : assignment ; - -// The prefix qualifies the named struct reference, not an enclosing array. -// Each [] / [~] suffix qualifies its own array layer. ? requires a reference. -type - : functionType - | primitiveType typeSuffix* - | accessModifier? typeName typeSuffix* - ; -accessModifier : '!' | '~' ; -typeSuffix : '?' | '[]' | '[~]' ; -typeName : IDENTIFIER ('.' IDENTIFIER)* ; - -primitiveType - : 'int' | 'i8' | 'i16' | 'i32' | 'i64' - | 'u1' | 'u8' | 'u16' | 'u32' | 'byte' | 'bool' - | 'flt' | 'f32' | 'f64' - ; - -assignment : expression (assignmentOperator assignment)? ; -assignmentOperator - : '=' | '+=' | '-=' | '*=' | '/=' | '&=' | '|=' | '^=' - | '<<=' | '>>=' | '>>>=' - ; - -expression : logicalExpression ('?' assignment (':' assignment)?)? ; - -// Both logical operators short-circuit and associate to the right here. -logicalExpression : bitwiseExpression (('&&' | '||') logicalExpression)? ; - -bitwiseExpression - : equalityExpression (('&' | '|' | '^') equalityExpression)* - ; - -equalityExpression : comparisonExpression (('==' | '!=') comparisonExpression)* ; - -// Chained comparisons test adjacent operands and short-circuit. A chain must -// keep its direction; equality has lower precedence and does not join a chain. -comparisonExpression - : shiftExpression - ( (('<' | '<=') shiftExpression)+ | (('>' | '>=') shiftExpression)+ )? - ; - -shiftExpression - : additiveExpression (('<<' | '>>' | '>>>') additiveExpression)* - ; - -additiveExpression - : multiplicativeExpression (('+' | '-') multiplicativeExpression)* - ; - -multiplicativeExpression - : unaryExpression (('*' | '/') unaryExpression)* - ; - -unaryExpression - : ('-' | '!') unaryExpression - | updateOperator IDENTIFIER - | postfixExpression - ; - -// Prefix updates require a local name; postfix updates also allow fields -// and array elements. All updates require an assignable operand. -updateOperator : '++' | '--' ; -postfixExpression : primaryExpression postfixSuffix* updateOperator? ; -postfixSuffix : '.' IDENTIFIER | '[' assignment ']' | '#' | callSuffix | methodCallSuffix ; - -// For a fixed function-valued member, object.name(args) passes object as self. -// This overlaps ordinary field selection followed by a call syntactically; -// name/type resolution determines which call form applies. -methodCallSuffix : '.' IDENTIFIER callSuffix ; - -primaryExpression - : INTEGER_LITERAL - | FLOAT_LITERAL - | STRING_LITERAL - | CHARACTER_LITERAL - | 'true' - | 'false' - | 'null' - | IDENTIFIER - | '(' assignment ')' - | newExpression - | functionExpression - ; - -// A function is an expression bound with an ordinary declaration. -// Its last statement supplies the implicit result; return can exit earlier. -functionExpression : '{' parameterList? '->' statement* '}' ; -parameterList : (parameter ','?)+ ; -parameter : type bindingModifier? IDENTIFIER ; - -// Function types have unnamed, space-separated argument types. -// {int} is the zero-argument type; its function expression still uses ->. -functionType - : '{' type+ '->' type '}' '?'? - | '{' type '}' '?'? - ; - -callSuffix : '(' argumentList? ')' ; -argumentList : assignment (',' assignment)* ','? ; - -// Allocation invokes the declared constructor; inline initializer blocks from -// earlier chapters are replaced by constructor arguments. -newExpression : 'new' type ('[' assignment ']' | callSuffix)? ; - -INTEGER_LITERAL : '0' | [1-9] DIGIT* ; -FLOAT_LITERAL : DIGIT+ ('.' DIGIT* ('e' DIGIT+)? | 'e' '-'? DIGIT+) ; -STRING_LITERAL : '"' (ESCAPE | ~["\\])* '"' ; -CHARACTER_LITERAL : '\'' (ESCAPE | ~['\\]) '\'' ; -fragment ESCAPE : '\\' [0ntr\\'"] ; -IDENTIFIER : NON_DIGIT (NON_DIGIT | DIGIT)* ; -fragment NON_DIGIT : [a-zA-Z_] ; -fragment DIGIT : [0-9] ; -WHITESPACE : [ \t\r\n]+ -> skip ; -LINE_COMMENT : '//' ~[\r\n]* -> skip ; -BLOCK_COMMENT : '/*' .*? '*/' -> skip ; -``` diff --git a/chapter28b/docs/25-grammar.md b/chapter28b/docs/25-grammar.md deleted file mode 100644 index 065cf051..00000000 --- a/chapter28b/docs/25-grammar.md +++ /dev/null @@ -1,175 +0,0 @@ -# Grammar for Chapter 25 - -English | [日本語](25-grammar.ja.md) - -```antlrv4 -grammar SimpleLanguage; - -// Name lookup, assignable operands, type compatibility, and access permissions -// are checked by the compiler in addition to these syntax rules. -// A file is a compilation unit; its path supplies its namespace. -// Qualified names resolve nested types and other units without an import keyword. -program : statement* EOF ; - -block : '{' statement* '}' ; - -statement - : block - | returnStatement - | ifStatement - | whileStatement - | forStatement - | breakStatement - | continueStatement - | structDeclaration - | declaration ';' - | assignment ';' - | ';' - ; - -returnStatement : 'return' assignment ';' ; -ifStatement : 'if' '(' assignment ')' statement ('else' statement)? ; -whileStatement : 'while' '(' assignment ')' statement ; -breakStatement : 'break' ';' ; -continueStatement : 'continue' ';' ; - -forStatement - : 'for' '(' (declaration | assignment)? ';' assignment? ';' assignment? ')' statement - ; - -structDeclaration : 'struct' IDENTIFIER '{' structMember* '}' ';' ; -structMember : constructorDeclaration | methodDeclaration | statement ; - -// The constructor name must match the enclosing struct's name. -constructorDeclaration : 'new' IDENTIFIER '=' functionExpression ';' ; - -// A method is an ordinary fixed function binding in a struct definition. -// The compiler supplies self; it is not written in parameterList. -// Function types and expressions both receive their implicit receiver here. -methodDeclaration : 'val' bindingModifier? IDENTIFIER '=' functionExpression ';' ; - -declaration : declarationType binding (',' binding)* ; -declarationType : type | 'var' | 'val' ; -binding : bindingModifier? IDENTIFIER ('=' initializer)? ; -bindingModifier : '!' | '~' ; -// A declaration initializer consisting of the string "C" declares an extern -// symbol: a function, or explicit numeric native storage. Ordinary strings -// elsewhere are array-valued expressions. -initializer : assignment ; - -// The prefix qualifies the named struct reference, not an enclosing array. -// Each [] / [~] suffix qualifies its own array layer. ? requires a reference. -type - : functionType - | primitiveType typeSuffix* - | accessModifier? typeName typeSuffix* - ; -accessModifier : '!' | '~' ; -typeSuffix : '?' | '[]' | '[~]' ; -typeName : IDENTIFIER ('.' IDENTIFIER)* ; - -primitiveType - : 'int' | 'i8' | 'i16' | 'i32' | 'i64' - | 'u1' | 'u8' | 'u16' | 'u32' | 'byte' | 'bool' - | 'flt' | 'f32' | 'f64' - ; - -assignment : expression (assignmentOperator assignment)? ; -assignmentOperator - : '=' | '+=' | '-=' | '*=' | '/=' | '&=' | '|=' | '^=' - | '<<=' | '>>=' | '>>>=' - ; - -expression : logicalExpression ('?' assignment (':' assignment)?)? ; - -// Both logical operators short-circuit and associate to the right here. -logicalExpression : bitwiseExpression (('&&' | '||') logicalExpression)? ; - -bitwiseExpression - : equalityExpression (('&' | '|' | '^') equalityExpression)* - ; - -equalityExpression : comparisonExpression (('==' | '!=') comparisonExpression)* ; - -// Chained comparisons test adjacent operands and short-circuit. A chain must -// keep its direction; equality has lower precedence and does not join a chain. -comparisonExpression - : shiftExpression - ( (('<' | '<=') shiftExpression)+ | (('>' | '>=') shiftExpression)+ )? - ; - -shiftExpression - : additiveExpression (('<<' | '>>' | '>>>') additiveExpression)* - ; - -additiveExpression - : multiplicativeExpression (('+' | '-') multiplicativeExpression)* - ; - -multiplicativeExpression - : unaryExpression (('*' | '/') unaryExpression)* - ; - -unaryExpression - : ('-' | '!') unaryExpression - | updateOperator IDENTIFIER - | postfixExpression - ; - -// Prefix updates require a local name; postfix updates also allow fields -// and array elements. All updates require an assignable operand. -updateOperator : '++' | '--' ; -postfixExpression : primaryExpression postfixSuffix* updateOperator? ; -postfixSuffix : '.' IDENTIFIER | '[' assignment ']' | '#' | callSuffix | methodCallSuffix ; - -// For a fixed function-valued member, object.name(args) passes object as self. -// This overlaps ordinary field selection followed by a call syntactically; -// name/type resolution determines which call form applies. -methodCallSuffix : '.' IDENTIFIER callSuffix ; - -primaryExpression - : INTEGER_LITERAL - | FLOAT_LITERAL - | STRING_LITERAL - | CHARACTER_LITERAL - | 'true' - | 'false' - | 'null' - | IDENTIFIER - | '(' assignment ')' - | newExpression - | functionExpression - ; - -// A function is an expression bound with an ordinary declaration. -// Its last statement supplies the implicit result; return can exit earlier. -functionExpression : '{' parameterList? '->' statement* '}' ; -parameterList : (parameter ','?)+ ; -parameter : type bindingModifier? IDENTIFIER ; - -// Function types have unnamed, space-separated argument types. -// {int} is the zero-argument type; its function expression still uses ->. -functionType - : '{' type+ '->' type '}' '?'? - | '{' type '}' '?'? - ; - -callSuffix : '(' argumentList? ')' ; -argumentList : assignment (',' assignment)* ','? ; - -// Allocation invokes the declared constructor; inline initializer blocks from -// earlier chapters are replaced by constructor arguments. -newExpression : 'new' type ('[' assignment ']' | callSuffix)? ; - -INTEGER_LITERAL : '0' | [1-9] DIGIT* ; -FLOAT_LITERAL : DIGIT+ ('.' DIGIT* ('e' DIGIT+)? | 'e' '-'? DIGIT+) ; -STRING_LITERAL : '"' (ESCAPE | ~["\\])* '"' ; -CHARACTER_LITERAL : '\'' (ESCAPE | ~['\\]) '\'' ; -fragment ESCAPE : '\\' [0ntr\\'"] ; -IDENTIFIER : NON_DIGIT (NON_DIGIT | DIGIT)* ; -fragment NON_DIGIT : [a-zA-Z_] ; -fragment DIGIT : [0-9] ; -WHITESPACE : [ \t\r\n]+ -> skip ; -LINE_COMMENT : '//' ~[\r\n]* -> skip ; -BLOCK_COMMENT : '/*' .*? '*/' -> skip ; -``` diff --git a/chapter28b/docs/28b-grammar.ja.md b/chapter28b/docs/28b-grammar.ja.md new file mode 100644 index 00000000..65944fe2 --- /dev/null +++ b/chapter28b/docs/28b-grammar.ja.md @@ -0,0 +1,175 @@ +# 第28b章の文法 + +[English](28b-grammar.md) | 日本語 + +```antlrv4 +grammar SimpleLanguage; + +// Name lookup, assignable operands, type compatibility, and access permissions +// are checked by the compiler in addition to these syntax rules. +// A file is a compilation unit; its path supplies its namespace. +// Qualified names resolve nested types and other units without an import keyword. +program : statement* EOF ; + +block : '{' statement* '}' ; + +statement + : block + | returnStatement + | ifStatement + | whileStatement + | forStatement + | breakStatement + | continueStatement + | structDeclaration + | declaration ';' + | assignment ';' + | ';' + ; + +returnStatement : 'return' assignment ';' ; +ifStatement : 'if' '(' assignment ')' statement ('else' statement)? ; +whileStatement : 'while' '(' assignment ')' statement ; +breakStatement : 'break' ';' ; +continueStatement : 'continue' ';' ; + +forStatement + : 'for' '(' (declaration | assignment)? ';' assignment? ';' assignment? ')' statement + ; + +structDeclaration : 'struct' IDENTIFIER '{' structMember* '}' ';' ; +structMember : constructorDeclaration | methodDeclaration | statement ; + +// The constructor name must match the enclosing struct's name. +constructorDeclaration : 'new' IDENTIFIER '=' functionExpression ';' ; + +// A method is an ordinary fixed function binding in a struct definition. +// The compiler supplies self; it is not written in parameterList. +// Function types and expressions both receive their implicit receiver here. +methodDeclaration : 'val' bindingModifier? IDENTIFIER '=' functionExpression ';' ; + +declaration : declarationType binding (',' binding)* ; +declarationType : type | 'var' | 'val' ; +binding : bindingModifier? IDENTIFIER ('=' initializer)? ; +bindingModifier : '!' | '~' ; +// A declaration initializer consisting of the string "C" declares an extern +// symbol: a function, or explicit numeric native storage. Ordinary strings +// elsewhere are array-valued expressions. +initializer : assignment ; + +// The prefix qualifies the named struct reference, not an enclosing array. +// Each [] / [~] suffix qualifies its own array layer. ? requires a reference. +type + : functionType + | primitiveType typeSuffix* + | accessModifier? typeName typeSuffix* + ; +accessModifier : '!' | '~' ; +typeSuffix : '?' | '[]' | '[~]' ; +typeName : IDENTIFIER ('.' IDENTIFIER)* ; + +primitiveType + : 'int' | 'i8' | 'i16' | 'i32' | 'i64' + | 'u1' | 'u8' | 'u16' | 'u32' | 'byte' | 'bool' + | 'flt' | 'f32' | 'f64' + ; + +assignment : expression (assignmentOperator assignment)? ; +assignmentOperator + : '=' | '+=' | '-=' | '*=' | '/=' | '&=' | '|=' | '^=' + | '<<=' | '>>=' | '>>>=' + ; + +expression : logicalExpression ('?' assignment (':' assignment)?)? ; + +// Both logical operators short-circuit and associate to the right here. +logicalExpression : bitwiseExpression (('&&' | '||') logicalExpression)? ; + +bitwiseExpression + : equalityExpression (('&' | '|' | '^') equalityExpression)* + ; + +equalityExpression : comparisonExpression (('==' | '!=') comparisonExpression)* ; + +// Chained comparisons test adjacent operands and short-circuit. A chain must +// keep its direction; equality has lower precedence and does not join a chain. +comparisonExpression + : shiftExpression + ( (('<' | '<=') shiftExpression)+ | (('>' | '>=') shiftExpression)+ )? + ; + +shiftExpression + : additiveExpression (('<<' | '>>' | '>>>') additiveExpression)* + ; + +additiveExpression + : multiplicativeExpression (('+' | '-') multiplicativeExpression)* + ; + +multiplicativeExpression + : unaryExpression (('*' | '/') unaryExpression)* + ; + +unaryExpression + : ('-' | '!') unaryExpression + | updateOperator IDENTIFIER + | postfixExpression + ; + +// Prefix updates require a local name; postfix updates also allow fields +// and array elements. All updates require an assignable operand. +updateOperator : '++' | '--' ; +postfixExpression : primaryExpression postfixSuffix* updateOperator? ; +postfixSuffix : '.' IDENTIFIER | '[' assignment ']' | '#' | callSuffix | methodCallSuffix ; + +// For a fixed function-valued member, object.name(args) passes object as self. +// This overlaps ordinary field selection followed by a call syntactically; +// name/type resolution determines which call form applies. +methodCallSuffix : '.' IDENTIFIER callSuffix ; + +primaryExpression + : INTEGER_LITERAL + | FLOAT_LITERAL + | STRING_LITERAL + | CHARACTER_LITERAL + | 'true' + | 'false' + | 'null' + | IDENTIFIER + | '(' assignment ')' + | newExpression + | functionExpression + ; + +// A function is an expression bound with an ordinary declaration. +// Its last statement supplies the implicit result; return can exit earlier. +functionExpression : '{' parameterList? '->' statement* '}' ; +parameterList : (parameter ','?)+ ; +parameter : type bindingModifier? IDENTIFIER ; + +// Function types have unnamed, space-separated argument types. +// {int} is the zero-argument type; its function expression still uses ->. +functionType + : '{' type+ '->' type '}' '?'? + | '{' type '}' '?'? + ; + +callSuffix : '(' argumentList? ')' ; +argumentList : assignment (',' assignment)* ','? ; + +// Allocation invokes the declared constructor; inline initializer blocks from +// earlier chapters are replaced by constructor arguments. +newExpression : 'new' type ('[' assignment ']' | callSuffix)? ; + +INTEGER_LITERAL : '0' | [1-9] DIGIT* ; +FLOAT_LITERAL : DIGIT+ ('.' DIGIT* ('e' DIGIT+)? | 'e' '-'? DIGIT+) ; +STRING_LITERAL : '"' (ESCAPE | ~["\\])* '"' ; +CHARACTER_LITERAL : '\'' (ESCAPE | ~['\\]) '\'' ; +fragment ESCAPE : '\\' [0ntr\\'"] ; +IDENTIFIER : NON_DIGIT (NON_DIGIT | DIGIT)* ; +fragment NON_DIGIT : [a-zA-Z_] ; +fragment DIGIT : [0-9] ; +WHITESPACE : [ \t\r\n]+ -> skip ; +LINE_COMMENT : '//' ~[\r\n]* -> skip ; +BLOCK_COMMENT : '/*' .*? '*/' -> skip ; +``` diff --git a/chapter28b/docs/28b-grammar.md b/chapter28b/docs/28b-grammar.md new file mode 100644 index 00000000..c7a279fa --- /dev/null +++ b/chapter28b/docs/28b-grammar.md @@ -0,0 +1,175 @@ +# Grammar for Chapter 28b + +English | [日本語](28b-grammar.ja.md) + +```antlrv4 +grammar SimpleLanguage; + +// Name lookup, assignable operands, type compatibility, and access permissions +// are checked by the compiler in addition to these syntax rules. +// A file is a compilation unit; its path supplies its namespace. +// Qualified names resolve nested types and other units without an import keyword. +program : statement* EOF ; + +block : '{' statement* '}' ; + +statement + : block + | returnStatement + | ifStatement + | whileStatement + | forStatement + | breakStatement + | continueStatement + | structDeclaration + | declaration ';' + | assignment ';' + | ';' + ; + +returnStatement : 'return' assignment ';' ; +ifStatement : 'if' '(' assignment ')' statement ('else' statement)? ; +whileStatement : 'while' '(' assignment ')' statement ; +breakStatement : 'break' ';' ; +continueStatement : 'continue' ';' ; + +forStatement + : 'for' '(' (declaration | assignment)? ';' assignment? ';' assignment? ')' statement + ; + +structDeclaration : 'struct' IDENTIFIER '{' structMember* '}' ';' ; +structMember : constructorDeclaration | methodDeclaration | statement ; + +// The constructor name must match the enclosing struct's name. +constructorDeclaration : 'new' IDENTIFIER '=' functionExpression ';' ; + +// A method is an ordinary fixed function binding in a struct definition. +// The compiler supplies self; it is not written in parameterList. +// Function types and expressions both receive their implicit receiver here. +methodDeclaration : 'val' bindingModifier? IDENTIFIER '=' functionExpression ';' ; + +declaration : declarationType binding (',' binding)* ; +declarationType : type | 'var' | 'val' ; +binding : bindingModifier? IDENTIFIER ('=' initializer)? ; +bindingModifier : '!' | '~' ; +// A declaration initializer consisting of the string "C" declares an extern +// symbol: a function, or explicit numeric native storage. Ordinary strings +// elsewhere are array-valued expressions. +initializer : assignment ; + +// The prefix qualifies the named struct reference, not an enclosing array. +// Each [] / [~] suffix qualifies its own array layer. ? requires a reference. +type + : functionType + | primitiveType typeSuffix* + | accessModifier? typeName typeSuffix* + ; +accessModifier : '!' | '~' ; +typeSuffix : '?' | '[]' | '[~]' ; +typeName : IDENTIFIER ('.' IDENTIFIER)* ; + +primitiveType + : 'int' | 'i8' | 'i16' | 'i32' | 'i64' + | 'u1' | 'u8' | 'u16' | 'u32' | 'byte' | 'bool' + | 'flt' | 'f32' | 'f64' + ; + +assignment : expression (assignmentOperator assignment)? ; +assignmentOperator + : '=' | '+=' | '-=' | '*=' | '/=' | '&=' | '|=' | '^=' + | '<<=' | '>>=' | '>>>=' + ; + +expression : logicalExpression ('?' assignment (':' assignment)?)? ; + +// Both logical operators short-circuit and associate to the right here. +logicalExpression : bitwiseExpression (('&&' | '||') logicalExpression)? ; + +bitwiseExpression + : equalityExpression (('&' | '|' | '^') equalityExpression)* + ; + +equalityExpression : comparisonExpression (('==' | '!=') comparisonExpression)* ; + +// Chained comparisons test adjacent operands and short-circuit. A chain must +// keep its direction; equality has lower precedence and does not join a chain. +comparisonExpression + : shiftExpression + ( (('<' | '<=') shiftExpression)+ | (('>' | '>=') shiftExpression)+ )? + ; + +shiftExpression + : additiveExpression (('<<' | '>>' | '>>>') additiveExpression)* + ; + +additiveExpression + : multiplicativeExpression (('+' | '-') multiplicativeExpression)* + ; + +multiplicativeExpression + : unaryExpression (('*' | '/') unaryExpression)* + ; + +unaryExpression + : ('-' | '!') unaryExpression + | updateOperator IDENTIFIER + | postfixExpression + ; + +// Prefix updates require a local name; postfix updates also allow fields +// and array elements. All updates require an assignable operand. +updateOperator : '++' | '--' ; +postfixExpression : primaryExpression postfixSuffix* updateOperator? ; +postfixSuffix : '.' IDENTIFIER | '[' assignment ']' | '#' | callSuffix | methodCallSuffix ; + +// For a fixed function-valued member, object.name(args) passes object as self. +// This overlaps ordinary field selection followed by a call syntactically; +// name/type resolution determines which call form applies. +methodCallSuffix : '.' IDENTIFIER callSuffix ; + +primaryExpression + : INTEGER_LITERAL + | FLOAT_LITERAL + | STRING_LITERAL + | CHARACTER_LITERAL + | 'true' + | 'false' + | 'null' + | IDENTIFIER + | '(' assignment ')' + | newExpression + | functionExpression + ; + +// A function is an expression bound with an ordinary declaration. +// Its last statement supplies the implicit result; return can exit earlier. +functionExpression : '{' parameterList? '->' statement* '}' ; +parameterList : (parameter ','?)+ ; +parameter : type bindingModifier? IDENTIFIER ; + +// Function types have unnamed, space-separated argument types. +// {int} is the zero-argument type; its function expression still uses ->. +functionType + : '{' type+ '->' type '}' '?'? + | '{' type '}' '?'? + ; + +callSuffix : '(' argumentList? ')' ; +argumentList : assignment (',' assignment)* ','? ; + +// Allocation invokes the declared constructor; inline initializer blocks from +// earlier chapters are replaced by constructor arguments. +newExpression : 'new' type ('[' assignment ']' | callSuffix)? ; + +INTEGER_LITERAL : '0' | [1-9] DIGIT* ; +FLOAT_LITERAL : DIGIT+ ('.' DIGIT* ('e' DIGIT+)? | 'e' '-'? DIGIT+) ; +STRING_LITERAL : '"' (ESCAPE | ~["\\])* '"' ; +CHARACTER_LITERAL : '\'' (ESCAPE | ~['\\]) '\'' ; +fragment ESCAPE : '\\' [0ntr\\'"] ; +IDENTIFIER : NON_DIGIT (NON_DIGIT | DIGIT)* ; +fragment NON_DIGIT : [a-zA-Z_] ; +fragment DIGIT : [0-9] ; +WHITESPACE : [ \t\r\n]+ -> skip ; +LINE_COMMENT : '//' ~[\r\n]* -> skip ; +BLOCK_COMMENT : '/*' .*? '*/' -> skip ; +``` diff --git a/chapter28b/docs/Makefile b/chapter28b/docs/Makefile deleted file mode 100644 index 12659b8f..00000000 --- a/chapter28b/docs/Makefile +++ /dev/null @@ -1,12 +0,0 @@ -GV := $(wildcard *.gv) -SVG := $(patsubst %.gv,%.svg,$(GV)) - -.PHONY: all -all: $(SVG) - -%.svg: %.gv - dot -Tsvg $< > $@ - -.PHONY: clean -clean: - @rm -f $(SVG) diff --git a/chapter28b/docs/examples/A_helloWorld.smp b/chapter28b/docs/examples/A_helloWorld.smp deleted file mode 100644 index 4ed6abdf..00000000 --- a/chapter28b/docs/examples/A_helloWorld.smp +++ /dev/null @@ -1,2 +0,0 @@ -sys.io.p("Hello, World!\n"); -return 0; diff --git a/chapter28b/docs/examples/BubbleSort.smp b/chapter28b/docs/examples/BubbleSort.smp deleted file mode 100644 index ca6906b5..00000000 --- a/chapter28b/docs/examples/BubbleSort.smp +++ /dev/null @@ -1,36 +0,0 @@ - -// An implementation of -// https://sampleprograms.io/projects/bubble-sort/ -// -// Bubble sort, with reading (parsing) and writing (formatting) the data. - -val sort = { !sys.aryi64 nums -> - sys.aryi64?! more = nums; - while( more ) { - more = null; - for( var i = 0; i < nums.len-1; i++ ) - if( nums.buf[i] > nums.buf[i+1] ) - more = nums.swap(i,i+1); - } -}; - -// Read one process argument of the form "[ 4, 3, 2, 1]" and print it sorted. -// args[0] is the executable name, as with native C argc/argv. -val main = { u8[~][] args -> - val usage = { -> - sys.io.p("Usage: please provide a list of at least two integers to sort in the format \"[1, 2, 3, 4, 5]\"\n"); - return 0; - }; - if( args# != 2 ) return usage(); - - var nums = sys.aryi64.parseAryI64(args[1]); - if( !nums ) return usage(); - if( nums.len < 2 ) return usage(); - - // Bubble sort array of integers - sort(nums); - - // Print the same bracketed array-list format accepted as input. - nums.str().add('\n').write(1); - return 0; -}; diff --git a/chapter28b/docs/examples/Capitalize.smp b/chapter28b/docs/examples/Capitalize.smp deleted file mode 100644 index 8e31c18f..00000000 --- a/chapter28b/docs/examples/Capitalize.smp +++ /dev/null @@ -1,22 +0,0 @@ - -// An implementation of -// https://sampleprograms.io/projects/capitalize/ - -val main = { u8[~][] args -> - if( args# > 2 ) { - sys.io.p("Use quotes around multiple strings.\n"); - return 0; - } - if( args# != 2 || args[1]# == 0 ) { - sys.io.p("Usage: please provide a string\n"); - return 0; - } - - u8[~] input = args[1]; - var output = new u8[input# + 1]; - sys.ary.copy(output,0,input,0,input#); - output[0] = sys.char.toupper(input[0]); - output[input#] = '\n'; - sys.io.p(output); - return 0; -}; diff --git a/chapter28b/docs/examples/Dijkstra.smp b/chapter28b/docs/examples/Dijkstra.smp deleted file mode 100644 index fd595eb5..00000000 --- a/chapter28b/docs/examples/Dijkstra.smp +++ /dev/null @@ -1,72 +0,0 @@ - -// An implementation of -// https://sampleprograms.io/projects/dijkstra/ - -val shortestPath = { !sys.aryi64 matrix, int nodes, int src, int dst -> - i64 infinity = (1 << 63)-1; - var dist = new i64[nodes]; - var visited = new sys.adt.bitset(); - // All nodes are infinitely far from each other - for( int i=0; i 0 && !visited.get(node) && best+weight < dist[node] ) - dist[node] = best+weight; - } - } - count++; - } - return result; -}; - -val usage = { -> - sys.io.p("Usage: please provide three inputs: a serialized matrix, a source node and a destination node\n"); - return 0; -}; - -val main = { u8[~][] args -> - // Exactly 3 args - if( args# != 4 ) return usage(); - // First is a serialized square matrix of positive numbers - var matrix = sys.aryi64.parseAryI64(args[1]); - if( !matrix ) return usage(); - if( !matrix.len ) return usage(); - // All numbers are positive - for( int i=0; i= nodes || dst < 0 || dst >= nodes ) - return usage(); // Source and destination land within the graph - - i64 cost = shortestPath(matrix,nodes,src,dst); - if( cost >= 0 ) { - new sys.aryu8().num(cost).add('\n').write(1); - return 0; - } - return usage(); -}; diff --git a/chapter28b/docs/examples/FileIO.smp b/chapter28b/docs/examples/FileIO.smp deleted file mode 100644 index e48d435b..00000000 --- a/chapter28b/docs/examples/FileIO.smp +++ /dev/null @@ -1,50 +0,0 @@ - -// An implementation of -// https://sampleprograms.io/projects/file-input-output/ - -val FILE = "output.txt"; - -val main = { u8[~][] args -> - var str = new sys.aryu8(); - str.addAry("Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.\n"); - str.addAry("Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.\n"); - str.addAry("Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.\n"); - str.addAry("Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.\n"); - - // Create - i32 fd = sys.io.create(FILE); - if( fd == -1 ) return _error(); - // Write - int wrote = sys.io.writeOff(fd,str.buf,0,str.len); - if( wrote == -1 ) return _error(); - if( wrote != str.len ) return _error2(-2); - // Close - if( sys.io.close(fd) != 0 ) return _error(); - - // Open - i32 fd2 = sys.io.open(FILE); - if( fd2 == -1 ) return _error(); - // Read - var got = sys.io.read(fd2); - if( got# != str.len ) return _error2(-3); - // Close - if( sys.io.close(fd2) != 0 ) return _error(); - - // Check contents are equal - if( sys.ary.cmp(got,0,str.buf,0,str.len) ) - return _error2(-4); - - // Remove - if( sys.io.remove(FILE) != 0 ) return _error(); - - sys.io.p("File I/O succeeded\n"); - return 0; -}; - -val _error2 = { i32 errno -> - sys.io.remove(FILE); - new sys.aryu8().addAry("Failed with error code ").num(errno).add('\n').write(sys.libc.STDERR); - sys.libc._exit(errno); -}; - -val _error = { -> _error2(sys.libc.errno()); }; diff --git a/chapter28b/docs/font-awesome-4.7.0.zip b/chapter28b/docs/font-awesome-4.7.0.zip deleted file mode 100644 index b6bdb4bd..00000000 Binary files a/chapter28b/docs/font-awesome-4.7.0.zip and /dev/null differ diff --git a/chapter28b/docs/ifg_trim.pdf b/chapter28b/docs/ifg_trim.pdf deleted file mode 100644 index d952fd4f..00000000 Binary files a/chapter28b/docs/ifg_trim.pdf and /dev/null differ diff --git a/chapter28b/docs/lattice.gv b/chapter28b/docs/lattice.gv deleted file mode 100644 index 8661082d..00000000 --- a/chapter28b/docs/lattice.gv +++ /dev/null @@ -1,203 +0,0 @@ -digraph Lattice { - compound = true; - // Define nodes - splines=false; - node [shape=circle, style=filled]; - nodesep=0.2; - ranksep=0.2; - - TOP [label=<⊤>, fillcolor=black, fontcolor=white]; - BOT [label=<⊥>, fillcolor=black, fontcolor=white]; - - // ---------------------- - // Control - XCTRL [label=<⊤:ctrl>, fillcolor=yellow, shape=oval]; - CTRL [label=<⊥:ctrl>, fillcolor=yellow, shape=oval]; - - TOP -> XCTRL; - XCTRL -> CTRL; - CTRL -> BOT; - - // ---------------------- - // Integers - INT_TOP [label=<⊤:int>, fillcolor=lightblue, shape=oval]; - INT_BOT [label=<⊥:int>, fillcolor=lightblue, shape=oval]; - - INT_HI [label="[min>max]" , fillcolor=lightblue, shape=oval]; - INT_XBOOL [label="[1...0]", fillcolor=lightblue, shape=oval]; - INT_CON [label="constants", fillcolor=lightblue, shape=oval]; - INT_CON0 [label="0", fillcolor=lightblue]; - INT_CON1 [label="1", fillcolor=lightblue]; - INT_BOOL [label="[0...1]", fillcolor=lightblue,shape=oval]; - INT_LO [label="[min INT_TOP; - INT_TOP -> INT_HI; - INT_HI -> INT_XBOOL; - INT_XBOOL -> INT_CON0; - INT_XBOOL -> INT_CON1; - INT_HI -> INT_CON; - INT_CON0 -> INT_BOOL; - INT_CON1 -> INT_BOOL; - INT_BOOL -> INT_LO; - INT_CON -> INT_LO; - INT_LO -> INT_BOT; - INT_BOT -> BOT; - - INT_CON0 -> INT_CON1 -> INT_CON [style=invis]; - - // ---------------------- - // Floats - FLT_TOP [label=<⊤:flt>, fillcolor=aqua, shape=oval]; - FLT_BOT [label=<⊥:flt>, fillcolor=aqua, shape=oval]; - - FLT_CON64 [label="64b consts\n[excludes\n32b consts]" , fillcolor=aqua, shape=oval]; - FLT_CON32 [label="32b consts", fillcolor=aqua, shape=oval]; - FLT_CONPI [label="3.14159...", fillcolor=aqua, shape=oval]; - FLT_X32 [label="~f32", fillcolor=aqua]; - FLT_CON0 [label="0." , fillcolor=aqua]; - FLT_32 [label="f32" , fillcolor=aqua]; - - TOP -> FLT_TOP; - FLT_TOP -> FLT_CON64 - FLT_TOP -> FLT_CONPI - FLT_CON64 -> FLT_BOT - FLT_CONPI -> FLT_BOT - - FLT_TOP -> FLT_X32; - FLT_X32 -> FLT_CON0; - FLT_X32 -> FLT_CON32; - FLT_CON0 -> FLT_32; - FLT_CON32 -> FLT_32; - FLT_32 -> FLT_BOT - - FLT_BOT -> BOT; - - FLT_CON0 -> FLT_CON32 -> FLT_CONPI -> FLT_CON64 [style=invis]; - - - // ---------------------- - // Pointers, just a boolean nil/not and a struct - PTR [shape=none, fillcolor=none, label=< - - - -
*ptr
struct
- >]; - PTR0 [shape=none, fillcolor=none, label=< - - - -
*ptr?
struct
- >]; - - TOP -> PTR; - PTR -> PTR0; - PTR0 -> BOT; - - // ---------------------- - // Structs - STRUCT_TOP [label=<⊤:struct>, fillcolor=lightgreen, shape=oval]; - STRUCT_BOT [label=<⊥:struct>, fillcolor=lightgreen, shape=oval]; - - STRUCT_S1 [shape=none, fillcolor=none, label=< - - -
fieldint/ptr
- >]; - STRUCT_S2 [shape=none, fillcolor=none, label=< - - - -
fieldint/ptr
fieldint/ptr
- >]; - STRUCT_SN [shape=none, fillcolor=none, label=< - - - - -
fieldint/ptr
... int/ptr
fieldint/ptr
- >]; - - - TOP -> STRUCT_TOP; - STRUCT_TOP -> STRUCT_S1; - STRUCT_TOP -> STRUCT_S2; - STRUCT_TOP -> STRUCT_SN; - STRUCT_S1 -> STRUCT_BOT; - STRUCT_S2 -> STRUCT_BOT; - STRUCT_SN -> STRUCT_BOT; - STRUCT_BOT -> BOT; - - STRUCT_S1 -> STRUCT_S2 -> STRUCT_SN [style=invis]; - - // ---------------------- - // Memory - MEM_TOP [label=<⊤:mem>, fillcolor=blue, fontcolor=white, shape=oval]; - MEM_BOT [label=<⊥:mem>, fillcolor=blue, fontcolor=white, shape=oval]; - MEM_ALIAS1 [label="#1" , fillcolor=blue, fontcolor=white]; - MEM_ALIASDOTS [label="..." , fillcolor=blue, fontcolor=white, shape=oval]; - MEM_ALIASN [label="#n" , fillcolor=blue, fontcolor=white]; - - TOP -> MEM_TOP; - MEM_TOP -> MEM_ALIAS1; - MEM_TOP -> MEM_ALIASDOTS; - MEM_TOP -> MEM_ALIASN; - MEM_ALIAS1 -> MEM_BOT; - MEM_ALIASDOTS -> MEM_BOT; - MEM_ALIASN -> MEM_BOT; - MEM_BOT -> BOT; - - MEM_ALIAS1 -> MEM_ALIASDOTS -> MEM_ALIASN [style=invis]; - - // ---------------------- - // Tuples - - TUPLE_TOP [label=<⊤:tuple>, fillcolor=pink, shape=oval]; - TUPLE_BOT [label=<⊥:tuple>, fillcolor=pink, shape=oval]; - - TUPLE1 [shape=none, fillcolor=none, label=< - - - -
Tuple
type
- >]; - TUPLE2 [shape=none, fillcolor=none, label=< - - - - -
Tuple
type
type
- >]; - TUPLEN [shape=none, fillcolor=none, label=< - - - - - -
Tuple
type
...
type
- >]; - - - TOP -> TUPLE_TOP; - TUPLE_TOP -> TUPLE1; - TUPLE_TOP -> TUPLE2; - TUPLE_TOP -> TUPLEN; - TUPLE1 -> TUPLE_BOT; - TUPLE2 -> TUPLE_BOT; - TUPLEN -> TUPLE_BOT; - TUPLE_BOT -> BOT; - - // ---------------------- - // Additional customization - {rank=same; TOP;} - {rank=same; INT_TOP; FLT_TOP; XCTRL; PTR; STRUCT_TOP; MEM_TOP; TUPLE_TOP} - {rank=same; INT_CON; INT_CON0; INT_CON1; - FLT_CON32; FLT_CON64; FLT_CON0; FLT_CONPI; - STRUCT_S1; STRUCT_S2; STRUCT_SN; - MEM_ALIAS1; MEM_ALIASDOTS; MEM_ALIASN; - TUPLE1; TUPLE2; TUPLEN; - } - {rank=same; INT_BOT; FLT_BOT; CTRL; PTR0; STRUCT_BOT; MEM_BOT; TUPLE_BOT} - {rank=same; BOT;} -} diff --git a/chapter28b/docs/lattice.svg b/chapter28b/docs/lattice.svg deleted file mode 100644 index e72b473b..00000000 --- a/chapter28b/docs/lattice.svg +++ /dev/null @@ -1,691 +0,0 @@ - - - - - - -Lattice - - - -TOP - -⊤ - - - -XCTRL - -⊤ -:ctrl - - - -TOP->XCTRL - - - - - -INT_TOP - -⊤ -:int - - - -TOP->INT_TOP - - - - - -FLT_TOP - -⊤ -:flt - - - -TOP->FLT_TOP - - - - - -PTR - - - -*ptr - - -struct - - - -TOP->PTR - - - - - -STRUCT_TOP - -⊤ -:struct - - - -TOP->STRUCT_TOP - - - - - -MEM_TOP - -⊤ -:mem - - - -TOP->MEM_TOP - - - - - -TUPLE_TOP - -⊤ -:tuple - - - -TOP->TUPLE_TOP - - - - - -BOT - -⊥ - - - -CTRL - -⊥ -:ctrl - - - -XCTRL->CTRL - - - - - -CTRL->BOT - - - - - -INT_HI - -[min>max] - - - -INT_TOP->INT_HI - - - - - -INT_BOT - -⊥ -:int - - - -INT_BOT->BOT - - - - - -INT_XBOOL - -[1...0] - - - -INT_HI->INT_XBOOL - - - - - -INT_CON - -constants - - - -INT_HI->INT_CON - - - - - -INT_CON0 - -0 - - - -INT_XBOOL->INT_CON0 - - - - - -INT_CON1 - -1 - - - -INT_XBOOL->INT_CON1 - - - - - -INT_LO - -[min<max] - - - -INT_CON->INT_LO - - - - - - -INT_BOOL - -[0...1] - - - -INT_CON0->INT_BOOL - - - - - - -INT_CON1->INT_BOOL - - - - - -INT_BOOL->INT_LO - - - - - -INT_LO->INT_BOT - - - - - -FLT_CON64 - -64b consts -[excludes -32b consts] - - - -FLT_TOP->FLT_CON64 - - - - - -FLT_CONPI - -3.14159... - - - -FLT_TOP->FLT_CONPI - - - - - -FLT_X32 - -~f32 - - - -FLT_TOP->FLT_X32 - - - - - -FLT_BOT - -⊥ -:flt - - - -FLT_BOT->BOT - - - - - -FLT_CON64->FLT_BOT - - - - - -FLT_CON32 - -32b consts - - - - -FLT_32 - -f32 - - - -FLT_CON32->FLT_32 - - - - - -FLT_CONPI->FLT_BOT - - - - - - -FLT_X32->FLT_CON32 - - - - - -FLT_CON0 - -0. - - - -FLT_X32->FLT_CON0 - - - - - - -FLT_CON0->FLT_32 - - - - - -FLT_32->FLT_BOT - - - - - -PTR0 - - - -*ptr? - - -struct - - - -PTR->PTR0 - - - - - -PTR0->BOT - - - - - -STRUCT_S1 - - - -field - - - - - - - - -int/ptr - - - -STRUCT_TOP->STRUCT_S1 - - - - - -STRUCT_S2 - - - -field - - - - - - - - -int/ptr - - -field - - - - - - - - -int/ptr - - - -STRUCT_TOP->STRUCT_S2 - - - - - -STRUCT_SN - - - -field - - - - - - - - -int/ptr - - -...   - - - - - - - - -int/ptr - - -field - - - - - - - - -int/ptr - - - -STRUCT_TOP->STRUCT_SN - - - - - -STRUCT_BOT - -⊥ -:struct - - - -STRUCT_BOT->BOT - - - - - -STRUCT_S1->STRUCT_BOT - - - - - - -STRUCT_S2->STRUCT_BOT - - - - - - -STRUCT_SN->STRUCT_BOT - - - - - -MEM_ALIAS1 - -#1 - - - -MEM_TOP->MEM_ALIAS1 - - - - - -MEM_ALIASDOTS - -... - - - -MEM_TOP->MEM_ALIASDOTS - - - - - -MEM_ALIASN - -#n - - - -MEM_TOP->MEM_ALIASN - - - - - -MEM_BOT - -⊥ -:mem - - - -MEM_BOT->BOT - - - - - -MEM_ALIAS1->MEM_BOT - - - - - - -MEM_ALIASDOTS->MEM_BOT - - - - - - -MEM_ALIASN->MEM_BOT - - - - - -TUPLE1 - - - -Tuple - - -type - - - -TUPLE_TOP->TUPLE1 - - - - - -TUPLE2 - - - -Tuple - - -type - - -type - - - -TUPLE_TOP->TUPLE2 - - - - - -TUPLEN - - - -Tuple - - -type - - -... - - -type - - - -TUPLE_TOP->TUPLEN - - - - - -TUPLE_BOT - -⊥ -:tuple - - - -TUPLE_BOT->BOT - - - - - -TUPLE1->TUPLE_BOT - - - - - -TUPLE2->TUPLE_BOT - - - - - -TUPLEN->TUPLE_BOT - - - - - diff --git a/chapter28b/docs/lattice2.gv b/chapter28b/docs/lattice2.gv deleted file mode 100644 index 6aa37fa0..00000000 --- a/chapter28b/docs/lattice2.gv +++ /dev/null @@ -1,85 +0,0 @@ -digraph Lattice { - compound = true; - // Define nodes - splines=false; - node [shape=oval, style=filled]; - nodesep=0.2; - ranksep=0.4; - - TOP [label="~scalar\n+int+tmp+0", fillcolor=black, fontcolor=white, group=center]; - - // ------------------------ - PTRHQ [label="~tmp\n+tmp+0", fillcolor=green, fontcolor=white, group=left]; - TOP -> PTRHQ - - VALH_ [label="~nscalar\n+int+tmp", fillcolor=white, group=center]; - TOP -> VALH_ - - INTHQ [label="~int\n+int+0", fillcolor=lightblue, group=right]; - TOP -> INTHQ - - LEFTHI [label="junk", style=invis, group=junkleft] - - - PTRHQ -> LEFTHI-> VALH_ -> INTHQ [style=invis]; - { rank=same; PTRHQ; LEFTHI; VALH_; INTHQ } - - // ------------------------ - PTRH_ [label="~ntmp\n+tmp", fillcolor=green, fontcolor=white, group=left]; - VALH_ -> PTRH_ - PTRHQ -> PTRH_ - - INTH_ [label="~nint\n+int", fillcolor=lightblue, group=right]; - VALH_ -> INTH_ - INTHQ -> INTH_ - { rank=same; PTRH_; INTH_ } - - // ------------------------ - NILX_ [label="~nil\n[int,tmp]+0", fillcolor=aqua, group=junkleft]; - INTHQ -> NILX_ - PTRHQ -> NILX_ - - NIL__ [label="nil\n[+int+tmp],0", fillcolor=pink]; - VALH_ -> NIL__; - - NILX_ -> NIL__ [style=invis]; - { rank=same; NIL__; NILX_ } - - // ------------------------ - PTRL_ [label="ntmp\ntmp", fillcolor=green, fontcolor=white, group=left]; - PTRH_ -> PTRL_ - - INTL_ [label="nint\nint", fillcolor=lightblue, group=right]; - INTH_ -> INTL_ - { rank=same; PTRL_; INTL_ } - - // ------------------------ - PTRL0 [label="tmp\ntmp,0", fillcolor=green, fontcolor=white, group=left]; - PTRL_ -> PTRL0 - NIL__ -> PTRL0 - - VALL_ [label="nscalar\nint,tmp", fillcolor=white, group=center]; - PTRL_ -> VALL_ - INTL_ -> VALL_ - NILX_ -> VALL_ - - INTL0 [label="int\nint,0", fillcolor=lightblue, group=right]; - INTL_ -> INTL0 - NIL__ -> INTL0 - - PTRL0 -> VALL_ -> INTL0 [style=invis]; - { rank=same; PTRL0; VALL_; INTL0 } - - // ------------------------ - BOT [label="scalar\nint,tmp,0", fillcolor=black, fontcolor=white, group=center]; - PTRL0 -> BOT - INTL0 -> BOT - VALL_ -> BOT - - // ------------------------ - // Verticle alignment - TOP -> VALH_ -> VALL_ -> BOT [style=invis]; - PTRHQ -> PTRH_ -> PTRL_ -> PTRL0 [style=invis]; - INTHQ -> INTH_ -> INTL_ -> INTL0 [style=invis]; - LEFTHI -> NILX_ [style=invis] -} diff --git a/chapter28b/docs/lattice2.svg b/chapter28b/docs/lattice2.svg deleted file mode 100644 index 8b682aa7..00000000 --- a/chapter28b/docs/lattice2.svg +++ /dev/null @@ -1,260 +0,0 @@ - - - - - - -Lattice - - - -TOP - -~scalar -+int+tmp+0 - - - -PTRHQ - -~tmp -+tmp+0 - - - -TOP->PTRHQ - - - - - -VALH_ - -~nscalar -+int+tmp - - - -TOP->VALH_ - - - - - - -INTHQ - -~int -+int+0 - - - -TOP->INTHQ - - - - - - - -PTRH_ - -~ntmp -+tmp - - - -PTRHQ->PTRH_ - - - - - - -NILX_ - -~nil -[int,tmp]+0 - - - -PTRHQ->NILX_ - - - - - - -VALH_->PTRH_ - - - - - -INTH_ - -~nint -+int - - - -VALH_->INTH_ - - - - - -NIL__ - -nil -[+int+tmp],0 - - - -VALH_->NIL__ - - - - - -VALL_ - -nscalar -int,tmp - - - - -INTHQ->INTH_ - - - - - - -INTHQ->NILX_ - - - - - - - -PTRL_ - -ntmp -tmp - - - -PTRH_->PTRL_ - - - - - - -INTL_ - -nint -int - - - -INTH_->INTL_ - - - - - - - -NILX_->VALL_ - - - - - -PTRL0 - -tmp -tmp,0 - - - -NIL__->PTRL0 - - - - - -INTL0 - -int -int,0 - - - -NIL__->INTL0 - - - - - -PTRL_->PTRL0 - - - - - - -PTRL_->VALL_ - - - - - -INTL_->VALL_ - - - - - -INTL_->INTL0 - - - - - - - -BOT - -scalar -int,tmp,0 - - - -PTRL0->BOT - - - - - - -VALL_->BOT - - - - - - -INTL0->BOT - - - - - diff --git a/chapter28b/docs/pardoe.docx b/chapter28b/docs/pardoe.docx deleted file mode 100644 index 24fde921..00000000 Binary files a/chapter28b/docs/pardoe.docx and /dev/null differ diff --git a/chapter28b/docs/webtcp.min.js b/chapter28b/docs/webtcp.min.js deleted file mode 100644 index bf23ee5a..00000000 --- a/chapter28b/docs/webtcp.min.js +++ /dev/null @@ -1,65 +0,0 @@ -function Http(j){this.cID=Math.random().toString(36).substr(2);this.webtcp=j;this.webtcp.httpClients[this.cID]=this;this.createPacket=function(){return{cID:this.cID,type:"http",host:this.remoteAddress,port:this.remotePort,method:null,data:null}};this.ondata=function(){};this.get=function(g,c){this.on("data",c);this.rpc("httpGet",[g])};this.post=function(g,c,j){this.on("data",j);this.rpc("httpPost",[g,c])}}Http.prototype=new WebTCPIO;function Socket(j,g,c,p){this.sID=Math.random().toString(36).substr(2);this.webtcp=j;this.closed=this.ready=!1;this.options=p;this.sockOpts={_updating:!1};this.remoteAddress=g;this.remotePort=c;this.webtcp.sockets[this.sID]=this;this.createPacket=function(){return{id:Math.random().toString(36).substr(2),sID:this.sID,type:"tcp",options:this.options,host:this.remoteAddress,port:this.remotePort,data:null}};this.onconnect=function(){this.webtcp.sockets[sID].ready=!0;this.webtcp.sockets[sID].closed=!1}; -this.ondata=function(){};this.onend=function(){};this.ontimeout=function(){};this.ondrain=function(){};this.onclose=function(){this.webtcp.sockets[sID].ready=!1;this.webtcp.sockets[sID].closed=!0};this.getSockOpts=function(){this.sockOpts._updating=!0;this.rpc("getSockOpts")};this.onSockOptsRcv=function(c){this.sockOpts=c;this.sockOpts._updating=!1}}Socket.prototype=new WebTCPIO;var JSON;JSON||(JSON={}); -(function(){function j(c,p){var q,t,n,x,i=k,e,l=p[c];l&&"object"==typeof l&&"function"==typeof l.toJSON&&(l=l.toJSON(c));"function"==typeof r&&(l=r.call(p,c,l));switch(typeof l){case "string":return g(l);case "number":return isFinite(l)?String(l):"null";case "boolean":case "null":return String(l);case "object":if(!l)return"null";k+=v;e=[];if("[object Array]"===Object.prototype.toString.apply(l)){x=l.length;for(q=0;qc?"0"+c:c}"use strict";"function"!=typeof Date.prototype.toJSON&&(Date.prototype.toJSON=function(){return isFinite(this.valueOf())?this.getUTCFullYear()+"-"+c(this.getUTCMonth()+1)+"-"+c(this.getUTCDate())+"T"+c(this.getUTCHours())+":"+c(this.getUTCMinutes())+":"+c(this.getUTCSeconds())+"Z":null},String.prototype.toJSON=Number.prototype.toJSON=Boolean.prototype.toJSON=function(){return this.valueOf()});var p=/[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g, -n=/[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,k,v,D={"\b":"\\b","\t":"\\t","\n":"\\n","\f":"\\f","\r":"\\r",'"':'\\"',"\\":"\\\\"},r;"function"!=typeof JSON.stringify&&(JSON.stringify=function(c,g,p){var n;v=k="";if("number"==typeof p)for(n=0;n=a};c.countRTO=function(a){var b;return 100b;b++)d.push(String.fromCharCode(b));B=(r.lastIndex=0,d.join("").replace(r,function(a){return c[a]="\\u"+("0000"+a.charCodeAt(0).toString(16)).slice(-4),""}),r.lastIndex=0,c)}a=a.replace(r,function(a){return B[a]})}return a};var q="websocket xdr-streaming xhr-streaming iframe-eventsource iframe-htmlfile xdr-polling xhr-polling iframe-xhr-polling jsonp-polling".split(" "); -c.probeProtocols=function(){for(var a={},b=0;b