diff --git a/crates/erg_compiler/lib/std/abc.er b/crates/erg_compiler/lib/std/abc.er index 76108e62..e9a256c4 100644 --- a/crates/erg_compiler/lib/std/abc.er +++ b/crates/erg_compiler/lib/std/abc.er @@ -3,11 +3,9 @@ .Sized = Trait { .__len__ = (self: Self) -> Nat } # TODO: varargs .Callable = Trait { .__call__ = (self: Self) -> Obj } -# .Iterator T = Trait { .__next__ = (self: Self) -> T } -.Iterator = Trait { .__next__ = (self: Self) -> Obj } -# .Iterable T = Trait { .__iter__ = (self: Self) -> Iterator T } -.Iterable = Trait { .__iter__ = (self: Self) -> .Iterator } -.Collection = Subsume .Container and .Iterable -.Reversible = Trait { .__reversed__ = (self: Self) -> .Iterator } -.Genertor = Subsume .Iterator -.Sequence = Subsume .Collection and .Sized and .Reversible +.Iterator T = Trait { .__next__ = (self: Self) -> T } +.Iterable T = Trait { .__iter__ = (self: Self) -> .Iterator(T) } +.Collection T = Subsume .Container and .Iterable(T) +.Reversible T = Trait { .__reversed__ = (self: Self) -> .Iterator(T) } +.Genertor T = Subsume .Iterator T +.Sequence T = Subsume .Collection(T) and .Sized and .Reversible(T) diff --git a/doc/JA/compiler/phases/10_codegen.md b/doc/JA/compiler/phases/10_codegen.md index 45234cca..c74e48a2 100644 --- a/doc/JA/compiler/phases/10_codegen.md +++ b/doc/JA/compiler/phases/10_codegen.md @@ -1 +1,99 @@ # コード生成 + +Ergスクリプトは、デフォルトではpycファイルに変換されて実行されます。つまり、Pythonスクリプトではなく[Pythonバイトコード](https://github.com/erg-lang/erg/blob/d1dc1e60e7d4e3333f80ed23c5ead77b5fe47cb2/doc/JA/python/bytecode_instructions.md)として実行されます。 +pycファイルは構文糖が剥がされ(phase 8)、依存関係の結合(phase 9)されたHIRから生成されます。 +処理は[`PyCodeGenerator`](https://github.com/erg-lang/erg/blob/d1dc1e60e7d4e3333f80ed23c5ead77b5fe47cb2/crates/erg_compiler/codegen.rs#L160)が行います。この構造体は`HIR`を受け取って`CodeObj`を返します。 +`CodeObj`はPythonのCodeオブジェクトに対応し、実行する命令列や静的領域のオブジェクト、その他様々なメタデータを持ちます。`Code`オブジェクトはPythonインタプリタから見るとスコープを表すオブジェクトです。トップレベルのスコープを表す`Code`が、実行に必要な全ての情報を持つことになります。`CodeObj`は[dump_as_pyc](https://github.com/erg-lang/erg/blob/d1dc1e60e7d4e3333f80ed23c5ead77b5fe47cb2/crates/erg_compiler/ty/codeobj.rs#L378)メソッドでバイナリ化され、pycファイルに書き出されます。 + +# Pythonに存在しない機能 + +## Ergランタイム + +ErgはPythonインタプリタ上で動作しますが、Pythonとは様々なセマンティクスの違いがあります。 +幾つかの機能はコンパイラがより低次の機能に脱糖することで実現されますが、ランタイムで実現するしかないものもあります。 + +組み込み型のPythonには存在しないメソッドなどがその例です。 +Pythonの組み込みには`Nat`型は存在しませんし、`times!`メソッドも存在しません。 +このようなメソッドは、Pythonの組み込み型をラップした新しい型を作ることで実現しています。 + +それらの型は[](https://github.com/erg-lang/erg/blob/d1dc1e60e7d4e3333f80ed23c5ead77b5fe47cb2/crates/erg_compiler/lib/std)に置かれています。 +生成されるバイトコードはまず[`_erg_std_prelude.py`をimport](https://github.com/erg-lang/erg/blob/d1dc1e60e7d4e3333f80ed23c5ead77b5fe47cb2/crates/erg_compiler/codegen.rs#L3113)します。このモジュールはErgランタイムの提供する型、関数をre-exportします。 + +## Record + +レコードは、Pythonの`namedtuple`で実現されています。 + +## トレイト + +トレイトは、実体としてはPythonのABC(抽象基底クラス)で実現されています。 +といっても、Ergのトレイトは実行時にはほとんど意味を持ちません。 + +## match + +パターンマッチは大抵、型判定と代入動作の組み合わせに還元されます。これはコンパイルの比較的早い段階で行われます。 + +```erg +i, [j, *k] = 1, [2, 3, 4] +``` + +↓ + +```erg +_0 = 1, [2, 3] +i = _0[0] +_1 = _0[1] +j = _1[0] +k = _1[1:] +``` + +しかし、実行時まで遅延するものもあります。 + +```erg +x: Int or Str +match x: + i: Int -> ... + s: Str -> ... +``` + +このパターンマッチは実行時の判定を必要とします。この判定は[`in_operator`](https://github.com/erg-lang/erg/blob/d1dc1e60e7d4e3333f80ed23c5ead77b5fe47cb2/crates/erg_compiler/lib/std/_erg_in_operator.py#L6)が行います。 + +したがって、上のコードを脱糖すると以下のようになります。網羅性検査はコンパイル時に行われます。 + +```erg +if in_operator(x, Int): + ... +else: + ... +``` + +## 制御構造をなす関数 + +`for!`や`if!`などPythonの制御構造に対応する関数は、最適化状況によって実体が変わります。通常は最適化が行えて、専用のバイトコード命令に還元されます。 + +```erg +for! [a, b], i => + ... +``` + +↓ + +```pyc +LOAD_NAME 0(a) +LOAD_NAME 1(b) +BUILD_LIST 2 +GET_ITER +FOR_ITER ... +STORE_NAME 2(i) +... +``` + +これは関数呼び出しよりも効率的です。しかし以下のように、最適化が行えない場合もあります。 + +```erg +f! = [for!, ...].choice!() + +f! [1, 2], i => + ... +``` + +このような場合は実体を持つ関数として扱わなくてはなりません。関数は[_erg_control.py](https://github.com/erg-lang/erg/blob/d1dc1e60e7d4e3333f80ed23c5ead77b5fe47cb2/crates/erg_compiler/lib/std/_erg_control.py)に定義されています。 diff --git a/doc/JA/dev_guide/runtime.md b/doc/JA/dev_guide/runtime.md new file mode 100644 index 00000000..c88958cf --- /dev/null +++ b/doc/JA/dev_guide/runtime.md @@ -0,0 +1,73 @@ +# Pythonで実装されているモジュール + +## [_erg_array.py](https://github.com/erg-lang/erg/blob/d1dc1e60e7d4e3333f80ed23c5ead77b5fe47cb2/crates/erg_compiler/lib/std/_erg_array.py) + +`list`のラッパーである`Array`クラスを定義します。 + +## [_erg_bool.py](https://github.com/erg-lang/erg/blob/d1dc1e60e7d4e3333f80ed23c5ead77b5fe47cb2/crates/erg_compiler/lib/std/_erg_bool.py) + +`Nat`のラッパー(`bool`ではないことに注意)である`Bool`クラスを定義します。 + +## [_erg_bytes.py](https://github.com/erg-lang/erg/blob/d1dc1e60e7d4e3333f80ed23c5ead77b5fe47cb2/crates/erg_compiler/lib/std/_erg_bytes.py) + +## [_erg_control.py](https://github.com/erg-lang/erg/blob/d1dc1e60e7d4e3333f80ed23c5ead77b5fe47cb2/crates/erg_compiler/lib/std/_erg_control.py) + +`for!`、`if!`などの制御構造を実現する関数を定義します。 + +## [_erg_converters.py](https://github.com/erg-lang/erg/blob/d1dc1e60e7d4e3333f80ed23c5ead77b5fe47cb2/crates/erg_compiler/lib/std/_erg_convertors.py) + +`int`や`str`などのコンストラクタを定義します。これらのコンストラクタは現状、失敗時に`None`を返します。 + +## [_erg_dict.py](https://github.com/erg-lang/erg/blob/d1dc1e60e7d4e3333f80ed23c5ead77b5fe47cb2/crates/erg_compiler/lib/std/_erg_dict.py) + +`dict`のラッパーである`Dict`クラスを定義します。 + +## [_erg_float.py](https://github.com/erg-lang/erg/blob/d1dc1e60e7d4e3333f80ed23c5ead77b5fe47cb2/crates/erg_compiler/lib/std/_erg_float.py) + +## [_erg_in_operator.py](https://github.com/erg-lang/erg/blob/d1dc1e60e7d4e3333f80ed23c5ead77b5fe47cb2/crates/erg_compiler/lib/std/_erg_in_operator.py) + +`in`演算子の実装を定義します。Ergの`in`演算子はPythonの`in`演算子の機能に加えて、型の包含判定も行います。 +例えば`1 in Int`、``[1, 2] in [Int; 2]``などが可能です。 + +## [_erg_int.py](https://github.com/erg-lang/erg/blob/d1dc1e60e7d4e3333f80ed23c5ead77b5fe47cb2/crates/erg_compiler/lib/std/_erg_int.py) + +## [_erg_mutate.py](https://github.com/erg-lang/erg/blob/d1dc1e60e7d4e3333f80ed23c5ead77b5fe47cb2/crates/erg_compiler/lib/std/_erg_mutate_operator.py) + +`!`演算子の実装を定義します。`!`演算子はオブジェクトを可変化します。例えば、`Int`を`IntMut`(`Int!`)に変換します。 +これは、実際は`mutate`メソッドを呼び出しているだけです。 + +## [_erg_nat.py](https://github.com/erg-lang/erg/blob/d1dc1e60e7d4e3333f80ed23c5ead77b5fe47cb2/crates/erg_compiler/lib/std/_erg_nat.py) + +## [_erg_range.py](https://github.com/erg-lang/erg/blob/d1dc1e60e7d4e3333f80ed23c5ead77b5fe47cb2/crates/erg_compiler/lib/std/_erg_range.py) + +`1..3`などで現れる範囲オブジェクトを定義します。 +これはPythonの`range`で返される`range`オブジェクトとは全く異なっており、セマンティクス的にはどちらかというとRustの`Range`に近いです。 +`Int`だけでなく整列可能なオブジェクト全般に対して使用できます。 + +## [_erg_result.py](https://github.com/erg-lang/erg/blob/d1dc1e60e7d4e3333f80ed23c5ead77b5fe47cb2/crates/erg_compiler/lib/std/_erg_result.py) + +エラーの基底クラスである`Error`を定義します。 + +## [_erg_set.py](https://github.com/erg-lang/erg/blob/d1dc1e60e7d4e3333f80ed23c5ead77b5fe47cb2/crates/erg_compiler/lib/std/_erg_set.py) + +## [_erg_std_prelude.py](https://github.com/erg-lang/erg/blob/d1dc1e60e7d4e3333f80ed23c5ead77b5fe47cb2/crates/erg_compiler/lib/std/_erg_std_prelude.py) + +Ergランタイムのエントリポイントです。 + +## [_erg_str.py](https://github.com/erg-lang/erg/blob/d1dc1e60e7d4e3333f80ed23c5ead77b5fe47cb2/crates/erg_compiler/lib/std/_erg_str.py) + +# Ergで実装されているモジュール + +## [abc.er](https://github.com/erg-lang/erg/blob/d1dc1e60e7d4e3333f80ed23c5ead77b5fe47cb2/crates/erg_compiler/lib/std/abc.er) + +トレイトを実装します。未実装の機能が使われており、コンパイル出来ません。 + +## [semver.er](https://github.com/erg-lang/erg/blob/d1dc1e60e7d4e3333f80ed23c5ead77b5fe47cb2/crates/erg_compiler/lib/std/semver.er) + +セマンティックバージョンを取り扱うためのモジュールです。 + +## consts + +### [consts/physics](https://github.com/erg-lang/erg/blob/d1dc1e60e7d4e3333f80ed23c5ead77b5fe47cb2/crates/erg_compiler/lib/std/consts/physics.er) + +よく使われる物理定数を定義します。