├── doc ├── JA │ ├── API │ │ ├── index.md │ │ ├── types │ │ │ ├── classes │ │ │ │ ├── Class.md │ │ │ │ ├── Type.md │ │ │ │ ├── Iterator.md │ │ │ │ ├── StrWithLen.md │ │ │ │ ├── Module.md │ │ │ │ ├── Str!.md │ │ │ │ ├── Kind(N).md │ │ │ │ ├── Array(T).md │ │ │ │ ├── Object.md │ │ │ │ ├── Vector.md │ │ │ │ ├── Operator.md │ │ │ │ ├── Pos.md │ │ │ │ ├── Dict!.md │ │ │ │ ├── Array!(T).md │ │ │ │ ├── Matrix.md │ │ │ │ ├── Neg.md │ │ │ │ ├── Result.md │ │ │ │ ├── Function(N).md │ │ │ │ ├── Either.md │ │ │ │ ├── Complex.md │ │ │ │ ├── Inf.md │ │ │ │ ├── Str.md │ │ │ │ ├── Nat.md │ │ │ │ ├── Int.md │ │ │ │ ├── TransCell(T).md │ │ │ │ ├── Subroutine.md │ │ │ │ ├── Ratio.md │ │ │ │ ├── Record.md │ │ │ │ ├── IntRange.md │ │ │ │ ├── Interval.md │ │ │ │ ├── Never.md │ │ │ │ ├── Tensor.md │ │ │ │ ├── Float.md │ │ │ │ ├── Option.md │ │ │ │ ├── ArrayWithMutLength!(T,N).md │ │ │ │ ├── NonZero.md │ │ │ │ ├── Tuple.md │ │ │ │ └── ArrayWithLen(T,N).md │ │ │ ├── traits │ │ │ │ ├── Eq.md │ │ │ │ ├── Ord.md │ │ │ │ ├── Seq.md │ │ │ │ ├── Show.md │ │ │ │ ├── Iterable.md │ │ │ │ ├── SafeDiv(R,O).md │ │ │ │ ├── Div(R,O).md │ │ │ │ ├── Into.md │ │ │ │ ├── Num.md │ │ │ │ ├── Unpack.md │ │ │ │ ├── Add(R,O).md │ │ │ │ └── Sample.md │ │ │ └── patches │ │ │ │ ├── UnaryOp.md │ │ │ │ └── BinOp.md │ │ ├── consts.md │ │ ├── modules │ │ │ ├── status.md │ │ │ ├── repl.md │ │ │ ├── unsound.md │ │ │ ├── external │ │ │ │ └── alstruct.md │ │ │ └── unit.md │ │ ├── procs.md │ │ └── operators.md │ ├── python │ │ ├── index.md │ │ ├── python_vers.txt │ │ ├── class_system.md │ │ └── bytecode_specification.md │ ├── tools │ │ ├── index.md │ │ ├── fmt.md │ │ ├── repl.md │ │ ├── build.md │ │ ├── install.md │ │ ├── env.md │ │ └── test.md │ ├── compiler │ │ ├── index.md │ │ ├── ty_bound_resolving.md │ │ ├── TODO_hint.md │ │ ├── query.md │ │ ├── TODO_warn.md │ │ ├── abandoned.md │ │ ├── TODO_recov_suggest.md │ │ ├── overview.md │ │ ├── unification.md │ │ ├── type_var_normalization.md │ │ ├── parsing.md │ │ ├── memory_management.md │ │ ├── transpile.md │ │ ├── errors.md │ │ └── trait_method_resolving.md │ ├── dev_guide │ │ ├── index.md │ │ ├── features.md │ │ ├── env.md │ │ ├── doc_guideline.md │ │ ├── branches.md │ │ ├── rust_code_guideline.md │ │ └── unify_terms.md │ ├── syntax │ │ ├── type │ │ │ ├── option.md │ │ │ ├── advanced.md │ │ │ ├── 09_attributive.md │ │ │ ├── guard.md │ │ │ ├── 10_interval.md │ │ │ ├── advanced │ │ │ │ ├── marker_trait.md │ │ │ │ ├── quantified_dependent.md │ │ │ │ ├── default_param.md │ │ │ │ ├── keyword_param.md │ │ │ │ ├── rank2type.md │ │ │ │ ├── existential.md │ │ │ │ ├── mut_struct.md │ │ │ │ ├── projection.md │ │ │ │ ├── erasure.md │ │ │ │ ├── phantom.md │ │ │ │ ├── recursive_type_inferring.md │ │ │ │ ├── GADTs.md │ │ │ │ ├── shared.md │ │ │ │ └── typeof.md │ │ │ ├── 08_value.md │ │ │ ├── newtype.md │ │ │ ├── special.md │ │ │ ├── 06_nst_vs_sst.md │ │ │ ├── 16_subtyping.md │ │ │ ├── 11_enum.md │ │ │ ├── 14_dependent.md │ │ │ ├── 17_type_casting.md │ │ │ ├── 12_refinement.md │ │ │ ├── overloading.md │ │ │ └── 13_algebraic.md │ │ ├── 15_type.md │ │ ├── 08_procedure.md │ │ ├── 09_builtin_procs.md │ │ ├── 24_module.md │ │ ├── 10_array.md │ │ ├── 06_operator.md │ │ ├── 34_generator.md │ │ ├── 31_pipeline.md │ │ ├── 28_spread_syntax.md │ │ ├── 14_set.md │ │ ├── 05_builtin_funcs.md │ │ ├── container_ownership.md │ │ ├── 03_declaration.md │ │ ├── 20_naming_rule.md │ │ ├── 32_integration_with_Python.md │ │ ├── 22_subroutine.md │ │ ├── 12_dict.md │ │ ├── 27_comprehension.md │ │ ├── 23_closure.md │ │ ├── 33_package_system.md │ │ ├── 21_lambda.md │ │ ├── 25_object_system.md │ │ └── 29_decorator.md │ ├── migration_from_py.md │ ├── index.md │ ├── improved_points.md │ ├── faq_technical.md │ └── faq_general.md └── EN │ ├── syntax │ ├── type │ │ ├── 10_interval.md │ │ ├── 11_enum.md │ │ ├── 06_nst_vs_sst.md │ │ ├── 09_attributive.md │ │ ├── 13_algebraic.md │ │ ├── advanced │ │ │ ├── GADTs.md │ │ │ ├── erasure.md │ │ │ ├── kind.md │ │ │ ├── phantom.md │ │ │ ├── shared.md │ │ │ ├── existential.md │ │ │ ├── marker_trait.md │ │ │ ├── mut_struct.md │ │ │ ├── projection.md │ │ │ ├── default_param.md │ │ │ ├── keyword_param.md │ │ │ └── quiantified_dependent.md │ │ ├── advanced.md │ │ ├── 08_value.md │ │ ├── 16_subtyping.md │ │ └── 14_dependent.md │ ├── 15_type.md │ ├── 08_procedure.md │ ├── 09_builtin_procs.md │ ├── 24_module.md │ ├── 10_array.md │ ├── 31_pipeline.md │ ├── 06_operator.md │ ├── 14_set.md │ ├── 34_generator.md │ ├── 05_builtin_funcs.md │ ├── 28_spread_syntax.md │ ├── 32_integration_with_Python.md │ ├── 22_subroutine.md │ ├── 20_naming_rule.md │ ├── 03_declaration.md │ ├── 12_dict.md │ └── 27_comprehension.md │ ├── migration_from_py.md │ ├── index.md │ ├── improved_points.md │ └── faq_technical.md ├── compiler ├── erg_parser │ ├── tests │ │ ├── hello_world.er │ │ ├── fib.er │ │ ├── dependent.er │ │ ├── ast_example.txt │ │ ├── test1_basic_syntax.er │ │ └── test2_advanced_syntax.er │ ├── README.md │ ├── lib.rs │ ├── .gitignore │ ├── main.rs │ └── Cargo.toml ├── erg_compiler │ ├── tests │ │ ├── infer_arr.er │ │ ├── fib.er │ │ ├── dependent.er │ │ └── side_effect.er │ ├── README.md │ ├── lib.rs │ ├── .gitignore │ ├── optimize.rs │ ├── Cargo.toml │ └── main.rs └── erg_common │ ├── color.rs │ ├── .gitignore │ ├── build.rs │ ├── Cargo.toml │ ├── datetime.rs │ ├── levenshtein.rs │ ├── stdin.rs │ ├── lazy_buffer.rs │ ├── cache.rs │ └── rccell.rs ├── tests ├── add.er ├── mut_array.er ├── fizzbuzz.er └── test.rs ├── assets ├── erg_logo.png ├── erg_logo_with_slogan_transparent.png └── erg_logo.svg ├── .gitattributes ├── src ├── lib.rs ├── .gitignore ├── main.rs └── scripts │ └── repl_server.py ├── examples ├── tuple.er ├── fib.er ├── helloworld.er ├── patch.er ├── quantified.er ├── dict.er ├── add.er ├── slot.ts ├── dependent.er ├── class.er ├── record.er ├── list.er ├── control.er ├── array.er ├── rank2.er └── enum.er ├── .github └── workflows │ └── rust.yml ├── .gitignore ├── LICENSE-MIT ├── Cargo.toml └── library └── std └── prelude.er /doc/JA/API/index.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /doc/JA/python/index.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /doc/JA/tools/index.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /doc/JA/compiler/index.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /doc/JA/dev_guide/index.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /doc/EN/syntax/type/10_interval.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /doc/EN/syntax/type/11_enum.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /doc/JA/API/types/classes/Class.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /doc/JA/API/types/classes/Type.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /doc/JA/API/types/traits/Eq.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /doc/JA/API/types/traits/Ord.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /doc/JA/API/types/traits/Seq.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /doc/JA/API/types/traits/Show.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /doc/EN/syntax/type/06_nst_vs_sst.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /doc/EN/syntax/type/09_attributive.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /doc/EN/syntax/type/13_algebraic.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /doc/EN/syntax/type/advanced/GADTs.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /doc/EN/syntax/type/advanced/erasure.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /doc/EN/syntax/type/advanced/kind.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /doc/EN/syntax/type/advanced/phantom.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /doc/EN/syntax/type/advanced/shared.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /doc/JA/API/types/classes/Iterator.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /doc/JA/API/types/classes/StrWithLen.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /doc/JA/API/types/traits/Iterable.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /doc/EN/syntax/type/advanced/existential.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /doc/EN/syntax/type/advanced/marker_trait.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /doc/EN/syntax/type/advanced/mut_struct.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /doc/EN/syntax/type/advanced/projection.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /doc/JA/syntax/type/option.md: -------------------------------------------------------------------------------- 1 | # Option 2 | -------------------------------------------------------------------------------- /doc/EN/syntax/type/advanced/default_param.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /doc/EN/syntax/type/advanced/keyword_param.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /doc/EN/syntax/type/advanced/quiantified_dependent.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /doc/JA/compiler/ty_bound_resolving.md: -------------------------------------------------------------------------------- 1 | # 型制約の解決 2 | -------------------------------------------------------------------------------- /compiler/erg_parser/tests/hello_world.er: -------------------------------------------------------------------------------- 1 | print! "Hello, world!" 2 | -------------------------------------------------------------------------------- /doc/JA/API/types/classes/Module.md: -------------------------------------------------------------------------------- 1 | # Module 2 | 3 | ## methods 4 | -------------------------------------------------------------------------------- /tests/add.er: -------------------------------------------------------------------------------- 1 | add x, y = 2 | x + y 3 | 4 | print! 1 + 1 5 | print! 1.0 + 1 -------------------------------------------------------------------------------- /assets/erg_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shinh/erg/main/assets/erg_logo.png -------------------------------------------------------------------------------- /doc/JA/syntax/type/advanced.md: -------------------------------------------------------------------------------- 1 | 以降は更に高度な型システムを解説します。入門者の方はすべての項を読まなくても問題ありません。 2 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | extern crate erg_common; 2 | extern crate erg_compiler; 3 | pub mod dummy; 4 | -------------------------------------------------------------------------------- /tests/mut_array.er: -------------------------------------------------------------------------------- 1 | v = ![] 2 | for! 0..10, i => 3 | v.push! i 4 | 5 | log v.sum() 6 | -------------------------------------------------------------------------------- /doc/JA/API/types/classes/Str!.md: -------------------------------------------------------------------------------- 1 | # StrWithLen! N: Nat! = Inherit StrWithLen N 2 | 3 | 可変長文字列を表す型。 4 | -------------------------------------------------------------------------------- /doc/JA/API/types/classes/Kind(N).md: -------------------------------------------------------------------------------- 1 | # Kind N: Nat 2 | 3 | ```erg 4 | Kind N: Nat = (Type; N) -> Type 5 | ``` 6 | -------------------------------------------------------------------------------- /doc/JA/API/types/classes/Array(T).md: -------------------------------------------------------------------------------- 1 | # Array T: Type 2 | 3 | `Array T = ArrayWithLen T, _`で定義される。`[T]`という糖衣構文がある。 4 | -------------------------------------------------------------------------------- /doc/JA/API/types/classes/Object.md: -------------------------------------------------------------------------------- 1 | # Object 2 | 3 | 全ての型の上位型である。 4 | 5 | ## methods 6 | 7 | * __sizeof__: Nat 8 | -------------------------------------------------------------------------------- /doc/JA/API/types/classes/Vector.md: -------------------------------------------------------------------------------- 1 | # Vector T: Num, N: Nat 2 | 3 | ベクトルを表す型です。RustやC++などの同名の型と違い、この型が扱うのは数値専用です。 4 | -------------------------------------------------------------------------------- /doc/JA/API/types/patches/UnaryOp.md: -------------------------------------------------------------------------------- 1 | # UnaryOp T, O 2 | 3 | 単項演算子の型です。 4 | 5 | ## def 6 | 7 | Operator [T], O 8 | -------------------------------------------------------------------------------- /doc/JA/API/types/patches/BinOp.md: -------------------------------------------------------------------------------- 1 | # BinOp L, R, O 2 | 3 | 二項演算子の型です。 4 | 5 | ## Patches 6 | 7 | Operator [L, R], O 8 | -------------------------------------------------------------------------------- /doc/JA/API/types/classes/Operator.md: -------------------------------------------------------------------------------- 1 | # Operator [...T], O 2 | 3 | 演算子の型です。 4 | 5 | ## def 6 | 7 | Inherit Func [...T], O 8 | -------------------------------------------------------------------------------- /assets/erg_logo_with_slogan_transparent.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shinh/erg/main/assets/erg_logo_with_slogan_transparent.png -------------------------------------------------------------------------------- /examples/tuple.er: -------------------------------------------------------------------------------- 1 | p = (1, 2) 2 | assert p.0 == 1 3 | 4 | q = (1, 1.0) 5 | assert q.1 == 1.0 6 | 7 | i, j = 0, 1 8 | assert i == 0 9 | -------------------------------------------------------------------------------- /compiler/erg_compiler/tests/infer_arr.er: -------------------------------------------------------------------------------- 1 | v = ![] 2 | v.push! 1 3 | 4 | w = v 5 | print! w 6 | print! v # this should cause a MoveError 7 | -------------------------------------------------------------------------------- /compiler/erg_parser/README.md: -------------------------------------------------------------------------------- 1 | # Erg parser 2 | 3 | ## Why isn't this module but crate? 4 | 5 | For maintainability. This crate has tests. 6 | -------------------------------------------------------------------------------- /doc/JA/tools/fmt.md: -------------------------------------------------------------------------------- 1 | # fmt 2 | 3 | fmtサブコマンドででコードフォーマットが出来ます。 4 | よく使用されるフラッグは以下の通りです。 5 | 6 | * explicit-type: 型指定が省略されている箇所を自動的に補完します。 7 | -------------------------------------------------------------------------------- /doc/EN/syntax/type/advanced.md: -------------------------------------------------------------------------------- 1 | The following sections describe more advanced type systems. Beginners do not need to read the entire section. 2 | -------------------------------------------------------------------------------- /doc/JA/API/types/classes/Pos.md: -------------------------------------------------------------------------------- 1 | # Pos 2 | 3 | Posは正数(1以上の整数)を表す型です。 4 | 0が入らないので、ゼロ除算の可能性を排除できるなどのメリットがあります。 5 | 6 | ## Def 7 | 8 | `Pos = 1.._` 9 | -------------------------------------------------------------------------------- /doc/JA/python/python_vers.txt: -------------------------------------------------------------------------------- 1 | version magic number 2 | 3.7.5 3394 3 | 3.8.0 3413 4 | 3.8.5 3413 5 | 3.9.0 3425 6 | 3.9.1 3425 7 | -------------------------------------------------------------------------------- /compiler/erg_compiler/tests/fib.er: -------------------------------------------------------------------------------- 1 | fib 0 = 0 2 | fib 1 = 1 3 | fib(n: 2.. Self! V, K 8 | -------------------------------------------------------------------------------- /doc/JA/API/consts.md: -------------------------------------------------------------------------------- 1 | # 組み込み定数 2 | 3 | ## True 4 | 5 | ## False 6 | 7 | ## None 8 | 9 | ## Ellipsis 10 | 11 | ## NotImplemented 12 | 13 | ## Inf 14 | -------------------------------------------------------------------------------- /doc/JA/API/types/classes/Array!(T).md: -------------------------------------------------------------------------------- 1 | # Array! T 2 | 3 | 可変長配列を表す型。コンパイル時に長さがわからない場合に使う。`[T]!`という糖衣構文がある。 4 | `Array! T = ArrayWithMutLength! T, !_`で定義される。 5 | -------------------------------------------------------------------------------- /doc/JA/API/types/classes/Matrix.md: -------------------------------------------------------------------------------- 1 | # Matrix T: Num, Shape: [M, N] 2 | 3 | 行列を表す型です。Tensor [M, N]を継承しています。 4 | 5 | ## def 6 | 7 | Inherit Tensor T, [M, N] 8 | -------------------------------------------------------------------------------- /doc/JA/API/types/traits/SafeDiv(R,O).md: -------------------------------------------------------------------------------- 1 | # SafeDiv R, O 2 | 3 | ```erg 4 | SafeDiv R, O = Subsume Div, { 5 | @Override 6 | .`/` = Self.(R) -> O 7 | } 8 | ``` 9 | -------------------------------------------------------------------------------- /examples/fib.er: -------------------------------------------------------------------------------- 1 | fib 0 = 0 2 | fib 1 = 1 3 | # a type annotation is required for the recursive function 4 | fib(n: Nat): Nat = fib(n-1) + fib(n-2) 5 | 6 | assert fib(10) == 55 7 | -------------------------------------------------------------------------------- /doc/JA/API/types/classes/Neg.md: -------------------------------------------------------------------------------- 1 | # Neg 2 | 3 | 負の整数を表す型です。Pos and Neg and {0} == Intとなります。 4 | ゼロ除算が起きない、Neg * Neg == Posとなるなど、いくつか特筆すべき性質も持っています。 5 | 6 | ## def 7 | 8 | Inf<..-1 9 | -------------------------------------------------------------------------------- /compiler/erg_compiler/README.md: -------------------------------------------------------------------------------- 1 | # The Erg compiler (codename: Centimetre) 2 | 3 | The overall structure is described in detail in [architecture.md](../../doc/JA/compiler/architecture.md). 4 | -------------------------------------------------------------------------------- /doc/JA/API/types/classes/Result.md: -------------------------------------------------------------------------------- 1 | # Result T, E 2 | 3 | ```erg 4 | Result T, E <: Error = Either T, E 5 | ``` 6 | 7 | `Option`と同じく「失敗するかもしれない値」を表すが、失敗時のコンテクストを持てる。使い方は`Either`とほぼ同じである。 8 | -------------------------------------------------------------------------------- /examples/helloworld.er: -------------------------------------------------------------------------------- 1 | print! "Hello, world!" 2 | print! "こんにちは、世界!" 3 | print! "Γειά σου Κόσμε!" 4 | print! "!مرحبا بالعالم" 5 | 6 | greeting = "Hello" 7 | print! "{greeting}, world!" 8 | -------------------------------------------------------------------------------- /compiler/erg_parser/tests/dependent.er: -------------------------------------------------------------------------------- 1 | concat|T: Type, M, N: Nat|(l: [T; M], r: [T; N]): [T; M + N] = l + r 2 | 3 | l: [Nat; 6] = concat [1, 2, 3], [4, 5, 6] 4 | assert l == [1, 2, 3, 4, 5, 6] 5 | -------------------------------------------------------------------------------- /doc/JA/API/types/traits/Div(R,O).md: -------------------------------------------------------------------------------- 1 | # Div R, O 2 | 3 | ゼロ除算によるエラーがない場合は`SafeDiv`を使ってください。 4 | 5 | ```erg 6 | Div R, O = Trait { 7 | .`/` = Self.(R) -> O or Panic 8 | } 9 | ``` 10 | -------------------------------------------------------------------------------- /compiler/erg_compiler/tests/dependent.er: -------------------------------------------------------------------------------- 1 | concat|T: Type, M, N: Nat|(l: [T; M], r: [T; N]): [T; M + N] = l + r 2 | 3 | l: [Nat; 6] = concat [1, 2, 3], [4, 5, 6] 4 | assert l == [1, 2, 3, 4, 5, 6] 5 | -------------------------------------------------------------------------------- /doc/JA/API/types/classes/Function(N).md: -------------------------------------------------------------------------------- 1 | # Function N: Nat 2 | 3 | ## methods of Function 1 4 | 5 | * then(self, g: Self) -> Self 6 | 7 | ```erg 8 | assert f(g(x)) == f.then(g) x 9 | ``` 10 | -------------------------------------------------------------------------------- /tests/fizzbuzz.er: -------------------------------------------------------------------------------- 1 | for! 1..100, i => 2 | match (i % 3, i % 5): 3 | 0, 0 => print! "FizzBuzz" 4 | 0, _ => print! "Fizz" 5 | _, 0 => print! "Buzz" 6 | _ => print! i 7 | -------------------------------------------------------------------------------- /doc/JA/API/types/classes/Either.md: -------------------------------------------------------------------------------- 1 | # Either L, R = L or R 2 | 3 | 「LかRかどちらか」を表す型。Or型の2つ限定形と考えて良い。 4 | 5 | ## methods 6 | 7 | * orl 8 | * orr 9 | * andl 10 | * andr 11 | * mapl 12 | * mapr 13 | -------------------------------------------------------------------------------- /doc/JA/syntax/15_type.md: -------------------------------------------------------------------------------- 1 | # 型 2 | 3 | 型はErgにおいて非常に重要な機能ですので、[専用のセクション](./type/01_type_system.md)を用意しています。そちらをご覧ください。 4 | 5 |

6 | Previous | Next 7 |

8 | -------------------------------------------------------------------------------- /doc/JA/API/types/classes/Complex.md: -------------------------------------------------------------------------------- 1 | # Complex 2 | 3 | 複素数を表す型です。Ergで数字を表す型、例えばFloatやInt、Natなどは、大抵この型を上位に持ちます。 4 | 5 | ## supers 6 | 7 | Num and Norm 8 | 9 | ## methods 10 | 11 | * abs 12 | * conjugate 13 | * imag 14 | * real 15 | -------------------------------------------------------------------------------- /doc/JA/API/types/classes/Inf.md: -------------------------------------------------------------------------------- 1 | # Inf 2 | 3 | Infはinfただひとつをインスタンスとするクラスである。 4 | infの主な使いみちは、区間型での使用である。 5 | 例えば、2以上の整数型は`2.. T 10 | 11 | 変換を行います。 12 | -------------------------------------------------------------------------------- /doc/JA/API/types/traits/Num.md: -------------------------------------------------------------------------------- 1 | # Num 2 | 3 | ## definition 4 | 5 | ```erg 6 | Num R = Add(R) and Sub(R) and Mul(R) and Eq 7 | Num = Num Self 8 | ``` 9 | 10 | ## supers 11 | 12 | Add and Sub and Mul and Eq 13 | 14 | ## methods 15 | 16 | * `abs` 17 | -------------------------------------------------------------------------------- /doc/JA/API/modules/status.md: -------------------------------------------------------------------------------- 1 | # module `status` 2 | 3 | 状態を表す型が定義されています。状況に応じて選択肢を外したりして使用してください。 4 | 5 | * ExecResult = {"success", "warning", "failure", "fatal", "unknown"} 6 | * ExecStatus = {"ready", "running", "sleeping", "plague", "completed", "terminated"} 7 | -------------------------------------------------------------------------------- /doc/JA/API/types/classes/Str.md: -------------------------------------------------------------------------------- 1 | # Str 2 | 3 | (不変長)文字列を表す型。単なる`Str`型は`StrWithLen N`型から文字数の情報を落とした型である(`Str = StrWithLen _`)。 4 | 5 | ## methods 6 | 7 | * isnumeric 8 | 9 | 文字列がアラビア数字であるかを返す。漢数字やその他の数字を表す文字の判定は`isunicodenumeric`を使う(この挙動はPythonと違うので注意)。 10 | -------------------------------------------------------------------------------- /doc/JA/dev_guide/features.md: -------------------------------------------------------------------------------- 1 | # `erg` build feature 2 | 3 | ## debug 4 | 5 | デバッグモードにする。これにより、Erg内部での挙動が逐次ログ表示される。 6 | Rustのdebug_assertionsフラグとは独立。 7 | 8 | ## japanese 9 | 10 | システム言語を日本語にする。 11 | Erg内部のオプション、ヘルプ(help, copyright, licenseなど)、エラー表示は日本語化が保証される。 12 | -------------------------------------------------------------------------------- /doc/JA/compiler/TODO_hint.md: -------------------------------------------------------------------------------- 1 | # Hint (not implemented) 2 | 3 | * `x is not defined` (x was deleted by `del`) => `hint: deleted in line X` 4 | * patch method duplication: "hint: Specify patch (like `T.foo(1)`) or delete either `.foo` using `del`" 5 | * `x was moved in line X` 6 | -------------------------------------------------------------------------------- /doc/EN/syntax/15_type.md: -------------------------------------------------------------------------------- 1 | # types 2 | 3 | Types are a very important feature in Erg, so we have a [dedicated section](./type/01_type_system.md). Please see there. 4 | 5 |

6 | Previous | Next 7 |

8 | -------------------------------------------------------------------------------- /doc/JA/tools/repl.md: -------------------------------------------------------------------------------- 1 | # REPL 2 | 3 | `erg`コマンドを引数を与えず実行すると、REPLが起動されます。また、`repl`サブコマンドを指定して起動することもできます。 4 | さらに以下のフラグを指定できます。 5 | 6 | * typed: オブジェクトとその型を表示します。 7 | 8 | ```console 9 | >>> 1 10 | 1: {1} 11 | >>> id x = x 12 | id = : |T: Type| T -> T 13 | ``` 14 | -------------------------------------------------------------------------------- /doc/JA/compiler/query.md: -------------------------------------------------------------------------------- 1 | # About Query system 2 | 3 | query systemはErg compiler(以下ergc)の採用する(予定の)コンパイルシステムです。 4 | ergcはパスベースではなくデマンドベースのコンパイルを行います。つまり、最終的な目標であるバイトコード生成に必要なものを取得するためクエリ(照会要求)を生成し、クエリに従って連鎖的に処理を進めていきます。クエリの実行結果はキャッシュされるため、理想的にはスクリプトの差分だけコンパイルするincremental compileが可能となります。 5 | -------------------------------------------------------------------------------- /doc/JA/API/types/classes/Nat.md: -------------------------------------------------------------------------------- 1 | # Nat 2 | 3 | 自然数を表す型。配列のインデックスや範囲型などで使われる。 4 | 5 | ## def 6 | 7 | ```erg 8 | Nat = 0.._ 9 | ``` 10 | 11 | ## methods 12 | 13 | * times!(self, p: () => NoneType) -> NoneType 14 | 15 | ```erg 16 | 100.times! () => 17 | print! "hello!" 18 | ``` 19 | -------------------------------------------------------------------------------- /doc/JA/syntax/type/09_attributive.md: -------------------------------------------------------------------------------- 1 | # 属性型(Attributive Type) 2 | 3 | 属性型は、レコードおよびデータクラス、パッチ、モジュールなどが含まれる型です。 4 | 属性型に属する型は値型ではありません。 5 | 6 | ## レコード型の合成 7 | 8 | 合成されたレコード型は平坦化できます。例えば、`{...{.name = Str; .age = Nat}; ...{.name = Str; .id = Nat}}`は`{.name = Str; .age = Nat; .id = Nat}`となります。 9 | -------------------------------------------------------------------------------- /tests/test.rs: -------------------------------------------------------------------------------- 1 | extern crate erg; 2 | 3 | mod tests { 4 | /* 5 | use erg_common::config::{ErgConfig, Input}; 6 | use erg_common::error::MultiErrorFmt; 7 | use erg_common::traits::Runnable; 8 | 9 | const FILE3: &str = "tests/test3_object_system.er"; 10 | */ 11 | } 12 | -------------------------------------------------------------------------------- /doc/JA/syntax/08_procedure.md: -------------------------------------------------------------------------------- 1 | # プロシージャ 2 | 3 | プロシージャは可変オブジェクトを取り扱う際に必要となるが、可変オブジェクトを引数に持てばプロシージャであるとは限らない。 4 | 5 | ```erg 6 | peek_str s: Str! = log s 7 | ``` 8 | 9 |

10 | Previous | Next 11 |

12 | -------------------------------------------------------------------------------- /doc/JA/API/types/classes/Int.md: -------------------------------------------------------------------------------- 1 | # Int 2 | 3 | 整数(Integer)を表すクラスです。インスタンスは0, 1, -1, 300000などがあります。 4 | 多くの言語では自然数を表す場合でもInt(に相当する型)を使用しますが、Ergではuse smaller typesの原則により、 5 | Nat, NZInt, Interval型などを使用することが推奨されます。 6 | IntはPythonに由来する型であり、その上位型には`Object`のみを持ちます。 7 | 8 | ## supers 9 | 10 | ## methods 11 | -------------------------------------------------------------------------------- /doc/JA/API/types/classes/TransCell(T).md: -------------------------------------------------------------------------------- 1 | # TransCell! T: Type! 2 | 3 | 中身を型ごと変えられるセルです。T型のサブタイプとなるので、T型としても振る舞います。 4 | 初期化時点ではT型で、ある時点以降はずっとU型、といった場合に便利です。 5 | 6 | ```erg 7 | a = TransCell!.new None 8 | a: TransCell! !NoneType 9 | a.set! 1 10 | a: TransCell! !Int 11 | assert a + 1 == 2 12 | ``` 13 | -------------------------------------------------------------------------------- /doc/JA/API/types/traits/Unpack.md: -------------------------------------------------------------------------------- 1 | # Unpack 2 | 3 | マーカートレイト。実装すると、レコードのようにパターンマッチで要素を分解できる。 4 | 5 | ```erg 6 | C = Class {i = Int}, Impl=Unpack 7 | C.new i = Self::new {i;} 8 | {i} = C.new(1) 9 | D = Class C or Int 10 | log match D.new(1): 11 | (i: Int) -> i 12 | ({i}: C) -> i 13 | ``` 14 | -------------------------------------------------------------------------------- /doc/JA/compiler/TODO_warn.md: -------------------------------------------------------------------------------- 1 | # warnings (not implemented yet) 2 | 3 | * `t = {(record type)}` => `T = {(record type)}`? (only types defined as constants can be used for type specification) 4 | * `{I: Int | ...}!` => `{I: Int! | ...}` 5 | * `return x`(`x != ()`) in for/while block => `f::return` (outer block)? 6 | -------------------------------------------------------------------------------- /examples/patch.er: -------------------------------------------------------------------------------- 1 | Binary = Patch {0, 1} 2 | Binary. 3 | invert self = 4 | if self == 0, 1 else 0 5 | assert 1.invert() == 0 6 | assert 0.invert() == 1 7 | 8 | Nat = Patch {I | I >= 0} 9 | Nat.times! self, block! = 10 | for! 0.. block!() 11 | 10.times! do!: 12 | print! "!" 13 | -------------------------------------------------------------------------------- /examples/quantified.er: -------------------------------------------------------------------------------- 1 | id|T|(x: T): T = x 2 | assert id(1) == 1 3 | assert id(True) == True 4 | assert id("hello") == "hello" 5 | 6 | const|T, C|(c: C): C = _: T -> c 7 | assert const(1)(2) == 1 8 | assert const(True)(2) == True 9 | 10 | print_to_str!|S <: Show|(s: S): Str = 11 | print! s 12 | s.to_str() 13 | -------------------------------------------------------------------------------- /doc/JA/syntax/09_builtin_procs.md: -------------------------------------------------------------------------------- 1 | # 組み込みプロシージャ 2 | 3 | ## id! 4 | 5 | オブジェクトのユニークな識別番号を返す。 6 | 純粋なErgの意味論の中では同一の構造を持つオブジェクトの間に差異を見出す事はできないが、実際のところ、オブジェクトはメモリ上の位置が異なる。`id!`はこの位置を表す数値を返す。 7 | 8 | ```erg 9 | ``` 10 | 11 |

12 | Previous | Next 13 |

14 | -------------------------------------------------------------------------------- /doc/JA/dev_guide/env.md: -------------------------------------------------------------------------------- 1 | # Development Environment 2 | 3 | ## Rust 4 | 5 | * ver >= 1.58.0 6 | * 2021 edition 7 | 8 | ## Recommended Development Environment 9 | 10 | * Editor: Visual Studio Code 11 | * VSCode Extensions: Rust-analyzer, GitLens, Git Graph, GitHub Pull Requests and Issues 12 | * OS: Windows 10/11 | Ubuntu 20.04 | MacOS Monterey 13 | -------------------------------------------------------------------------------- /doc/JA/API/types/classes/Subroutine.md: -------------------------------------------------------------------------------- 1 | # Subroutine 2 | 3 | FuncやProcの基底型です。 4 | 5 | ## methods 6 | 7 | * return 8 | 9 | サブルーチンを中断して、指定した値を返す。ネストから一気に脱出する際に便利。 10 | 11 | ```erg 12 | f x = 13 | for 0..10, i -> 14 | if i == 5: 15 | do 16 | f::return i 17 | do 18 | log i 19 | ``` 20 | -------------------------------------------------------------------------------- /doc/JA/tools/build.md: -------------------------------------------------------------------------------- 1 | # buildサブコマンド 2 | 3 | buildサブコマンドでは、パッケージのビルドを行います。 4 | デフォルトのビルドで行われる工程は、以下の通りです。 5 | 6 | 1. コメント/ドキュメント(doc以下のmdファイル)内のコードを検査する。 7 | 2. パッケージに必要なコードをコンパイルする。 8 | 3. アプリケーションパッケージの場合は、コマンド相当のバッチファイルまたはシェルスクリプトを生成する。 9 | 4. テストを実行する。 10 | 11 | ビルド終了後の成果物は以下のディレクトリに出力されます。 12 | 13 | * デバッグビルド時: build/debug 14 | * リリースビルド時: build/release 15 | -------------------------------------------------------------------------------- /doc/JA/tools/install.md: -------------------------------------------------------------------------------- 1 | # installサブコマンド 2 | 3 | installでレジストリサイトに登録されたパッケージをインストールできる。 4 | 基本的な使い方はcargoなどのパッケージマネージャと同じ。 5 | 6 | ## 便利機能 7 | 8 | * 似た名前のパッケージ名があり、そちらのほうが10倍以上ダウンロード数が多かった場合、間違えて入力したのではないかというサジェスチョンが出る。これにより、typo squattingを防止できる。 9 | * パッケージサイズが大きい場合(50MB以上)、サイズを表示して本当にインストールするかサジェスチョンする。 10 | * パッケージがduplicatedになっていた場合、代替のパッケージをサジェスチョンする。 11 | -------------------------------------------------------------------------------- /compiler/erg_common/color.rs: -------------------------------------------------------------------------------- 1 | //! Escape sequences change the color of the terminal 2 | 3 | pub const RESET: &str = "\x1b[m"; 4 | pub const DEEP_RED: &str = "\x1b[31m"; 5 | pub const RED: &str = "\x1b[91m"; 6 | pub const GREEN: &str = "\x1b[92m"; 7 | pub const YELLOW: &str = "\x1b[93m"; 8 | pub const BLUE: &str = "\x1b[94m"; 9 | pub const CYAN: &str = "\x1b[96m"; 10 | -------------------------------------------------------------------------------- /compiler/erg_parser/lib.rs: -------------------------------------------------------------------------------- 1 | //! Implements `Parser` for Erg. `Parser` parses the source code to generate `AST`, 2 | //! and performs type checking and other optimizations if necessary. 3 | extern crate erg_common; 4 | 5 | pub mod ast; 6 | pub mod desugar; 7 | pub mod error; 8 | pub mod lex; 9 | pub mod parse; 10 | pub mod token; 11 | 12 | pub use parse::{Parser, ParserRunner}; 13 | -------------------------------------------------------------------------------- /examples/dict.er: -------------------------------------------------------------------------------- 1 | immut_dict: {Str: Int} = {"Alice": 1, "Bob": 2, "Charlie": 3} 2 | # can insert / remove an element 3 | telescoping_dict = {"Alice": 1, "Bob": 2, "Charlie": 3}.into {Str: Int; !*} 4 | telescoping_dict.insert!("Dave", 4) 5 | _ = telescoping_dict.remove!("Alice") 6 | mut_content_dict: {Str: !Int} = {"Alice": !1, "Bob": !2, "Charlie": !3} 7 | mut_content_dict["Bob"].update! 0 8 | -------------------------------------------------------------------------------- /examples/add.er: -------------------------------------------------------------------------------- 1 | Point = Class {x = Int; y = Int}, Impl: Add() and Eq() 2 | Point. 3 | new x, y = Self::__new__ {x; y} 4 | norm &self = self::x**2 + self::y**2 5 | @Impl Add() 6 | `+` self, other = 7 | Self.new(self::x + other::x, self::y + other::y) 8 | 9 | p = Point.new 1, 2 10 | q = Point.new 3, 4 11 | r = p + q 12 | assert r == Point.new 4, 6 13 | assert r.norm() == 52 14 | -------------------------------------------------------------------------------- /compiler/erg_compiler/tests/side_effect.er: -------------------------------------------------------------------------------- 1 | if True, () -> log "hello" 2 | if! True, () => print! "hello" 3 | # if True, () => print! "hello" # this should cause a type error 4 | if True, () -> 5 | _x = "aaa" + input!() # this should cause an effect error 6 | print! "hello" # this should cause an effect error 7 | 8 | f x: Int = log x 9 | g x: Int = print! x # this should cause an effect error 10 | -------------------------------------------------------------------------------- /doc/JA/dev_guide/doc_guideline.md: -------------------------------------------------------------------------------- 1 | # 書式 2 | 3 | 以下のルールに従っていないドキュメントはすべて修正の対象となる。 4 | 5 | * コードコメント、または内部用のドキュメントは、である調で書く。 6 | * 外部に見せるドキュメントは、ですます調で書く。 7 | * ドキュメント内で初出の用語は、必ず定義や意味、またはリンクを併記する。 8 | * ただし書きとしての()は、補助的ではあるものの本文の理解に必要な文の場合のみ使用し、本文の理解に必須でない文は脚注を使用する[1](#1)。 9 | 10 | --- 11 | 12 | 1 脚注の書き方はこれを参照すること。 [↩](#f1) 13 | -------------------------------------------------------------------------------- /examples/slot.ts: -------------------------------------------------------------------------------- 1 | const assert = console.assert 2 | 3 | const john = { 4 | name: "John Smith", 5 | age: 27, 6 | } 7 | 8 | assert(john.name == "John Smith") 9 | 10 | type Person = { 11 | readonly name: String, 12 | readonly age: number, 13 | } 14 | 15 | // assert(Person['age'] == String) 16 | 17 | function isPerson(arg): arg is Person { return true } 18 | 19 | assert(isPerson(john)) 20 | -------------------------------------------------------------------------------- /doc/JA/API/types/classes/Ratio.md: -------------------------------------------------------------------------------- 1 | # Ratio 2 | 3 | 有理数を表す型です。主に、分数を使いたいときに使います。 4 | 実はErgでの/演算子はRatioを返します。1/3などは0.33333...とは評価されず1/3のまま処理されます。また、0.1は1/10と等価です。なので、`0.1 + 0.2 == 0.3`となります。当たり前のように聞こえますが、PythonではなんとFalseになります。 5 | とはいえ、Ratio型はFloat型に比べて若干効率が下がる傾向があります。そこまで正確な数値は要らず、かつ実行速度が重要となるポイントではFloat型を使用するといいでしょう。とはいえ、Rob Pikeが言うように早すぎる最適化は諸悪の根源です。Ratio型を捨ててFloat型を使用するのは実際にパフォーマンステストを行ってからにしましょう。素人ほど無条件に軽量な型を好みます。 6 | -------------------------------------------------------------------------------- /doc/JA/API/types/classes/Record.md: -------------------------------------------------------------------------------- 1 | # Record 2 | 3 | レコードの属するクラス。例えば`{i = 1}`は`Structural {i = Int}`型などの要素であり、`{i = Int}`クラスのインスタンスである。 4 | 他のクラスのインスタンスはレコード型の要素であってもレコードクラスのインスタンスではないことに注意。 5 | 6 | ```erg 7 | assert not Structural({i = Int}) in Class 8 | assert {i = Int} in Class 9 | 10 | C = Class {i = Int} 11 | c = C.new {i = 1} 12 | assert c in Structural {i = Int} 13 | assert not c in {i = Int} 14 | ``` 15 | -------------------------------------------------------------------------------- /doc/JA/compiler/abandoned.md: -------------------------------------------------------------------------------- 1 | # 放棄・却下された言語仕様 2 | 3 | ## オーバーロード(アドホック多相) 4 | 5 | パラメトリック+サブタイピング多相で代替できること、Pythonの意味論との相性の悪さなどを理由に放棄された。詳しくは[overload](../syntax/type/overloading.md)の記事を参照。 6 | 7 | ## 明示的ライフタイム付き所有権システム 8 | 9 | Rustのような所有権システムを導入する予定だったが、Pythonの意味論との相性の悪さ、ライフタイム注釈など煩雑な仕様の導入が必要であることなどから放棄され、不変オブジェクトは全てRCで管理され、可変オブジェクトの所有権は1つのみ、という文法になった。 10 | DyneはC#, NimのようにGILを持たず、値オブジェクトや安全な範囲での低レベル操作もできるようにする方針である。 11 | -------------------------------------------------------------------------------- /doc/JA/tools/env.md: -------------------------------------------------------------------------------- 1 | # envサブコマンド 2 | 3 | envサブコマンドはerg実行環境の指定を行います。 4 | `erg env new [env name]`で新しい実行環境を作成します。対話ツールが開き、ergのバージョンを指定すると、そのバージョンのergがインストール(すでにあれば流用されます)され、新しい環境として使えるようになります。 5 | `erg env switch [env name]`で環境の切り替えができます。 6 | 作成された環境は`erg env edit`で編集でき、パッケージをプリインストールしたり、他言語の依存関係を指定できる。 7 | このコマンドの最大の特徴は`erg env export`で環境を再現する情報を`[env name].env.er`ファイルとして出力できる点である。これにより、他人と同じ環境ですぐに開発を始められる。さらに`erg env publish`でパッケージのように環境を公開できる。 8 | -------------------------------------------------------------------------------- /compiler/erg_compiler/lib.rs: -------------------------------------------------------------------------------- 1 | //! defines the compiler for Erg (ergc). 2 | extern crate erg_common; 3 | pub extern crate erg_parser; 4 | 5 | mod compile; 6 | pub use compile::*; 7 | mod codegen; 8 | pub mod effectcheck; 9 | pub mod error; 10 | pub mod eval; 11 | pub mod hir; 12 | pub mod initialize; 13 | pub mod lower; 14 | pub use lower::ASTLowerer; 15 | pub mod context; 16 | pub mod optimize; 17 | pub mod ownercheck; 18 | pub mod varinfo; 19 | -------------------------------------------------------------------------------- /doc/JA/API/types/classes/IntRange.md: -------------------------------------------------------------------------------- 1 | # IntRange L, R 2 | 3 | `L..R`のクラス。 4 | 5 | ```erg 6 | IntRange L, R: Int == L..R 7 | ``` 8 | 9 | ## methods 10 | 11 | * .`_+_`: Self(L1, R1), Self(L2, R2) -> Self(L1+L2, R1+R2) 12 | 13 | 通常の加算。`Int`や`Nat`の加算はそれぞれのクラスで定義されていると見せかけて、ここで定義されている。 14 | 15 | ```erg 16 | 0..10 + 1..12 == 1..22 17 | Int + 0..10 == _..|Int|_ + 0..10 == _..|Int|_ == Int 18 | Nat + Nat == 0.._ + 0.._ == 0.._ == Nat 19 | ``` 20 | -------------------------------------------------------------------------------- /doc/EN/syntax/08_procedure.md: -------------------------------------------------------------------------------- 1 | # Procedures 2 | 3 | Procedures are necessary when dealing with mutable objects, but having a mutable object as an argument does not necessarily make it a procedure. 4 | Here is a function takes a mutable object (not procedure). 5 | 6 | ```erg 7 | peek_str s: Str! = log s 8 | ``` 9 | 10 |

11 | Previous | Next 12 |

13 | -------------------------------------------------------------------------------- /doc/JA/API/types/classes/Interval.md: -------------------------------------------------------------------------------- 1 | # Interval begin, end: WellOrder 2 | 3 | 整列集合型(WellOrder)の部分型を表す型です。Interval型にはPreOpen(x<..y)などの派生型が存在します。 4 | 5 | ```erg 6 | Months = 1..12 7 | Alphabet = "a".."z" 8 | Weekdays = Monday..Friday 9 | Winter = November..December or January..February 10 | ``` 11 | 12 | ```erg 13 | 0..1 # 整数の範囲 14 | 0.0..1.0 # 実数(有理数)の範囲 15 | # or 0/1..1/1でも同じ 16 | ``` 17 | 18 | コンピュータは無限桁の数を上手く扱えないので、実数の範囲と言っても実際は有理数の範囲である。 19 | -------------------------------------------------------------------------------- /doc/JA/API/modules/repl.md: -------------------------------------------------------------------------------- 1 | # module `repl` 2 | 3 | provides REPL(Read-Eval-Print-Loop)-related APIs. 4 | 5 | ## functions 6 | 7 | * `gui_help` 8 | 9 | オブジェクトに関する情報をブラウザで表示する。オフラインでも使用可能。 10 | 11 | ## types 12 | 13 | ### Guess = Object 14 | 15 | #### methods 16 | 17 | * `.guess` 18 | 19 | 与えられた引数と戻り値から、関数を推測する。 20 | 21 | ```erg 22 | 1.guess((1,), 2) # 23 | [1, 2].guess((3, 4), [1, 2, 3, 4]) # 24 | ``` 25 | -------------------------------------------------------------------------------- /.github/workflows/rust.yml: -------------------------------------------------------------------------------- 1 | name: Rust 2 | 3 | on: 4 | push: 5 | branches: [ main ] 6 | pull_request: 7 | branches: [ main ] 8 | 9 | env: 10 | CARGO_TERM_COLOR: always 11 | 12 | jobs: 13 | build: 14 | 15 | runs-on: ubuntu-latest 16 | 17 | steps: 18 | - uses: actions/checkout@v2 19 | - uses: Swatinem/rust-cache@v2 20 | - name: Build 21 | run: cargo build --verbose 22 | - name: Run tests 23 | run: cargo test --verbose 24 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Generated by Cargo 2 | # will have compiled files and executables 3 | /target/ 4 | 5 | # Remove Cargo.lock from gitignore if creating an executable, leave it for libraries 6 | # More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html 7 | Cargo.lock 8 | 9 | # These are backup files generated by rustfmt 10 | **/*.rs.bk 11 | *.pyc 12 | /.vscode/ 13 | /.VSCodeCounter/ 14 | /.vs/ 15 | /.DS_Store 16 | /*/.DS_Store 17 | /.idea/ 18 | /timeit.dat -------------------------------------------------------------------------------- /src/.gitignore: -------------------------------------------------------------------------------- 1 | # Generated by Cargo 2 | # will have compiled files and executables 3 | /target/ 4 | 5 | # Remove Cargo.lock from gitignore if creating an executable, leave it for libraries 6 | # More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html 7 | Cargo.lock 8 | 9 | # These are backup files generated by rustfmt 10 | **/*.rs.bk 11 | *.pyc 12 | /.vscode/ 13 | /.VSCodeCounter/ 14 | /.vs/ 15 | /.DS_Store 16 | /*/.DS_Store 17 | /.idea/ 18 | /timeit.dat -------------------------------------------------------------------------------- /doc/EN/syntax/09_builtin_procs.md: -------------------------------------------------------------------------------- 1 | # Built-in procedure 2 | 3 | ## id! 4 | 5 | Returns the unique identification number of the object. 6 | Although in pure Erg semantics no difference can be found between objects with the same structure, in practice objects have different locations in memory. 7 | `id!` returns a number representing this position. 8 | 9 | ```erg 10 | ``` 11 | 12 |

13 | Previous | Next 14 |

15 | -------------------------------------------------------------------------------- /compiler/erg_common/.gitignore: -------------------------------------------------------------------------------- 1 | # Generated by Cargo 2 | # will have compiled files and executables 3 | /target/ 4 | 5 | # Remove Cargo.lock from gitignore if creating an executable, leave it for libraries 6 | # More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html 7 | Cargo.lock 8 | 9 | # These are backup files generated by rustfmt 10 | **/*.rs.bk 11 | *.pyc 12 | /.vscode/ 13 | /.VSCodeCounter/ 14 | /.vs/ 15 | /.DS_Store 16 | /*/.DS_Store 17 | /.idea/ 18 | /timeit.dat -------------------------------------------------------------------------------- /compiler/erg_parser/.gitignore: -------------------------------------------------------------------------------- 1 | # Generated by Cargo 2 | # will have compiled files and executables 3 | /target/ 4 | 5 | # Remove Cargo.lock from gitignore if creating an executable, leave it for libraries 6 | # More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html 7 | Cargo.lock 8 | 9 | # These are backup files generated by rustfmt 10 | **/*.rs.bk 11 | *.pyc 12 | /.vscode/ 13 | /.VSCodeCounter/ 14 | /.vs/ 15 | /.DS_Store 16 | /*/.DS_Store 17 | /.idea/ 18 | /timeit.dat -------------------------------------------------------------------------------- /compiler/erg_compiler/.gitignore: -------------------------------------------------------------------------------- 1 | # Generated by Cargo 2 | # will have compiled files and executables 3 | /target/ 4 | 5 | # Remove Cargo.lock from gitignore if creating an executable, leave it for libraries 6 | # More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html 7 | Cargo.lock 8 | 9 | # These are backup files generated by rustfmt 10 | **/*.rs.bk 11 | *.pyc 12 | /.vscode/ 13 | /.VSCodeCounter/ 14 | /.vs/ 15 | /.DS_Store 16 | /*/.DS_Store 17 | /.idea/ 18 | /timeit.dat -------------------------------------------------------------------------------- /examples/dependent.er: -------------------------------------------------------------------------------- 1 | Queue! T: Type, N: Nat! = Class {.payload = [T; !N]} 2 | Queue!. 3 | new = Self!(*, 0)::__new__ {.payload = []} 4 | Queue!(T, N). 5 | enqueue!(ref!(self(T, N ~> N+1)), x: T) = 6 | self.payload.push! x 7 | dequeue!(ref! self(T, N ~> N-1)): T = 8 | self.payload.remove!(0) 9 | 10 | q = Queue!.new() 11 | q.enqueue!(1) 12 | q.enqueue!(2) 13 | q: Queue!(Int, !2) 14 | assert q.dequeue!() == 1 15 | assert q.dequeue!() == 2 16 | # q.dequeue!() will cause a TypeError 17 | -------------------------------------------------------------------------------- /doc/JA/migration_from_py.md: -------------------------------------------------------------------------------- 1 | # PythonからErgへの移行に関してのTips 2 | 3 | ## 文字列をint等に変換したい 4 | 5 | `Str`クラスの`parse`メソッドを使用してください。これは`Result`型を返します。 6 | 7 | ```python 8 | s: str 9 | i: int = int(s) 10 | ``` 11 | 12 | ```erg 13 | s: Str 14 | res: Result(Int, IntParseError) = s.parse Int 15 | i: Int = res.unwrap() 16 | f: Result(Float, FloatParseError) = s.parse Float 17 | ``` 18 | 19 | `try_from`メソッドも使えます。 20 | 21 | ```erg 22 | s: Str 23 | i: Int = Int.try_from(s).unwrap() 24 | f: Float = Float.try_from(s).unwrap() 25 | ``` 26 | -------------------------------------------------------------------------------- /doc/JA/API/types/classes/Never.md: -------------------------------------------------------------------------------- 1 | # Never 2 | 3 | 全ての型の下位型である。全てのメソッドを持っており、当然`.new`も持っているため`Class`である。しかしインスタンスは持たず、生成されそうになった瞬間にErgは停止する。 4 | `Panic`という同じくインスタンスを持たない型が存在するが、正常に終了する際や意図的な無限ループの際は`Never`、異常終了する際には`Panic`を使う。 5 | 6 | ```erg 7 | # Never <: Panic 8 | f(): Panic = exit 0 # OK 9 | g(): Never = panic() # TypeError 10 | ``` 11 | 12 | `Never`/`Panic`のOr型、例えば`T or Never`は`T`に変換することができる。これは、`Never`は意味論上起こり得ない(起こった場合プログラムは即時停止する)選択肢であるためである。 13 | しかし、関数の戻り値型などで使用する場合、プログラムの終了が起こりうることを示すため`or Never`を省略することはできない。 14 | -------------------------------------------------------------------------------- /doc/JA/syntax/type/guard.md: -------------------------------------------------------------------------------- 1 | # 型境界 (Type Bound) 2 | 3 | 型境界は型指定に条件を加えるものである。これを実現する機能がガード(ガード節)である。 4 | 関数シグニチャ、無名関数シグニチャのほか、篩型でもこの機能を利用できる。 5 | ガードは戻り値型の後に記述する。 6 | 7 | ## 述語式 (Predicate) 8 | 9 | 変数の満たす条件を、`Bool`を返す式(述語式)で指定できる。 10 | 使用できるのは[基本オブジェクト](./basic.md)と演算子だけである。 11 | 12 | ```erg 13 | f a: [T; N] | T, N, N > 5 = ... 14 | g a: [T; N | N > 5] | T, N = ... 15 | Odd = {I: Int | I % 2 == 1} 16 | R2Plus = {(L, R) | L, R: Ratio; L > 0 and R > 0} 17 | GeneralizedOdd = {I | U; I <: Div(Nat, U); I % 2 == 0} 18 | ``` 19 | -------------------------------------------------------------------------------- /examples/class.er: -------------------------------------------------------------------------------- 1 | @Inheritable 2 | Point2D = Class {x = Int; y = Int} 3 | Point2D. 4 | new x, y = Self::__new__ {x; y} 5 | norm ref self = self::x**2 + self::y**2 6 | 7 | Point3D = Inherit Point2D, Additional: {z = Int} 8 | Point3D. 9 | @Override 10 | new x, y, z = Self::__new__ {x; y; z} 11 | @Override 12 | norm ref self = self::x**2 + self::y**2 + self::z**2 13 | 14 | UnpackPoint2D = Class {x = Int; y = Int}, Impl: Unpack 15 | 16 | p = UnpackPoint2D.{x = 1; y = 2} 17 | UnpackPoint2D.{x; y} = p 18 | -------------------------------------------------------------------------------- /compiler/erg_parser/tests/ast_example.txt: -------------------------------------------------------------------------------- 1 | 1 + 2 * 3 2 | 3 | [1, 2, 3, *, +] 4 | 5 | x = 6 | y = 1 7 | z = 2 8 | 3 9 | 10 | [x y, 1, =, ;, z, 2, =, ;, 3, =] 11 | 12 | f 13 | 1 14 | 2 15 | 3 16 | 17 | # 直前が=, :=, ->, =>, do!なら改行はセミコロンと解釈し、それ以外ならコンマと解釈する 18 | [1, 2, ',', 3, ',', f] 19 | 20 | add! x, y = 21 | print! x, y 22 | print! x + y 23 | x + y 24 | 25 | add!(x, y) = (print! x, y;print! x + y; x + y) 26 | [add(x,y), NewBlock, x, y, ',', print!, ;, x, y, +, print!, ;, x, y, +, BlockEnd, = -------------------------------------------------------------------------------- /compiler/erg_parser/tests/test1_basic_syntax.er: -------------------------------------------------------------------------------- 1 | # 基本的な構文をパーサーがパスできるかチェックする 2 | # Check that a parser can pass the basic syntax 3 | 4 | _a = 1_234 + 1113.* 3_000.2e-4 ** 0003 * .4 5 | a, _, ...b = five_elem_tuple 6 | f x, y = 7 | x + y 8 | if! True, do! 9 | print! "\\hello, world\"" 10 | 10.times! do! 11 | if! x.y.z, do! 12 | print! "" 13 | # illegal indent 14 | # do_nothing! 15 | Hello = S2c "hello" 16 | aあ아 = 17 | # コメント 18 | "aaa" 19 | x; x;; x; 20 | 10..twelve; 21 | -------------------------------------------------------------------------------- /doc/JA/compiler/TODO_recov_suggest.md: -------------------------------------------------------------------------------- 1 | # Error recovery suggestions (not implemented yet) 2 | 3 | * `1 or 2`, `1 and 2` => `{1, 2}`? 4 | * `U = Inherit T` => Non-class type cannot be inherited, or `U = Class T`? 5 | * `Int and Str` => Multiple inheritance is not allowed, or `Int or Str`? 6 | * `: [1, 2]` => `: {1, 2}`? 7 | * `: [Int, 2]` => `: [Int; 2]`? 8 | * `[Int; Str]` => `(Int, Str)`(Tuple) or `[Int: Str]`(Dict)? 9 | * `{x: Int}` => `{x = Int}`? 10 | * `{x = Int}!` => `{x = Int!}`? 11 | * `ref! immut_expr` => `ref! !immut_expr`? 12 | -------------------------------------------------------------------------------- /doc/JA/API/types/classes/Tensor.md: -------------------------------------------------------------------------------- 1 | # Tensor Shape: [Nat; N] 2 | 3 | 多次元配列を効率的に操作するためのクラス。多次元配列に対する積などの演算も定義する。 4 | Matrix, Vectorなどはこの型を継承している。 5 | 6 | ```erg 7 | Tensor.arange(0..9) # Tensor [10] 8 | ``` 9 | 10 | * reshape(self, NewShape: [Nat; M]) -> Self NewShape 11 | 12 | ```erg 13 | (1..9).into(Tensor).reshape [3, 3] 14 | ``` 15 | 16 | * identity i: Nat -> Self shape: [Nat; N] 17 | * zeros(Shape: [Nat; N]) -> Self 18 | * ones(Shape: [Nat; N]) -> Self 19 | 20 | * diag 21 | 22 | * linspace 23 | * logspace 24 | * geomspace 25 | -------------------------------------------------------------------------------- /compiler/erg_compiler/optimize.rs: -------------------------------------------------------------------------------- 1 | use crate::error::CompileWarnings; 2 | use crate::hir::HIR; 3 | 4 | #[derive(Debug)] 5 | pub struct HIROptimizer {} 6 | 7 | impl HIROptimizer { 8 | pub fn fold_constants(&mut self, mut _hir: HIR) -> HIR { 9 | todo!() 10 | } 11 | 12 | pub fn eliminate_unused_variables(&mut self, mut _hir: HIR) -> (HIR, CompileWarnings) { 13 | todo!() 14 | } 15 | 16 | pub fn eliminate_dead_code(&mut self, mut _hir: HIR) -> (HIR, CompileWarnings) { 17 | todo!() 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /doc/JA/index.md: -------------------------------------------------------------------------------- 1 | # Index 2 | 3 | ## [API/](./API/index.md) 4 | 5 | Ergの組み込みまたは標準ライブラリで提供されるサブルーチン、型、定数等の仕様が記述されている。 6 | 7 | ## [compiler/](./compiler/index.md) 8 | 9 | Ergコンパイラ(Centimetre)の設計について解説されている。 10 | 11 | ## [dev_guide/](./dev_guide/index.md) 12 | 13 | プロジェクトの開発方針、コントリビューションの仕方などが解説されている。 14 | 15 | ## [python/](./python/index.md) 16 | 17 | Ergを開発する上で必要となるPythonの知識が解説されている。 18 | 19 | ## [syntax/](./syntax/00_basic.md) 20 | 21 | Ergの文法が解説されている。 22 | 23 | ## [tools/](./tools/index.md) 24 | 25 | Ergの周辺ツール、コマンドオプションの使い方などが解説されている。 26 | -------------------------------------------------------------------------------- /examples/record.er: -------------------------------------------------------------------------------- 1 | # Record is a feature similar to object (literal notation) in JS 2 | # `.` means the field is public 3 | john = { 4 | .name = "John Smith" 5 | .age = !27 6 | } 7 | 8 | assert john.name == "John Smith" 9 | assert john.age == 27 10 | john.age.update! old -> old + 1 11 | assert john.age == 28 12 | # Record is not Dict, so `john["name"]` is invalid 13 | 14 | # A record whose values are all types will also behave as a type 15 | Person! = { 16 | .name = Str 17 | .age = Nat! 18 | } 19 | 20 | assert Person!.age == Str 21 | assert john in Person! 22 | -------------------------------------------------------------------------------- /doc/JA/API/types/classes/Float.md: -------------------------------------------------------------------------------- 1 | # Float size 2 | 3 | 実数(小数を含む数)を表す型です。IEEE 754に準拠した浮動小数点数を表し、他の言語では一般的にfloatに相当する型です。 4 | Float sizeのsizeは、8(1byte)~128(16byte)となります。単にFloatとした場合`Float 64`を表します。 5 | Ergでの0.1は実はFloat型ではなく、Ratio型に属します。Float型のリテラルは存在せず、`(Ratioオブジェクト)f64`(e.g. (1/2)f64, 15f64)で生成します。f64は実数の1に対応します。 6 | 7 | ## supers 8 | 9 | Complex and Ord 10 | 11 | ## methods 12 | 13 | * sgn(self) -> {-1, 0, 1} 14 | 符号を返す。 15 | 16 | * truncate(self) -> Int 17 | 自身に最も近い整数を返す。 18 | 19 | * separate(self) -> [Str] 20 | * separate(self, dight: Nat) -> [Str] 21 | dight桁ごとに区切る。引数なしだと3。 22 | -------------------------------------------------------------------------------- /compiler/erg_common/build.rs: -------------------------------------------------------------------------------- 1 | use std::process::Command; 2 | // use std::io::Write; 3 | 4 | mod datetime; 5 | 6 | fn main() -> std::io::Result<()> { 7 | // recording the build date and the git hash 8 | let output = Command::new("git") 9 | .args(&["rev-parse", "--short", "HEAD"]) 10 | .output() 11 | .expect("failed to get the git hash"); 12 | let git_hash_short = String::from_utf8(output.stdout).unwrap(); 13 | let now = datetime::now(); 14 | println!("cargo:rustc-env=GIT_HASH_SHORT={git_hash_short}"); 15 | println!("cargo:rustc-env=BUILD_DATE={now}"); 16 | Ok(()) 17 | } 18 | -------------------------------------------------------------------------------- /doc/JA/API/types/classes/Option.md: -------------------------------------------------------------------------------- 1 | # Option T = T or NoneType 2 | 3 | 「失敗するかもしれない」を表す型。 4 | 5 | ## methods 6 | 7 | * unwrap(self, msg = "unwrapped a None value") -> T or Panic 8 | 9 | 中身が`T`型であると期待して取り出す。`None`であった場合`msg`を出力してパニックする。 10 | 11 | ```erg 12 | x = "...".parse(Int).into(Option Int) 13 | x.unwrap() # UnwrappingError: unwrapped a None value 14 | x.unwrap("failed to convert from string to number") # UnwrappingError: failed to convert from string to number 15 | ``` 16 | 17 | * unwrap_or(self, else: T) -> T 18 | 19 | * unwrap_or_exec(self, f: () -> T) -> T 20 | 21 | * unwrap_or_exec!(self, p!: () => T) -> T 22 | -------------------------------------------------------------------------------- /compiler/erg_parser/tests/test2_advanced_syntax.er: -------------------------------------------------------------------------------- 1 | # Check that a parser can pass the advanced syntax 2 | # 高度な文法をチェックする 3 | 4 | # overloading (多重定義) 5 | f x = 1 + x + 2 6 | f x, y = 7 | 1 + x + y 8 | f x, y, z = 9 | 1 + x + y + z 10 | assert 4 == f 1 11 | assert 4 == f 1, 1 12 | assert 3 == f 1, 1, 1 13 | 14 | # pattern overloading 15 | fib 0 = 0 16 | fib 1 = 1 17 | fib(n: Nat) -> Nat = fib(n-1) + fib(n-2) 18 | 19 | # keyword arguments (キーワード引数) 20 | t = if True: 21 | then: 1 22 | else: 2 23 | assert t == 1 24 | 25 | # import 26 | math = import "math" 27 | # {*} = "math" # use all 28 | {pi} = import "math" 29 | -------------------------------------------------------------------------------- /doc/EN/migration_from_py.md: -------------------------------------------------------------------------------- 1 | # Tips on migrating from Python to Erg 2 | 3 | ## Want to convert a string to an int, etc 4 | 5 | Use the `parse` method of the `Str` class. It returns a `Result` type. 6 | 7 | ```python 8 | # Python 9 | s: str 10 | i: int = int(s) 11 | ``` 12 | 13 | ```erg 14 | # Erg 15 | s: Str 16 | res: Result(Int, IntParseError) = s.parse Int 17 | i: Int = res.unwrap() 18 | f: Result(Float, FloatParseError) = s.parse Float 19 | ``` 20 | 21 | You can also use the `try_from` method. 22 | 23 | ```erg 24 | # Erg 25 | s: Str 26 | i: Int = Int.try_from(s).unwrap() 27 | f: Float = Float.try_from(s).unwrap() 28 | ``` 29 | -------------------------------------------------------------------------------- /doc/JA/API/types/classes/ArrayWithMutLength!(T,N).md: -------------------------------------------------------------------------------- 1 | # ArrayWithMutLength! T: Type, N: Nat! 2 | 3 | コンパイル時に長さのわかる可変長配列。`ArrayWithMutLength(T, !N) == [T; !N]`という糖衣構文もある。 4 | 5 | ## methods 6 | 7 | * push! ref! self(N ~> N+1, ...), elem: T 8 | 9 | * pop! ref! (N ~> N-1, ...) -> T 10 | 11 | * sample!(ref! self) -> T 12 | * sample! ref! self, M: Nat -> [T; M] 13 | 中の要素をランダムに選んでコピーを返す。 14 | 15 | * shuffle!(ref! self) 16 | 中身をシャッフルする。 17 | 18 | * assert_len ref! self(_ ~> N, ...), N: Nat -> () or Panic 19 | 長さを検証する。 20 | 長さが不正な場合は`panic!`する。 21 | 22 | ## Impl 23 | 24 | * From Range Int 25 | * From [T; N] 26 | * Num 27 | -------------------------------------------------------------------------------- /doc/JA/API/types/classes/NonZero.md: -------------------------------------------------------------------------------- 1 | # NonZero N 2 | 3 | ゼロではない数を表すクラスです。ゼロ除算の安全性が保証されます。 4 | 5 | ```mermaid 6 | classDiagram 7 | class NonZero~Int~ { 8 | ... 9 | } 10 | class Int { 11 | ... 12 | } 13 | class Div { 14 | <> 15 | /(Self, R) -> O or Panic 16 | } 17 | class SafeDiv { 18 | <> 19 | /(Self, R) -> O 20 | } 21 | Int <|-- NonZero~Int~: Inherit 22 | Div <|-- SafeDiv: Subsume 23 | SafeDiv <|.. NonZero~Int~: Impl 24 | Div <|.. Int: Impl 25 | ``` 26 | 27 | ## methods 28 | 29 | @Impl SafeDiv R, O 30 | .`/`: Self.(R) -> O 31 | -------------------------------------------------------------------------------- /compiler/erg_common/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "erg_common" 3 | version = "0.2.2" 4 | description = "A common components library of Erg" 5 | authors = ["Shunsuke Shibayama "] 6 | license = "MIT OR Apache-2.0" 7 | edition = "2021" 8 | repository = "https://github.com/erg-lang/erg/tree/main/src/erg_common" 9 | documentation = "https://docs.rs/erg_common" 10 | homepage = "https://erg-lang.github.io/" 11 | 12 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 13 | 14 | [features] 15 | debug = [] 16 | japanese = [] 17 | 18 | [dependencies] 19 | 20 | [lib] 21 | path = "lib.rs" 22 | -------------------------------------------------------------------------------- /examples/list.er: -------------------------------------------------------------------------------- 1 | Nil T = Class Impl: Phantom(T) and Eq 2 | Cons T, N = Inherit {head = T; rest = List(T, N-1)} 3 | List: (Type, Nat) -> Type 4 | List T, 0 = Class Nil T 5 | List T, N = Class Cons(T, N), Impl: Eq 6 | List. 7 | nil T = List(T, 0).new Nil(T).new() 8 | cons|T, N| rest: List(T, N-1), head: T = List(T, N).new Cons(T, N).{head; rest} 9 | {nil, cons} = List 10 | 11 | a = cons(nil(Int), 1) |> cons 2 |> cons 3 12 | match a: 13 | Cons(_, _).{head=h1; rest=Cons(_, _).{head=h2; rest}} -> 14 | assert h1 == 3 15 | assert h2 == 2 16 | assert rest == Cons.{head = 1; rest = nil(Int)} 17 | _ -> 18 | pass 19 | -------------------------------------------------------------------------------- /compiler/erg_parser/main.rs: -------------------------------------------------------------------------------- 1 | extern crate erg_common; 2 | extern crate erg_parser; 3 | 4 | use std::process; 5 | 6 | use erg_common::config::ErgConfig; 7 | use erg_common::traits::Runnable; 8 | 9 | use erg_parser::lex::LexerRunner; 10 | use erg_parser::ParserRunner; 11 | 12 | fn main() { 13 | let cfg = ErgConfig::parse(); 14 | match cfg.mode { 15 | "lex" => { 16 | LexerRunner::run(cfg); 17 | } 18 | "parse" | "exec" => { 19 | ParserRunner::run(cfg); 20 | } 21 | other => { 22 | println!("invalid mode: {other}"); 23 | process::exit(1); 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /doc/JA/API/types/traits/Add(R,O).md: -------------------------------------------------------------------------------- 1 | # Add R, O 2 | 3 | ```erg 4 | Add R, O = Trait { 5 | .`_+_` = (Self, R) -> O 6 | } 7 | ``` 8 | 9 | `Add`は加算を定義する型である。加算としての`+`にはメソッドと関数の2種類がある。 10 | 二項関数としての`+`、すなわち`_+_`は、以下のように定義されている。 11 | 12 | ```erg 13 | `_+_`(l: Add(R, O), r: R): O = l.`_+_` r 14 | ``` 15 | 16 | わざわざこの定義があるのは、`+`をメソッドではなく関数として取り扱えるようにである。 17 | 18 | ```erg 19 | assert [1, 2, 3].fold(0, `_+_`) == 6 20 | 21 | call op, x, y = op(x, y) 22 | assert call(`_+_`, 1, 2) == 3 23 | ``` 24 | 25 | 加算はこのように型付けされる。 26 | 27 | ```erg 28 | f: |O: Type; A <: Add(Int, O)| A -> O 29 | f x = x + 1 30 | 31 | g: |A, O: Type; Int <: Add(A, O)| A -> O 32 | g x = 1 + x 33 | ``` 34 | -------------------------------------------------------------------------------- /compiler/erg_common/datetime.rs: -------------------------------------------------------------------------------- 1 | use std::process::Command; 2 | 3 | /// returns the current datetime as String 4 | pub fn now() -> String { 5 | let output = if cfg!(windows) { 6 | Command::new("cmd") 7 | .args(&["/C", "echo %date% %time%"]) 8 | .output() 9 | .expect("failed to execute a process to get current time") 10 | } else { 11 | Command::new("date") 12 | .args(&["+%Y/%m/%d %T"]) 13 | .output() 14 | .expect("failed to execute process to get current time") 15 | }; 16 | String::from_utf8(output.stdout) 17 | .unwrap() 18 | .trim_end() 19 | .to_string() 20 | } 21 | -------------------------------------------------------------------------------- /compiler/erg_parser/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "erg_parser" 3 | version = "0.2.2" 4 | description = "The Erg parser" 5 | authors = ["mtshiba "] 6 | license = "MIT OR Apache-2.0" 7 | edition = "2021" 8 | repository = "https://github.com/erg-lang/erg/tree/main/src/erg_compiler/erg_parser" 9 | documentation = "https://docs.rs/erg_parser" 10 | homepage = "https://erg-lang.github.io/" 11 | 12 | [features] 13 | debug = [ "erg_common/debug" ] 14 | japanese = [ "erg_common/japanese" ] 15 | 16 | [dependencies] 17 | erg_common = { version = "0.2.2", path = "../erg_common" } 18 | 19 | [lib] 20 | path = "lib.rs" 21 | 22 | [[bin]] 23 | name = "ergp" 24 | path = "main.rs" 25 | -------------------------------------------------------------------------------- /doc/JA/syntax/type/10_interval.md: -------------------------------------------------------------------------------- 1 | # Interval Type 2 | 3 | `Range`オブジェクトの最も基本的な使い方は、イテレータとしての使用です。 4 | 5 | ```erg 6 | for! 0..9, i => 7 | print! i 8 | ``` 9 | 10 | Pythonと違い、末尾の数字は含まれることに注意してください。 11 | 12 | しかし、`Range`オブジェクトの使い道はこれだけではありません。型としても使うことが出来ます。このような型を区間型(Interval type)と呼びます。 13 | 14 | ```erg 15 | i: 0..10 = 2 16 | ``` 17 | 18 | `Nat`型は`0.. 0] # same as {A | N: Nat; A: Array(_, N); N > 0} 8 | ``` 9 | 10 | 量化依存型の標準形は`T(A, ... | Pred)`です。`T`は型構築子、`A, B`は型引数、`Pred`は条件式です。 11 | 12 | 左辺値としての量化依存型は、元の型と同じモジュール内でのみメソッドを定義出来ます。 13 | 14 | ```erg 15 | T A: Nat = Class ... 16 | T(A). 17 | ... 18 | T(A | A >= 1). 19 | method ref! self(A ~> A+1) = ... 20 | ``` 21 | 22 | 右辺値としての量化依存型は、使用する型変数を型変数リスト(`||`)で宣言する必要がある。 23 | 24 | ```erg 25 | a: |N: Nat| [T; N | N > 1] 26 | ``` 27 | -------------------------------------------------------------------------------- /doc/JA/API/procs.md: -------------------------------------------------------------------------------- 1 | # プロシージャ 2 | 3 | ## print! 4 | 5 | ```erg 6 | print!(x) -> NoneType 7 | ``` 8 | 9 | xを改行ありで返す。 10 | 11 | ## debug! 12 | 13 | ```erg 14 | debug!(x, type = Info) -> NoneType 15 | ``` 16 | 17 | xを改行ありでデバッグ表示(ファイル名、行数、変数の場合変数名が一緒に表示される)する。リリースモードでは除去される。 18 | 絵文字対応ターミナルではtypeに応じてプレフィックスが付く。 19 | 20 | * type == Info: 💬 21 | * type == Ok: ✅ 22 | * type == Warn: ⚠️ 23 | * type == Hint: 💡 24 | 25 | ## for! i: Iterable T, block: T => NoneType 26 | 27 | blockの動作でイテレータを走査する。 28 | 29 | ## while! cond: Bool!, block: () => NoneType 30 | 31 | condがTrueの間、blockを実行する。 32 | 33 | ## Lineno!() -> Nat 34 | 35 | ## Filename!() -> Str 36 | 37 | ## Namespace!() -> Str 38 | 39 | ## Module!() -> Module 40 | -------------------------------------------------------------------------------- /doc/JA/compiler/overview.md: -------------------------------------------------------------------------------- 1 | # `erg`の概観 2 | 3 | 各レイヤーの働きと特に重要な関数、メソッドを紹介します。 4 | 5 | ## 1. 字句解析 6 | 7 | * `Lexer`が字句解析を行います。`Lexer::next`が字句解析のメインロジックを担います。解析の結果として`Token`が出力されます。 8 | 9 | ## 2. 構文解析 10 | 11 | * `Parser`が構文解析を行います。特に重要なのは`Parser::parse_expr`です。解析の結果として`ast::Expr`の集まりである`AST`が出力されます。 12 | 13 | ## 3. 型チェック 14 | 15 | * `ASTLowerer`がASTをHIRに変換して型付けを行います。型チェックは主に`SymbolTable`によって行われます。特に重要なのは`SymbolTable::supertype_of`(部分型関係を判定する), `SymbolTable::unify`(型変数の単一化を行う), `SymbolTable::init_builtin_*`(組み込みAPIを定義する)です。解析の結果として`HIR`が出力されます。 16 | 17 | ## 4. 副作用チェック 18 | 19 | ## 5. 所有権チェック 20 | 21 | ## 6. バイトコード生成 22 | 23 | * `Compiler`が`HIR`を`CodeObj`に変換します。`CodeObj`はバイトコードと実行設定を保持します。特に重要なのは`Compiler::compile_expr`です。 24 | -------------------------------------------------------------------------------- /doc/JA/syntax/type/advanced/default_param.md: -------------------------------------------------------------------------------- 1 | # デフォルト引数付きの関数型 2 | 3 | まず、デフォルト引数の使用例を見る。 4 | 5 | ```erg 6 | f: (Int, Int, |= Int) -> Int 7 | f(x, y, z |= 0) = x + y + z 8 | 9 | g: (Int, Int, |= Int, Int) -> Int 10 | g(x, y, z |= 0, w |= 1) = x + y + z + w 11 | 12 | fold: ((Int, Int) -> Int, [Int], |= Int) -> Int 13 | fold(f, [], acc) = acc 14 | fold(f, arr, acc |= 0) = fold(f, arr[1..], f(acc, arr[0])) 15 | assert fold(f, [1, 2, 3]) == 6 16 | assert fold(g, [1, 2, 3]) == 8 17 | ``` 18 | 19 | `|=`以降の引数はデフォルト引数である。 20 | 部分型付け規則は以下の通り。 21 | 22 | ```erg 23 | ((X, |= Y) -> Z) < (X -> Z) 24 | ((X, |= Y, ...) -> Z) < ((X, |= ...) -> Z) 25 | ``` 26 | 27 | 1番目は、デフォルト引数のある関数はない関数と同一視できる、という意味である。 28 | 2番目は、任意のデフォルト引数は省略できる、という意味である。 29 | -------------------------------------------------------------------------------- /doc/JA/compiler/unification.md: -------------------------------------------------------------------------------- 1 | # 単一化(Unification) 2 | 3 | ## 出現検査(Occur Check) 4 | 5 | Ergは再帰型を許可するが、意味の無い、ナンセンスな再帰型はエラーとする。ナンセンスな型とは、具体的な型を挙げることができない型である。そのチェックするのが出現検査である。 6 | 下の例は、意味のある型である。 7 | 8 | ```erg 9 | T = Int 10 | T = Int or Option T # Int or Option Int or Option Option Int or ... 11 | Maybe T = Option T 12 | T = Int or T # will be warned (should just be `Int`) 13 | ``` 14 | 15 | 対して以下は、意味をなさない型である。 16 | 17 | ```erg 18 | T = T 19 | T = Option T 20 | T = T or T 21 | 22 | T = U 23 | U = T 24 | 25 | T X = T X 26 | U T = T U 27 | ``` 28 | 29 | 判定のアルゴリズムは、大まかにはこうである。 30 | 31 | * ある未判定の型`T`を判定する時、それが「定義済みの型を含むor型」でなく、`T`を含む場合はエラーとなる。 32 | * 多項カインドが単純型として扱われた場合はエラーとなる。 33 | 34 | 注意として、Ergは`F = F -> T`(`T`は任意の型)型の存在を許す。 35 | -------------------------------------------------------------------------------- /doc/JA/syntax/type/advanced/keyword_param.md: -------------------------------------------------------------------------------- 1 | # キーワード引数付き関数型 2 | 3 | ```erg 4 | h(f) = f(y: 1, x: 2) 5 | h: |T: Type|((y: Int, x: Int) -> T) -> T 6 | ``` 7 | 8 | キーワード引数付き関数の部分型付け規則は以下の通り。 9 | 10 | ```erg 11 | ((x: T, y: U) -> V) < ((T, U) -> V) # x, y are arbitrary keyword parameters 12 | ((y: U, x: T) -> V) < ((x: T, y: U) -> V) 13 | ((x: T, y: U) -> V) < ((y: U, x: T) -> V) 14 | ``` 15 | 16 | これは、キーワード引数は消去ないし入れ替えができるということを意味する。 17 | しかし、両者を同時に行うことはできない。 18 | すなわち、`(x: T, y: U) -> V`を`(U, T) -> V`にキャストすることはできない。 19 | なお、キーワード引数がつくのはトップレベルのタプル内のみで、配列やネストしたタプルでキーワード引数は付かない。 20 | 21 | ```erg 22 | Valid: [T, U] -> V 23 | Invalid: [x: T, y: U] -> V 24 | Valid: (x: T, ys: (U,)) -> V 25 | Invalid: (x: T, ys: (y: U,)) -> V 26 | ``` 27 | -------------------------------------------------------------------------------- /examples/control.er: -------------------------------------------------------------------------------- 1 | cond = True 2 | s = if cond: 3 | do "then block" 4 | do "else block" 5 | assert s == "then block" 6 | 7 | # else: binary operator 8 | x = cond.then 1 else 2 9 | assert x == 1 10 | 11 | if! cond: 12 | do!: 13 | print! "then block" 14 | do!: 15 | print! "else block" 16 | 17 | a = [1, 2, 3] 18 | sum = match a: 19 | [x, y, z] -> x + y + z 20 | (x, y, z) -> x + y + z 21 | {x; y; z} -> x + y + z 22 | i: Int -> i 23 | _ -> panic "unknown object" 24 | 25 | for! 0.., i => 26 | print! "i = {i}" 27 | if i >= 100: 28 | do return break() 29 | 30 | counter = !100 31 | while! not counter.is_zero(), do!: 32 | print! "counter = {counter}" 33 | counter.dec!() 34 | -------------------------------------------------------------------------------- /doc/JA/API/modules/unsound.md: -------------------------------------------------------------------------------- 1 | # module `unsound` 2 | 3 | Provides APIs perform unsound and unsafe operations that cannot be guaranteed safe in Erg's type system. 4 | 5 | ## `unsafe!` 6 | 7 | Executes a `Unsafe` procedure. Just like Rust, `Unsafe` APIs cannot be called directly, but are all passed as higher-order functions to this procedure. 8 | 9 | ```erg 10 | unsound = import "unsound" 11 | 12 | i = unsound.unsafe! do!: 13 | # convert `Result Int` to `Int` 14 | unsound.transmute input!().try_into(Int), Int 15 | ``` 16 | 17 | ## transmute 18 | 19 | 第1引数のオブジェクトを第2引数の型へ変換します。型チェックは行われません。 20 | この関数は型システムの型安全性を損ないます。使用の際はバリデーション等を行ってください。 21 | 22 | ## auto_transmute 23 | 24 | `transmute`とは違い、期待される型に自動で変換します。Ocamlの`Obj.magic`と同じ働きをします。 25 | -------------------------------------------------------------------------------- /doc/JA/syntax/24_module.md: -------------------------------------------------------------------------------- 1 | # モジュール 2 | 3 | Ergでは、ファイル自体を1つのレコードとみなすことができます。これをモジュールと呼びます。 4 | 5 | ```erg: foo.er 6 | # foo.er 7 | .i = 1 8 | ``` 9 | 10 | ```erg 11 | # fooモジュールを定義するのはこのレコードを定義するのとほとんど同じ 12 | foo = {.i = 1} 13 | ``` 14 | 15 | ```erg: bar.er 16 | # bar.er 17 | foo = import "foo" 18 | print! foo # 19 | assert foo.i == 1 20 | ``` 21 | 22 | モジュール型はレコード型でもあるので、分解代入が可能です。 23 | 24 | ```erg 25 | {sin; cos; ...} = import "math" 26 | ``` 27 | 28 | ## モジュールの可視性 29 | 30 | ```console 31 | └─┬ ./src 32 | ├─ lib.er 33 | ├─ foo.er 34 | ├─ bar.er 35 | └─┬ bar 36 | ├─ baz.er 37 | └─ qux.er 38 | ``` 39 | 40 |

41 | Previous | Next 42 |

43 | -------------------------------------------------------------------------------- /doc/JA/compiler/type_var_normalization.md: -------------------------------------------------------------------------------- 1 | # 正規化 2 | 3 | * Ergの型引数正規化はSymPyのsimplify関数を参考にしています。 4 | 5 | 例えば`concat: |T, M, N|([T; M], [T; N] -> [T; M+N])`を定義するとき、型変数・引数を具体化せずに一致判定を行わなくてはならない。 6 | 等式判定は自ずと限界があるが、現時点で可能な判定とその方式は以下の通り。 7 | 8 | * 加算・乗算の対称性: 9 | 10 | `n+m == m+n` 11 | 12 | 型変数は文字列としてソートし正規化する。 13 | 14 | * 加算と乗算、減算と除算の等価性: 15 | 16 | `n+n == 2*n` 17 | 18 | Σ[c] x == c*xに正規化する(cは定数)。 19 | 定数は二項演算の左辺に置いて正規化する。 20 | 21 | * 複式の等価性: 22 | 23 | `n+m+l == m+n+l == l+m+n == ...` 24 | `n+m*l == m*l+n` 25 | 26 | ソートで正規化して判定する。 27 | 乗算・除算のブロックは加算・減算より左側に出す。ブロック同士は最左辺の型変数を比較してソートする。 28 | 29 | * 基本的な不等式: 30 | 31 | `n > m -> m + 1 > n` 32 | 33 | * 等式: 34 | 35 | `n >= m and m >= n -> m == n` 36 | 37 | * 不等式の推移性: 38 | 39 | `n > 0 -> n > -1` 40 | -------------------------------------------------------------------------------- /doc/JA/dev_guide/branches.md: -------------------------------------------------------------------------------- 1 | # ブランチの命名と運用方針 2 | 3 | * main, beta, ver-*はread-onlyブランチである。直接のコミットは受け付けず、下流ブランチからのマージによってのみ更新される。 4 | * 基本的に開発は`dev`ブランチ一本で行う。どうしてもブランチを切らないと作業しにくい場合のみ`feature-*`ブランチか`issue-*`ブランチを作成する。 5 | 6 | ## major 7 | 8 | * 最新のメジャーリリース 9 | * 以下の条件を満たしたbetaをマージする 10 | 11 | * コンパイルが成功する 12 | * 全てのテストが成功する 13 | * インストーラを用意する 14 | 15 | ## beta 16 | 17 | * 最新のベータリリース 18 | * 以下の条件を満たしたdevをマージする 19 | 20 | * コンパイルが成功する 21 | * 全てのテストが成功する 22 | 23 | ## main 24 | 25 | * メイン開発ブランチ 26 | 27 | * コンパイルが成功する 28 | 29 | ## ver-* 30 | 31 | * 過去のメジャーリリース 32 | * majorを切って作る 33 | * 深刻なバグが見つかった場合はブランチごと削除する 34 | 35 | ## feature-* 36 | 37 | * 特定の一機能を開発するブランチ 38 | * mainを切って作る 39 | 40 | * 条件なし 41 | 42 | ## issue-* 43 | 44 | * 特定のissueを解決するブランチ 45 | 46 | * 条件なし 47 | -------------------------------------------------------------------------------- /doc/EN/index.md: -------------------------------------------------------------------------------- 1 | # Index 2 | 3 | ## [API/](./API/index.md) 4 | 5 | This section describes the specifications of subroutines, types, constants, etc. provided by Erg's built-in or standard libraries. 6 | 7 | ## [compiler/](./compiler/index.md) 8 | 9 | Describes the design of the Erg compiler (Centimetre). 10 | 11 | ## [dev_guide/](./dev_guide/index.md) 12 | 13 | It explains the development policy of the project, how to make contributions, etc. 14 | 15 | ## [python/](./python/index.md) 16 | 17 | The knowledge of Python required to develop Erg is explained. 18 | 19 | ## [syntax/](./syntax/00_basic.md) 20 | 21 | The syntax of Erg is explained. 22 | 23 | ## [tools/](./tools/index.md) 24 | 25 | Explains how to use Erg's peripheral tools and command options. 26 | -------------------------------------------------------------------------------- /doc/JA/API/types/classes/Tuple.md: -------------------------------------------------------------------------------- 1 | # Tuple T: ...Type 2 | 3 | 複数の型のオブジェクトを保持するコレクション。 4 | 5 | ## methods 6 | 7 | * zip self, other 8 | 9 | 2つの順番付けられたコレクション(配列かタプル)を合成する。 10 | 11 | ```erg 12 | assert ([1, 2, 3].zip [4, 5, 6])[0] == (1, 4) 13 | ``` 14 | 15 | * zip_by self, op, other 16 | 17 | zipを一般化したメソッド。合成するための二項演算を指定できる。 18 | 演算子には`()`, `[]`, `{}`, `{:}`も指定可能で、それぞれタプル, 配列, セット, ディクトを生成する。 19 | 20 | ```erg 21 | assert ([1, 2, 3].zip([4, 5, 6]))[0] == (1, 4) 22 | assert ([1, 2, 3].zip_by((), [4, 5, 6]))[0] == (1, 4) 23 | assert ([1, 2, 3].zip_by([], [4, 5, 6]))[0] == [1, 4] 24 | assert ([1, 2, 3].zip_by({}, [4, 5, 6]))[0] == {1, 4} 25 | assert ([1, 2, 3].zip_by({:}, [4, 5, 6]))[0] == {1: 4} 26 | assert ([1, 2, 3].zip_by(`_+_`, [4, 5, 6]))[0] == 5 27 | ``` 28 | -------------------------------------------------------------------------------- /doc/JA/dev_guide/rust_code_guideline.md: -------------------------------------------------------------------------------- 1 | # Rustコードに関するガイドライン 2 | 3 | ## ローカルルール 4 | 5 | * デバッグ用の出力には`log!`を使用する(release時にも必要な出力処理は`println!`等を使用する)。 6 | * 未使用・または内部用の(privateかつ特定の機能のみに使用する)変数・メソッドは先頭に`_`を1つ付ける。予約語との衝突を回避したい場合は後ろに`_`を1つ付ける。 7 | 8 | ## 奨励されるコード 9 | 10 | * 狭い範囲の数値やboolの代わりにドメイン固有のEnumを定義する。 11 | * アクセス修飾子は必要最小限のものとする。公開する場合でも`pub(mod)`や`pub(crate)`を優先的に使用する。 12 | * for式でのiterableオブジェクトは明示的にイテレータに変換する(`for i in x`ではなく`for i in x.iter()`)。 13 | * 遅延評価。例えば、`default`がリテラル以外の場合は`unwrap_or`ではなく`unwrap_or_else`を使用する。 14 | 15 | ## 奨励されないコード 16 | 17 | * return type overloadingを多用する。具体的には自明でない`.into`を多用するコード。これは型推論結果が直感に反する場合があるためである。この場合は代わりに`from`を使うことを推奨する。 18 | 19 | * `Deref`を多用する。これは実質的に継承と同じ問題を引き起こす。 20 | 21 | ## 文脈により判断が変わるコード 22 | 23 | * 未使用のヘルパーメソッドを定義する。 24 | * `unwrap`, `clone`を多用する。場合によってはそうするより他にないものもある。 25 | -------------------------------------------------------------------------------- /doc/JA/syntax/type/advanced/rank2type.md: -------------------------------------------------------------------------------- 1 | # ランク2型 2 | 3 | Ergでは`id|T|(x: T) -> T = x`などのように色々な型を受け取れる関数、すなわち多相関数を定義できる。 4 | では、多相関数を受け取れる関数は定義できるだろうか? 5 | 例えば、このような関数である(この定義は誤りを含むことに注意してほしい)。 6 | 7 | ```erg 8 | # pair_map(i -> i * 2, (1, "a")) == (2, "aa")になってほしい 9 | pair_map|T, L, R|(f: T -> T, (l: L, r: R)) -> (L, R) = (f(l), f(r)) 10 | ``` 11 | 12 | `1`と`"a"`の型が違うので、無名関数は一度単相化して終わりではないことに注意してほしい。2回単相化する必要がある。 13 | しかしはErgは型変数を一度しか単相化しない。すなわち、`T -> T`は`f(tup.0)`の時点で`Int -> Int`に決定されてしまう。 14 | 15 | ```erg 16 | # pair_map: |L, R: Type; F <: L -> L; F <: R -> R|(F, (L, R)) -> (L, R) 17 | pair_map|L, R|(f, (l: L, r: R)): (L, R) = (f(l), f(r)) 18 | ``` 19 | 20 | 何も指定しなかった場合はこうなる。 21 | 22 | ```erg 23 | # pair_map: |F, T, U, V, W: Type; F <: T -> V; F <: U -> W| (F, (T, U)) -> (V, W) 24 | pair_map(f, (l, r)) = (f(l), f(r)) 25 | ``` 26 | -------------------------------------------------------------------------------- /doc/JA/API/types/classes/ArrayWithLen(T,N).md: -------------------------------------------------------------------------------- 1 | # ArrayWithLen T: Type, N: Nat 2 | 3 | `[T; N]`は糖衣構文。長さを省いた[`Array`型](./Array.md)もある。 4 | 5 | ## methods 6 | 7 | * values_at(self, selectors: [Nat; N]) -> [T; N] 8 | 9 | ```erg 10 | assert ["a", "b", "c", "d", "e"].values_at([0, 1, 3]) == ["a", "b", "d"] 11 | ``` 12 | 13 | * all(self, pred: T -> Bool) -> Bool 14 | 全ての要素がpredを満たすかどうかを返す。 15 | 要素が0のときはpredに関わらず`True`となるが、Warningを出す。 16 | この仕様自体は多くの言語で採用されており、論理学的な整合性から要請される。 17 | 18 | ```erg 19 | assert [].all(_ -> False) 20 | ``` 21 | 22 | ```python 23 | assert all(False for _ in []) 24 | ``` 25 | 26 | ## methods of ArrayWithLen T, N | T <: Eq 27 | 28 | * freq self -> [{T: Nat}] 29 | オブジェクトの出現頻度を返す。 30 | 31 | ```erg 32 | assert ["a", "b", "c", "b", "c", "b"].freq() \ 33 | == [{"a", 1}, {"b": 3}, {"c": 2}] 34 | ``` 35 | -------------------------------------------------------------------------------- /doc/JA/syntax/10_array.md: -------------------------------------------------------------------------------- 1 | # 配列 2 | 3 | 配列はもっとも基本的な __コレクション(集約)__ です。 4 | コレクションとは、内部にオブジェクトを複数保持できるオブジェクトのことです。 5 | 6 | ```erg 7 | a = [1, 2, 3] 8 | a: [Int; 3] # 型指定: セミコロンの後の数字は要素数 9 | # 要素数がわからない場合は省略可能 10 | a: [Int] 11 | 12 | mut_a = [!1, !2, !3] 13 | mut_a[0].inc!() 14 | assert mut_a == [2, 2, 3] 15 | ``` 16 | 17 | ## スライス 18 | 19 | 配列は、複数の値をまとめて取り出すこともできます。これをスライスと呼びます。 20 | 21 | ```erg 22 | l = [1, 2, 3, 4] 23 | # Pythonのl[1:3]に相当 24 | assert l[1..<3] == [2, 3] 25 | assert l[1..2] == [2, 3] 26 | # l[1]と同じ 27 | assert l[1..1] == [2] 28 | # Pythonのl[::2]に相当 29 | assert l[..].step(2) == [2, 4] 30 | ``` 31 | 32 | スライスで得られるオブジェクトは配列の(不変)参照です。 33 | 34 | ```erg 35 | print! Typeof l[1..2] # Ref [Int; 4] 36 | ``` 37 | 38 |

39 | Previous | Next 40 |

41 | -------------------------------------------------------------------------------- /doc/JA/compiler/parsing.md: -------------------------------------------------------------------------------- 1 | # Erg言語の構文解析 2 | 3 | ## 空白の扱い 4 | 5 | Ergの文法において特異なのは、space-sensitive(空白による区別がある)である点である。 6 | これは、`()`の省略による表現力の低下を補うためである。同様の文法は同じく`()`を省略可能なNimでも見られる。 7 | 8 | ```erg 9 | f +1 == f(+1) 10 | f + 1 == (f+1) 11 | f (1,) == f((1,)) 12 | f(1,) == f(1) 13 | (f () -> ...) == f(() -> ...) 14 | (f() -> ...) == (f() -> ...) 15 | ``` 16 | 17 | ## 左辺値、右辺値 18 | 19 | Ergにおいて左辺値とは`=`の左側といった単純なものではない。 20 | 実際、(非常に紛らわしいが)`=`の左側にも右辺値は存在するし、`=`の右側にも左辺値が存在する。 21 | 右辺値の中に左辺値が存在することさえある。 22 | 23 | ```erg 24 | # iは左辺値、Array(Int)と[1, 2, 3]は右辺値 25 | i: Array(Int) = [1, 2, 3] 26 | # `[1, 2, 3].iter().map i -> i + 1`は右辺値だが、->の左側のiは左辺値 27 | a = [1, 2, 3].iter().map i -> i + 1 28 | # {x = 1; y = 2}は右辺値だが、x, yは左辺値 29 | r = {x = 1; y = 2} 30 | ``` 31 | 32 | 左辺値、右辺値の正確な定義は、「評価可能ならば右辺値、そうでないならば左辺値」である。 33 | 例として`i = 1; i`というコードを考える。2つ目の`i`は評価可能であるため右辺値だが、1つ目の`i`は左辺値となる。 34 | -------------------------------------------------------------------------------- /compiler/erg_compiler/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "erg_compiler" 3 | version = "0.2.2" 4 | description = "Centimetre: the Erg compiler" 5 | authors = ["Shunsuke Shibayama "] 6 | license = "MIT OR Apache-2.0" 7 | edition = "2021" 8 | repository = "https://github.com/erg-lang/erg/tree/main/src/erg_compiler" 9 | documentation = "https://docs.rs/erg_compiler" 10 | homepage = "https://erg-lang.github.io/" 11 | 12 | [features] 13 | # when "debug" feature is turned on, that of parser will also be turned on. 14 | debug = [ "erg_common/debug", "erg_parser/debug" ] 15 | japanese = [ "erg_common/japanese", "erg_parser/japanese" ] 16 | 17 | [dependencies] 18 | erg_common = { version = "0.2.2", path = "../erg_common" } 19 | erg_parser = { version = "0.2.2", path = "../erg_parser" } 20 | 21 | [lib] 22 | path = "lib.rs" 23 | 24 | [[bin]] 25 | name = "cm" 26 | path = "main.rs" 27 | -------------------------------------------------------------------------------- /doc/EN/syntax/24_module.md: -------------------------------------------------------------------------------- 1 | # module 2 | 3 | Erg allows you to think of the file itself as a single record. This is called a module. 4 | 5 | ```erg: foo.er 6 | # foo.er 7 | .i = 1 8 | ``` 9 | 10 | ``` erg 11 | # Defining the foo module is almost the same as defining this record 12 | foo = {.i = 1} 13 | ``` 14 | 15 | ```erg: bar.er 16 | #bar.er 17 | foo = import "foo" 18 | print! foo # 19 | assert foo.i == 1 20 | ``` 21 | 22 | Since module types are also record types, deconstruction assignment is possible. 23 | 24 | ``` erg 25 | {sin; cos; ...} = import "math" 26 | ``` 27 | 28 | ## module visibility 29 | 30 | ```console 31 | └─┬ ./src 32 | ├─ lib.er 33 | ├─ foo.er 34 | ├─bar.er 35 | └─┬ bar 36 | ├─ baz.er 37 | └─ qux.er 38 | ``` 39 | 40 |

41 | Previous | Next 42 |

43 | -------------------------------------------------------------------------------- /doc/JA/syntax/06_operator.md: -------------------------------------------------------------------------------- 1 | # 演算子 2 | 3 | 演算子(オペレーター)は、演算を表す記号です。被演算子(オペランド)は演算子の(左)右にあるもので、Ergでは専らオブジェクトです。 4 | 5 | 演算子は関数の一種であり、したがってそれ自体も第一級オブジェクトで変数に束縛できます。束縛の際は``で囲む必要があります。 6 | `+`(と`-`)については、単項演算子と二項演算子の両方が存在するため、一意化するために`_+_`(二項演算)/`+_`(単項演算)のどちらかを指定する必要があります。 7 | 8 | ```erg 9 | add = `+` # SyntaxError: specify `_+_` or `+_` 10 | add = `_+_` 11 | assert f(1, 2) == 3 12 | assert f("a", "b") == "ab" 13 | 14 | g = `*` # OK, this is binary only 15 | assert g(1, 2) == 2 16 | ``` 17 | 18 | ただし、特殊形式と呼ばれる一部の演算子は束縛できないことに注意してください。 19 | 20 | ```erg 21 | def = `=` # SyntaxError: cannot bind `=` operator, this is a special form 22 | # NG: def x, 1 23 | function = `->` # SyntaxError: cannot bind `->` operator, this is a special form 24 | # NG: function x, x + 1 25 | ``` 26 | 27 |

28 | Previous | Next 29 |

30 | -------------------------------------------------------------------------------- /doc/JA/syntax/34_generator.md: -------------------------------------------------------------------------------- 1 | # ジェネレータ 2 | 3 | ジェネレータは、ブロック中で`yield!`プロシージャを使う特殊なプロシージャです。 4 | 5 | ```erg 6 | g!() = 7 | yield! 1 8 | yield! 2 9 | yield! 3 10 | ``` 11 | 12 | `yield!`はサブルーチンのブロックで定義されるプロシージャで、`self!.yield!`を呼び出します。 13 | これは`return`と同じく渡された値を戻り値として返すものですが、その時点でのブロックの実行状態を保存し、もう一度呼び出された際に続きから実行するという特徴があります。 14 | ジェネレータはプロシージャでありながらイテレータでもあります。Pythonのジェネレータはイテレータを生成する関数ですが、Ergは直接イテレートします。プロシージャ自体は一般に可変オブジェクトではありません(`!`が付かない)が、ジェネレータは実行ごとに自身の内容が変わる得るので可変オブジェクトです。 15 | 16 | ```erg 17 | # Generator! < Proc 18 | g!: Generator!((), Int) 19 | assert g!() == 1 20 | assert g!() == 2 21 | assert g!() == 3 22 | ``` 23 | 24 | Pythonスタイルのジェネレータは以下のようにして定義できます。 25 | 26 | ```erg 27 | make_g() = () => 28 | yield! 1 29 | yield! 2 30 | yield! 3 31 | make_g: () => Generator!((), Int) 32 | ``` 33 | 34 |

35 | Previous | Next 36 |

37 | -------------------------------------------------------------------------------- /examples/array.er: -------------------------------------------------------------------------------- 1 | immut_arr = [1, 2, 3, 4, 5] 2 | mut_content_arr = [1, 2, 3, 4, 5].into [Int!; 5] 3 | telescoping_arr = [1, 2, 3, 4, 5].into [Int; !5] 4 | mut_arr = [1, 2, 3, 4, 5].into [Int!; !5] 5 | 6 | mut_content_arr.map!(x -> x + 1) 7 | # A mutable array class inherits an immutable array class, so a mutable array can compare with an immutable array 8 | assert mut_content_arr == [2, 3, 4, 5, 6] 9 | # This is invalid: telescoping_arr.map!(x -> x + 1) 10 | telescoping_arr.push!(6) 11 | assert telescoping_arr == [1, 2, 3, 4, 5, 6] 12 | # This is invalid: mut_content_arr.push!(6) 13 | 14 | # NOTE: `telescoping_arr` can actually do the same thing as `mut_content_arr` or `mut_arr`. 15 | # `mut_arr[0].inc!()` is the same as `telescoping_arr.insert! 0, telescoping_arr.remove!(0) + 1`. 16 | # The important thing is that the length of `mut_content_arr` will not change. This gives advantages such as guaranteed success of accessing. 17 | -------------------------------------------------------------------------------- /compiler/erg_compiler/main.rs: -------------------------------------------------------------------------------- 1 | extern crate erg_common; 2 | extern crate erg_compiler; 3 | extern crate erg_parser; 4 | 5 | use std::process; 6 | 7 | use erg_common::config::ErgConfig; 8 | use erg_common::deserialize::Deserializer; 9 | use erg_common::traits::Runnable; 10 | 11 | use erg_compiler::Compiler; 12 | 13 | use erg_parser::lex::LexerRunner; 14 | use erg_parser::ParserRunner; 15 | 16 | fn main() { 17 | let cfg = ErgConfig::parse(); 18 | match cfg.mode { 19 | "lex" => { 20 | LexerRunner::run(cfg); 21 | } 22 | "parse" => { 23 | ParserRunner::run(cfg); 24 | } 25 | "compile" | "exec" => { 26 | Compiler::run(cfg); 27 | } 28 | "read" => { 29 | Deserializer::run(cfg); 30 | } 31 | other => { 32 | println!("invalid mode: {other}"); 33 | process::exit(1); 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /doc/JA/syntax/31_pipeline.md: -------------------------------------------------------------------------------- 1 | # パイプライン演算子 2 | 3 | パイプライン演算子は、次のように使う。 4 | 5 | ```erg 6 | assert f(g(x)) == (x |> g |> f) 7 | assert f(g(x, y)) == ((x, y) |> g |> f) 8 | ``` 9 | 10 | つまり、`Callable(object)`という順序を`object |> Callable`と変えられるのである。 11 | パイプライン演算子はメソッドに対しても使える。メソッドの場合、`object.method(args)`が`object |>.method(args)`と変わる。 12 | 単に`|>`が増えただけにも見えるが、結合強度が低めなので`()`の量を減らせる場合がある。 13 | 14 | ```erg 15 | rand = -1.0..1.0 |>.sample!() 16 | log rand # 0.2597... 17 | 1+1*2 |>.times do log("a", end: "") # aaa 18 | # without `|>`, the following will be `evens = (1..100).iter().filter(i -> i % 2 == 0).collect(Array)` 19 | evens = 1..100 |>.iter |>.filter i -> i % 2 == 0 |>.collect Array 20 | # or 21 | _evens = 1..100 \ 22 | .iter() \ 23 | .filter i -> i % 2 == 0 \ 24 | .collect Array 25 | ``` 26 | 27 |

28 | Previous | Next 29 |

30 | -------------------------------------------------------------------------------- /doc/JA/syntax/28_spread_syntax.md: -------------------------------------------------------------------------------- 1 | # Spread assignment (展開代入) 2 | 3 | 分解代入において、変数の前に`...`を置くと残りの要素を全てその変数に展開できる。これを展開代入と呼ぶ。 4 | 5 | ```erg 6 | [x, ...y] = [1, 2, 3] 7 | assert x == 1 8 | assert y == [2, 3] 9 | x, ...y = (1, 2, 3) 10 | assert x == 1 11 | assert y == (2, 3) 12 | ``` 13 | 14 | ## Extract assignment (抽出代入) 15 | 16 | `...`のあとに何も書かない場合、残りの要素は無視して代入される。このタイプの展開代入を特に抽出代入と呼ぶ。 17 | 抽出代入は、モジュールやレコード内にある特定の属性をローカルに持ってくる際に便利な構文である。 18 | 19 | ```erg 20 | {sin; cos; tan; ..} = import "math" 21 | ``` 22 | 23 | このようにすると、以降はローカルで`sin, cos, tan`が使用できる。 24 | 25 | レコードでも同じようにできる。 26 | 27 | ```erg 28 | record = {x = 1; y = 2} 29 | {x; y; ...} = record 30 | ``` 31 | 32 | 全て展開したい場合は`{*} = record`とする。OCamlなどでいう`open`である。 33 | 34 | ```erg 35 | record = {x = 1; y = 2} 36 | {*} = record 37 | assert x == 1 and y == 2 38 | ``` 39 | 40 |

41 | Previous | Next 42 |

43 | -------------------------------------------------------------------------------- /doc/JA/syntax/14_set.md: -------------------------------------------------------------------------------- 1 | # セット(Set) 2 | 3 | セットは集合を表し、データ構造的には重複、順序のない配列です。 4 | 5 | ```erg 6 | assert Set.from([1, 2, 3, 2, 1]) == {1, 2, 3} 7 | assert {1, 2} == {1, 1, 2} # 重複は自動で削除される 8 | assert {1, 2} == {2, 1} 9 | ``` 10 | 11 | セットは集合演算を行えます。 12 | 13 | ```erg 14 | assert 1 in {1, 2, 3} 15 | assert not 1 in {} 16 | assert {1} or {2} == {1, 2} 17 | assert {1, 2} and {2, 3} == {2} 18 | assert {1, 2} not {2} == {1} 19 | ``` 20 | 21 | セットは等質なコレクションである。別のクラスのオブジェクトを共存させるためには等質化させなくてはならない。 22 | 23 | ```erg 24 | s: {Int or Str} = {"a", 1, "b", -1} 25 | ``` 26 | 27 | ## 型としてのセット 28 | 29 | セットは型としても扱える。このような型は __列挙型(Enum type)__ と呼ばれる。 30 | 31 | ```erg 32 | i: {1, 2, 3} = 1 33 | assert i in {1, 2, 3} 34 | ``` 35 | 36 | セットの要素がそのまま型の要素になる。 37 | セット自身は違うことに注意してほしい。 38 | 39 | ```erg 40 | mut_set = {1, 2, 3}.into {Int; !3} 41 | mut_set.insert!(4) 42 | ``` 43 | 44 |

45 | Previous | Next 46 |

47 | -------------------------------------------------------------------------------- /assets/erg_logo.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /doc/JA/syntax/type/advanced/existential.md: -------------------------------------------------------------------------------- 1 | # 存在型 2 | 3 | ∀に対応する全称型があるならば、∃に対応する存在型があると考えるのが自然です。 4 | 存在型は難しいものではありません。そうと意識していないだけで、既にあなたは存在型を知っています。 5 | 6 | ```erg 7 | T: Trait 8 | f x: T = ... 9 | ``` 10 | 11 | 上のトレイト`T`は存在型として使われています。 12 | 対して下の場合の`T`はトレイトでしかなく、`X`は全称型です。 13 | 14 | ```erg 15 | f|X <: T| x: X = ... 16 | ``` 17 | 18 | 実際、存在型は全称型に置き換えられます。ではなぜ存在型などというものが存在するのでしょうか。 19 | まず、上で見たように存在型は型変数を伴わないので、型指定をシンプルにできます。 20 | また、型変数を除去できるので全称型ならランク2を超えてしまうような型も構成できます。 21 | 22 | ```erg 23 | show_map f: (|T| T -> T), arr: [Show; _] = 24 | arr.map x -> 25 | y = f x 26 | log y 27 | y 28 | ``` 29 | 30 | しかし、見ればわかるように存在型は元の型を忘却・拡大してしまうので、戻り値の型を広げたくない場合などは全称型を使う必要があります。 31 | 逆に、引数として受け取るだけで戻り値に関係のない型は存在型で記述して構いません。 32 | 33 | ```erg 34 | # id(1): Intになって欲しい 35 | id|T|(x: T): T = x 36 | # |S <: Show|(s: S) -> ()は冗長 37 | show(s: Show): () = log s 38 | ``` 39 | 40 | ちなみに、クラスは存在型とは呼びません。予めその要素となるオブジェクトが定められているためです。 41 | 存在型はあるトレイトを満たすすべての型という意味で、実際にどのような型が代入されるか知るところではないのです。 42 | -------------------------------------------------------------------------------- /src/main.rs: -------------------------------------------------------------------------------- 1 | extern crate erg; 2 | extern crate erg_compiler; 3 | extern crate erg_parser; 4 | 5 | use std::process; 6 | 7 | use erg_common::config::ErgConfig; 8 | use erg_common::deserialize::Deserializer; 9 | use erg_common::traits::Runnable; 10 | 11 | use erg_parser::lex::LexerRunner; 12 | use erg_parser::ParserRunner; 13 | 14 | use erg_compiler::Compiler; 15 | 16 | use erg::dummy::DummyVM; 17 | 18 | fn main() { 19 | let cfg = ErgConfig::parse(); 20 | match cfg.mode { 21 | "lex" => { 22 | LexerRunner::run(cfg); 23 | } 24 | "parse" => { 25 | ParserRunner::run(cfg); 26 | } 27 | "compile" => { 28 | Compiler::run(cfg); 29 | } 30 | "exec" => { 31 | DummyVM::run(cfg); 32 | } 33 | "read" => { 34 | Deserializer::run(cfg); 35 | } 36 | other => { 37 | eprintln!("invalid mode: {other}"); 38 | process::exit(1); 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /doc/JA/syntax/05_builtin_funcs.md: -------------------------------------------------------------------------------- 1 | # 組み込み関数 2 | 3 | ## if 4 | 5 | `if`は条件に応じて処理を変える関数です。 6 | 7 | ```erg 8 | result: Option Int = if! Bool.sample!(), do: 9 | log "True was chosen" 10 | 1 11 | print! result # None (or 1) 12 | ``` 13 | 14 | `.sample!()`は集合の値をランダムに返します。もし戻り値が真ならば、`print! "True"`が実行されます。 15 | 条件が偽であった際の処理も指定できます。2つ目のdoブロックはelseブロックと呼ばれます。 16 | 17 | ```erg 18 | result: Nat = if Bool.sample!(): 19 | do: 20 | log "True was chosen" 21 | 1 22 | do: 23 | log "False was chosen" 24 | 0 25 | print! result # 1 (or 0) 26 | ``` 27 | 28 | 処理が1行ならば、インデントを省略できます。 29 | 30 | ```erg 31 | result = if Bool.sample!(): 32 | do 1 33 | do 0 34 | ``` 35 | 36 | ## for 37 | 38 | 繰り返し行う処理を書くときは`for`が使えます。 39 | 40 | ```erg 41 | match_s(ss: Iterator(Str), pat: Pattern): Option Str = 42 | for ss, s -> 43 | if pat.match(s).is_some(): 44 | break s 45 | ``` 46 | 47 |

48 | Previous | Next 49 |

50 | -------------------------------------------------------------------------------- /doc/JA/syntax/type/08_value.md: -------------------------------------------------------------------------------- 1 | # 値型(Value types) 2 | 3 | 値型はErg組み込み型のうちコンパイル時評価が可能な型で、具体的には以下のものです。 4 | 5 | ```erg 6 | Value = ( 7 | Int 8 | or Nat 9 | or Ratio 10 | or Float 11 | or Complex 12 | or Bool 13 | or Str 14 | or NoneType 15 | or Array Const 16 | or Tuple Const 17 | or Set Const 18 | or ConstFunc(Const, _) 19 | or ConstProc(Const, _) 20 | or ConstMethod(Const, _) 21 | ) 22 | ``` 23 | 24 | 値型のオブジェクト・定数、およびそれにコンパイル時サブルーチンを適用したものを定数式と呼びます。 25 | 26 | ```erg 27 | 1, 1.0, 1+2im, True, None, "aaa", [1, 2, 3], Fib(12) 28 | ``` 29 | 30 | サブルーチンについては注意が必要です。サブルーチンは値型であるものとそうでないものがあります。 31 | サブルーチンの実体は単なるポインタであるためすべて値として扱っても良い[1](#1)のですが、コンパイル時サブルーチンでないものを定数文脈で使えてもあまり意味がないため、値型とはなっていません。 32 | 33 | 値型に分類される型は、将来的には追加される可能性があります。 34 | 35 | --- 36 | 37 | 1 Ergにおける値型という用語は、他の言語での定義とは異なっています。純粋なErgの意味論内でメモリという概念は存在せず、スタックに置かれるから値型であるとか、実体としてポインタだから値型ではない、といった言明は正しくありません。あくまで、値型は`Value`型もしくはそのサブタイプであるという意味しか持ちません。 [↩](#f1) 38 | -------------------------------------------------------------------------------- /doc/EN/syntax/10_array.md: -------------------------------------------------------------------------------- 1 | # Array 2 | 3 | Arrays are the most basic __collection (aggregate)__. 4 | A collection is an object that can hold multiple objects inside it. 5 | 6 | ```erg 7 | a = [1, 2, 3] 8 | a: [Int; 3] # Type specification: number after semicolon is the number of elements 9 | # Can be omitted if the number of elements is not known 10 | a: [Int] 11 | 12 | mut_a = [!1, !2, !3] 13 | mut_a[0].inc!() 14 | assert mut_a == [2, 2, 3] 15 | ``` 16 | 17 | ## Slice 18 | 19 | An array can also have multiple values taken out at once. This is called slicing. 20 | 21 | ```erg 22 | l = [1, 2, 3, 4] 23 | # Same as l[1:3] in Python 24 | assert l[1.. <3] == [2, 3] 25 | assert l[1..2] == [2, 3] 26 | # Same as l[1] 27 | assert l[1..1] == [2] 28 | # Same as l[::2] in Python 29 | assert l[..].step(2) == [2, 4] 30 | ``` 31 | 32 | The object obtained by slicing is an (immutable) copy to an array. 33 | 34 | ```erg 35 | print! Typeof l[1..2] # [Int; 4] 36 | ``` 37 | 38 |

39 | Previous | Next 40 |

41 | -------------------------------------------------------------------------------- /LICENSE-MIT: -------------------------------------------------------------------------------- 1 | Permission is hereby granted, free of charge, to any person obtaining a copy 2 | of this software and associated documentation files (the "Software"), to deal 3 | in the Software without restriction, including without limitation the rights 4 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 5 | copies of the Software, and to permit persons to whom the Software is 6 | furnished to do so, subject to the following conditions: 7 | 8 | The above copyright notice and this permission notice shall be included in all 9 | copies or substantial portions of the Software. 10 | 11 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 12 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 13 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 14 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 15 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 16 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 17 | SOFTWARE. 18 | -------------------------------------------------------------------------------- /doc/JA/API/types/traits/Sample.md: -------------------------------------------------------------------------------- 1 | # Sample 2 | 3 | インスタンスを「適当に」選出する`sample`メソッドと`sample!`メソッドを持つトレイト。`sample`メソッドは常に同じインスタンスを返し、`sample!`メソッドは呼び出しごとに変わる適当なインスタンスを返す。 4 | 5 | これはテストなどで適当なインスタンスがほしい場合を想定したトレイトであり、必ずしも無作為ではないことに注意が必要である。無作為抽出が必要な場合は`random`モジュールを使用する。 6 | 7 | 主要な値クラスは全て`Sample`を実装する。また、`Sample`なクラスで構成されているタプル型やレコード型、Or型、篩型でも実装されている。 8 | 9 | ```erg 10 | assert Int.sample() == 42 11 | assert Str.sample() == "example" 12 | # Intの場合、標準では64bitの範囲でサンプルされる 13 | print! Int.sample!() # 1313798 14 | print! {x = Int; y = Int}.sample!() # {x = -32432892, y = 78458576891} 15 | ``` 16 | 17 | 以下は`Sample`の実装例である。 18 | 19 | ```erg 20 | EmailAddress = Class {header = Str; domain = Str}, Impl=Sample and Show 21 | @Impl Show 22 | EmailAddress. 23 | show self = "{self::header}@{self::domain}" 24 | @Impl Sample 25 | EmailAddress. 26 | sample(): Self = Self.new "sample@gmail.com" 27 | sample!(): Self = 28 | domain = ["gmail.com", "icloud.com", "yahoo.com", "outlook.com", ...].sample!() 29 | header = AsciiStr.sample!() 30 | Self.new {header; domain} 31 | ``` 32 | -------------------------------------------------------------------------------- /doc/EN/syntax/31_pipeline.md: -------------------------------------------------------------------------------- 1 | # Pipeline Operator 2 | 3 | The pipeline operator is used like this: 4 | 5 | ``` erg 6 | assert f(g(x)) == (x |> g |> f) 7 | assert f(g(x, y)) == ((x, y) |> g |> f) 8 | ``` 9 | 10 | In other words, the order `Callable(object)` can be changed to `object |> Callable`. 11 | Pipeline operators can also be used on methods. For methods, `object.method(args)` changes to `object |>.method(args)`. 12 | It looks like just an increase in `|>`, but since the bond strength is low, the amount of `()` may be reduced. 13 | 14 | ``` erg 15 | rand = -1.0..1.0 |>.sample!() 16 | log rand # 0.2597... 17 | 1+1*2 |>.times do log("a", end: "") # aaa 18 | # without `|>`, the following will be `evens = (1..100).iter().filter(i -> i % 2 == 0).collect(Array)` 19 | evens = 1..100 |>.iter |>.filter i -> i % 2 == 0 |>.collect Array 20 | # or 21 | _evens = 1..100\ 22 | .iter() \ 23 | .filter i -> i % 2 == 0 \ 24 | .collect Array 25 | ``` 26 | 27 |

28 | Previous | Next 29 |

30 | -------------------------------------------------------------------------------- /doc/JA/syntax/container_ownership.md: -------------------------------------------------------------------------------- 1 | # Subscript(添字アクセス) 2 | 3 | `[]`は通常のメソッドとは異なっています。 4 | 5 | ```erg 6 | a = [!1, !2] 7 | a[0].inc!() 8 | assert a == [2, 2] 9 | ``` 10 | 11 | サブルーチンの戻り値には参照を指定できないということを思い出してください。 12 | `a[0]`の型は、ここでは明らかに`Ref!(Int!)`であるはずです(`a[0]`の型は文脈に依存します)。 13 | よって、`[]`は実際には`.`と同じく特別な構文の一部です。Pythonとは違い、オーバーロードできません。 14 | メソッドで`[]`の挙動を再現することもできません。 15 | 16 | ```erg 17 | C = Class {i = Int!} 18 | C.get(ref self) = 19 | self::i # TypeError: `self::i` is `Int!` (require ownership) but `get` doesn't own `self` 20 | C.steal(self) = 21 | self::i 22 | # NG 23 | C.new({i = 1}).steal().inc!() # OwnershipWarning: `C.new({i = 1}).steal()` is not owned by anyone 24 | # hint: assign to a variable or use `uwn_do!` 25 | # OK (assigning) 26 | c = C.new({i = 1}) 27 | i = c.steal() 28 | i.inc!() 29 | assert i == 2 30 | # or (own_do!) 31 | own_do! C.new({i = 1}).steal(), i => i.inc!() 32 | ``` 33 | 34 | また、`[]`は所有権を奪うこともできますが、その際に要素がシフトするわけではありません。 35 | 36 | ```erg 37 | a = [!1, !2] 38 | i = a[0] 39 | i.inc!() 40 | assert a[1] == 2 41 | a[0] # OwnershipError: `a[0]` is moved to `i` 42 | ``` 43 | -------------------------------------------------------------------------------- /compiler/erg_common/levenshtein.rs: -------------------------------------------------------------------------------- 1 | /// Calculates the Levenshtein distance (edit distance). 2 | /// This shows how close the strings are to each other. 3 | pub fn levenshtein(lhs: &str, rhs: &str) -> usize { 4 | let lhs = lhs.chars().collect::>(); 5 | let rhs = rhs.chars().collect::>(); 6 | let l_len = lhs.len(); 7 | let r_len = rhs.len(); 8 | // l_len+1 × r_len+1 array 9 | let mut table = vec![vec![0; r_len + 1]; l_len + 1]; 10 | for i in 0..l_len + 1 { 11 | table[i][0] = i; 12 | } 13 | for i in 0..r_len + 1 { 14 | table[0][i] = i; 15 | } 16 | for i1 in 0..l_len { 17 | for i2 in 0..r_len { 18 | let cost = if lhs[i1] == rhs[i2] { 0 } else { 1 }; 19 | table[i1 + 1][i2 + 1] = *[ 20 | table[i1][i2 + 1] + 1, // delete cost 21 | table[i1 + 1][i2] + 1, // insert cost 22 | table[i1][i2] + cost, // replace cost 23 | ] 24 | .iter() 25 | .min() 26 | .unwrap(); 27 | } 28 | } 29 | table[l_len][r_len] 30 | } 31 | -------------------------------------------------------------------------------- /doc/EN/syntax/06_operator.md: -------------------------------------------------------------------------------- 1 | # operator 2 | 3 | Operators are symbols that represent operations. Operands are things to the (left) right of an operator. 4 | 5 | Operators are a kind of function, and thus are themselves first-class objects that can be bound to variables. When binding, it is necessary to enclose it with ``. 6 | For `+` (and `-`), there are both unary and binary operators, so `_+_`(binary operation)/`+_`(unary operation ) must be specified. 7 | 8 | ``` erg 9 | add = `+` # SyntaxError: specify `_+_` or `+_` 10 | add=`_+_` 11 | assert f(1, 2) == 3 12 | assert f("a", "b") == "ab" 13 | 14 | g = `*` # OK, this is binary only 15 | assert g(1, 2) == 2 16 | ``` 17 | 18 | Some fundamental operators, called special forms, cannot be bound. 19 | 20 | ``` erg 21 | def = `=` # SyntaxError: cannot bind `=` operator, this is a special form 22 | # NG: def x, 1 23 | function = `->` # SyntaxError: cannot bind `->` operator, this is a special form 24 | # NG: function x, x + 1 25 | ``` 26 | 27 |

28 | Previous | Next 29 |

30 | -------------------------------------------------------------------------------- /doc/JA/syntax/type/newtype.md: -------------------------------------------------------------------------------- 1 | # Newtype pattern 2 | 3 | ここでは、Rustでよく使われるnewtypeパターンのErg版を紹介します。 4 | 5 | Ergはでは以下のように型のエイリアスを定義することができますが、これはあくまで同じ型を指します。 6 | 7 | ```erg 8 | UserId = Int 9 | ``` 10 | 11 | なので、例えば`UserId`型の数値は8桁の正数、という仕様があったとしても、`Int`型と同じなので10でも-1でも入れられてしまうわけです。`Nat`にすれば-1は弾くことができますが、8桁の数という性質はErgの型システムのみでは表現できません。 12 | 13 | また、例えばあるデータベースのシステムを設計する時、いくつかの種類のIDがあったとします。ユーザーID, 商品ID, 注文IDなどとIDの種類が増えてくると、関数に違う種類のIDを渡すというバグが発生する可能性があります。ユーザーIDと商品IDなどは構造的に等価であっても、意味論的には異なるわけです。 14 | 15 | newtypeパターンはこのような場合に適したデザインパターンです。 16 | 17 | ```erg 18 | UserId = Class {id = Nat} 19 | UserId. 20 | new id: Nat = 21 | assert id.dights().len() == 8, else="UserId must be a positive number with length 8" 22 | UserId::__new__ {id;} 23 | 24 | i = UserId.new(10000000) 25 | print! i # <__main__.UserId object> 26 | i + UserId.new(10000001) # TypeError: + is not implemented between `UserId` and `UserId` 27 | ``` 28 | 29 | コンストラクタが8桁の数という事前条件を保証してくれます。 30 | この`UserId`は`Nat`の持つメソッドをすべて失ってしまうので、必要な演算を都度再定義する必要があります。 31 | 再定義するコストが見合わない場合は、継承を使う方がよいでしょう。逆にメソッドがなくなるという性質が望ましい場合もあるので、状況に応じて適切な方法を選んでください。 32 | -------------------------------------------------------------------------------- /doc/JA/syntax/type/special.md: -------------------------------------------------------------------------------- 1 | # 特殊型(Self, Super) 2 | 3 | `Self`は自身の型を表します。単にエイリアスとして使うことも出来ますが、派生型中では意味が変わる(自身の型を指す)ので注意してください。 4 | 5 | ```erg 6 | @Inheritable 7 | C = Class() 8 | C. 9 | new_self() = Self.new() 10 | new_c() = C.new() 11 | D = Inherit C 12 | 13 | classof D.new_self() # D 14 | classof D.new_c() # C 15 | ``` 16 | 17 | `Super`は基底クラスの型を表します。メソッド自体は基底クラスのものを参照しますが、インスタンスは自身の型を使います。 18 | 19 | ```erg 20 | @Inheritable 21 | C = Class() 22 | 23 | D = Inherit(C) 24 | D. 25 | new_super() = Super.new() 26 | new_c() = C.new() 27 | 28 | classof D.new_super() # D 29 | classof D.new_c() # C 30 | ``` 31 | 32 | ## 特殊型変数 33 | 34 | `Self`, `Super`は、構造型・トレイト中では型変数として使用できます。これは、その型のサブタイプであるところのクラスを指します。すなわち、型`T`中で`Self`は`Self <: T`を意味します。 35 | 36 | ```erg 37 | Add R, O = Trait { 38 | .`_+_`: Self, R -> O 39 | } 40 | BinAdd = Subsume Add(Self, Self.AddO), { 41 | .AddO = Type 42 | } 43 | 44 | IntIsBinAdd = Patch(Int, Impl: BinAdd) 45 | IntIsBinAdd. 46 | AddO = Int 47 | 48 | assert 1 in Add(Int, Int) 49 | assert 1 in BinAdd 50 | assert Int < Add(Int, Int) 51 | assert Int < BinAdd 52 | ``` 53 | -------------------------------------------------------------------------------- /doc/JA/tools/test.md: -------------------------------------------------------------------------------- 1 | # testサブコマンド 2 | 3 | ergコマンドにはtestというサブコマンドがあり、テスト実装、及び実行の支援を行う。 4 | 5 | ## Testデコレータ(@Test) 6 | 7 | Ergではパッケージ中の`tests`ディレクトリか`*.test.er`ファイル中の`@Test`を付けたサブルーチンを`erg test`コマンドでテストする。 8 | `tests`のサブルーチンはブラックボックステスト、`*.test.er`のサブルーチンはホワイトボックステストを担当する。 9 | 10 | ```erg 11 | # tests/test1.er 12 | {add; ...} = import "foo" 13 | 14 | @Test 15 | test_1_plus_n(n: Nat) = 16 | assert add(1, n) == n + 1 17 | ``` 18 | 19 | 実行結果がサマリとして表示され、各種ファイル形式(.md, .csv, etc.)で出力もできる。 20 | 21 | ## Doc Test 22 | 23 | Ergでは`#`, `#[`でコメント行となるが、`##`, `#[[`でdoc commentとなり、VSCodeなどエディタからコメントをmd表示できる。 24 | さらにdoc comment中のソースコードはergと指定されていれば、erg testコマンドで自動テストされる。 25 | 以下はテストの例である。 26 | 27 | ```erg 28 | VM = ... 29 | ... 30 | #[[ 31 | execute commands. 32 | ```erg 33 | # VM in standard configuration 34 | {vm1; ...} = import "tests/template" 35 | 36 | assert vm1.exec!("i = 0") == None 37 | assert vm1.exec!("i").try_into(Int)? == 0 38 | ``` 39 | ]]# 40 | .exec! ref self, src = 41 | ... 42 | ... 43 | ``` 44 | 45 | テストを行う際に使う典型的なオブジェクトは`tests/template`モジュールに定義する。 46 | -------------------------------------------------------------------------------- /doc/JA/improved_points.md: -------------------------------------------------------------------------------- 1 | # Pythonから改良された点 2 | 3 | ## 静的解析を行う(静的型チェック、変数・プロパティチェック) 4 | 5 | 静的型チェックの恩恵は今更強調するまでもないほどですが、変数・プロパティの存在チェックもかなり効いてくる部分です。 6 | 7 | ## 厳密にスコープを扱う 8 | 9 | Pythonでは文がスコープを持ちません。 10 | そのため、`for`や`if`の中で定義した変数は外に影響を与えてしまいます。気軽に変数を名付けることができません。 11 | 12 | ```python 13 | for i in range(10): 14 | x = 1 15 | print(i + x) 16 | print(x) # 1 17 | ``` 18 | 19 | Ergでは全てのブロックがスコープを持ち、完全に隔離されています。 20 | 21 | ## 可変オブジェクトと不変オブジェクトの区別が明確 22 | 23 | Pythonは可変オブジェクトと不変オブジェクト、ヒープオブジェクトと値オブジェクトの区別が明確ではないため、タプルは不変だがリストは可変...などと言った知識を頭に入れておく必要があります。 24 | また、自作クラスを不変にしたいとき、面倒な手順をふまなくてはなりません。 25 | 26 | ```python 27 | # このコードが過去のPythonでは有効だったと信じられますか? 28 | i = 256 29 | assert i is 256 30 | i = 257 31 | assert i is not 257 32 | ``` 33 | 34 | ## トレイトを持つ 35 | 36 | Javaのインターフェースと同じように、契約に基づくプログラミングを行うことができます。 37 | 38 | Pythonにも抽象基底クラスがありますが、この手の構造体は静的型付けと組み合わせることで最大の効果を発揮します。 39 | 40 | ## 依存関係を静的に解決する 41 | 42 | 長時間実行の末にモジュールが足りずエラーなどといったゲンナリする体験を未然に防ぎます。 43 | 44 | ## 組み込みのパッケージマネージャー 45 | 46 | 規格化されたディレクトリ構造とビルドファイルを用いて再現性のあるビルドが可能です。 47 | ロックファイルの生成やバージョン管理はもちろん行われます。 48 | anacondaやらpyenvやらpoetryやらをプロジェクトごとに取捨選択したり組み合わせたりする必要はありません。 49 | -------------------------------------------------------------------------------- /doc/JA/compiler/memory_management.md: -------------------------------------------------------------------------------- 1 | # オブジェクトの種別 2 | 3 | オブジェクトにはSize, Mutabilityの2つの属性がある。 4 | 5 | ## Size(Small/Big/Unsized) 6 | 7 | 比較的小さいサイズのオブジェクトは「Small」と呼ばれる。小さいとみなされるサイズはプラットフォーム依存である。 8 | これに該当するオブジェクトは基本的にスタックで管理される。複製(duplication)は値ごとする(Light clone)ので、参照カウントは行われない。 9 | ただしスタックの80%以上が消費された場合は、ヒープ管理に移行する。 10 | 11 | 比較的大きいサイズのオブジェクトは「Big」と呼ばれる。これに該当するオブジェクトはヒープで管理される。 12 | 複製は大抵RCで管理される(copy)。 13 | 14 | (実行時)可変サイズのオブジェクトは「Unsized」と呼ばれる。対してSmall/Bigは「Sized」と呼ばれる。 15 | 可変オブジェクトだから全てUnsizedとは限らない。長さが10で中身を書き換えられる可変配列([T; !N])はMut Sizedオブジェクトである。 16 | 不変オブジェクトは全てSizedとなる。当たり前のようにも聞こえるが、多くの言語においてスライス―配列の部分(不変)参照)―はUnsizedとなっている。 17 | 逆にUnsizedオブジェクトは可変なので、全てヒープで管理される。コピー(`.frozen`で生成する)はオリジナルが破壊的に変更されると使用不可になる。完全な複製はクローンで行う。 18 | 19 | ## Mutability(Immut/Mut) 20 | 21 | 不変オブジェクトは「Immut」と呼ばれる。これに該当するオブジェクトはLight duplicationまたはコピーができる。コピーは実体を1つだけ持つ。 22 | 可変オブジェクトは「Mut」と呼ばれる。これに該当するオブジェクトはコピーができないので、複製したいときはHeavy duplication = cloneを使う。 23 | cloneは内容が同じオブジェクトを1から作り直すので、コピーより低速である。 24 | 25 | ## .dupの詳細 26 | 27 | `.dup`はその時によって最適なアルゴリズムが選択される。 28 | 不変オブジェクトに対しては大抵の場合RCを使う。可変オブジェクトにはcloneを使う。 29 | 30 | 可変オブジェクトを`.dup`すると可変オブジェクトが作られるが、不変オブジェクトが欲しい場合は`.frozen`を使う。 31 | これはRCで管理され、オブジェクトが改変されると使えなくなる。 32 | -------------------------------------------------------------------------------- /doc/JA/syntax/type/06_nst_vs_sst.md: -------------------------------------------------------------------------------- 1 | # 記名的部分型 vs. 構造的部分型 2 | 3 | ```erg 4 | # SST 5 | Months = 0..12 6 | MonthsImpl = Patch Months 7 | MonthsImpl. 8 | name self = 9 | match self: 10 | 1 -> "January" 11 | 2 -> "February" 12 | 3 -> "March" 13 | ... 14 | # NST 15 | MonthsClass = Class Months 16 | MonthsClass. 17 | name self = 18 | match self: 19 | 1 -> "january" 20 | 2 -> "february" 21 | 3 -> "march" 22 | ... 23 | 24 | assert 12 in Months 25 | assert 2.name() == "February" 26 | assert not 12 in MonthsClass 27 | assert MonthsClass.new(12) in MonthsClass 28 | # クラスでラップしても構造型は使える 29 | assert MonthsClass.new(12) in Months 30 | # 両方ある場合クラスメソッドが優先 31 | assert MonthsClass.new(2).name() == "february" 32 | ``` 33 | 34 | ## 結局、NSTとSSTどちらを使えばいいのか? 35 | 36 | どちらにすればよいか判断がつかないときはNSTを推奨します。 37 | SSTはどんなユースケースでも破綻しないコードを書く抽象化能力が要求されます。よい抽象化を実現できれば高い生産性を発揮できますが、間違った抽象化(__見かけによる共通化__)を行うと逆効果となってしまいます。NSTは抽象性をあえて抑え、このリスクを減らすことができます。あなたがライブラリの実装者でないならば、NSTのみでコーディングを行っても悪くはないでしょう。 38 | 39 |

40 | Previous | Next 41 |

42 | -------------------------------------------------------------------------------- /doc/EN/syntax/14_set.md: -------------------------------------------------------------------------------- 1 | # Set 2 | 3 | A set is an unordered array with no duplicates. 4 | 5 | ```erg 6 | assert Set.from([1, 2, 3, 2, 1]) == {1, 2, 3} 7 | assert {1, 2} == {1, 1, 2} # duplicates are automatically removed 8 | assert {1, 2} == {2, 1} 9 | ``` 10 | 11 | Sets can perform mathematical set operations. 12 | 13 | ```erg 14 | assert 1 in {1, 2, 3} 15 | assert not 1 in {} 16 | assert {1} or {2} == {1, 2} 17 | assert {1, 2} and {2, 3} == {2} 18 | assert {1, 2} not {2} == {1} 19 | ``` 20 | 21 | A set is a homogenous collection. Objects of different classes must be made equal in order to coexist. 22 | 23 | ```erg 24 | s1 = {"a", 1, "b", -1} # TypeError 25 | s2: {Int or Str} = {"a", 1, "b", -1} 26 | ``` 27 | 28 | ## Set as Type 29 | 30 | Sets can also be treated as types. Such a type is called an __Enum type_. 31 | 32 | ```erg 33 | i: {1, 2, 3} = 1 34 | assert i in {1, 2, 3} 35 | ``` 36 | 37 | The elements of the set are directly the elements of the type. 38 | Note that the set itself is different. 39 | 40 | ```erg 41 | mut_set = {1, 2, 3}.into {Int; !3} 42 | mut_set.insert!(4) 43 | ``` 44 | 45 |

46 | Previous | Next 47 |

48 | -------------------------------------------------------------------------------- /doc/EN/syntax/34_generator.md: -------------------------------------------------------------------------------- 1 | # Generator 2 | 3 | Generators are special procedures that use the `yield!` procedure in a block. 4 | 5 | ```erg 6 | g!() = 7 | yield! 1 8 | yield! 2 9 | yield! 3 10 | ``` 11 | 12 | `yield!` is a procedure defined in a block of subroutines that calls `self!.yield!`. Like `return`, it returns the value passed to it as a return value, but it has the feature of saving the current execution state of the block and executing it from the beginning when it is called again. 13 | A generator is both a procedure and an iterator; a Python generator is a function that creates an iterator, while Erg iterates directly. Procedures themselves are generally not mutable objects (no `!`), but a generator is a mutable object because its own contents can change with each execution. 14 | 15 | ```erg 16 | # Generator! 17 | g!: Generator!((), Int) 18 | assert g!() == 1 19 | assert g!() == 2 20 | assert g!() == 3 21 | ``` 22 | 23 | A Python-style generator can be defined as follows. 24 | 25 | ```erg 26 | make_g() = () => 27 | yield! 1 28 | yield! 2 29 | yield! 3 30 | make_g: () => Generator! 31 | ``` 32 | 33 |

34 | Previous | Next 35 |

36 | -------------------------------------------------------------------------------- /doc/EN/syntax/05_builtin_funcs.md: -------------------------------------------------------------------------------- 1 | # Built-in functions 2 | 3 | ## if 4 | 5 | `if` is a function that changes processing depending on a condition. 6 | 7 | ```erg 8 | result: Option Int = if! Bool.sample!(), do: 9 | log "True was chosen" 10 | 1 11 | print! result # None (or 1) 12 | ``` 13 | 14 | `.sample!()` returns a random set of values. If the return value is true, `print! "True"` is executed. 15 | You can also specify what to do if the condition is false; the second do block is called the else block. 16 | 17 | ```erg 18 | result: Nat = if Bool.sample!(): 19 | do: 20 | log "True was chosen" 21 | 1 22 | do: 23 | log "False was chosen" 24 | 0 25 | print! result # 1 (or 0) 26 | ``` 27 | 28 | If the process is a single line, you can omit indentation. 29 | 30 | ```erg 31 | result = if Bool.sample!(): 32 | do 1 33 | do 0 34 | ``` 35 | 36 | ## for 37 | 38 | You can use `for` to write a repeating process. 39 | 40 | ```erg 41 | match_s(ss: Iterator(Str), pat: Pattern): Option Str = 42 | for ss, s -> 43 | if pat.match(s).is_some(): 44 | break s 45 | ``` 46 | 47 |

48 | Previous | Next 49 |

50 | -------------------------------------------------------------------------------- /examples/rank2.er: -------------------------------------------------------------------------------- 1 | id x = x 2 | add1 x = x + 1 3 | 4 | Reversible = Trait { 5 | .reverse = Self.() -> Self.RevReturnType 6 | .RevReturnType = Type 7 | } 8 | Rev4Bool = Patch Bool, Impl=Reversible 9 | Rev4Bool 10 | .reverse self = not self 11 | .RevReturnType = Bool 12 | # Str already has the 'reverse' method 13 | Rev4Str = Patch Str, Impl=Reversible 14 | Rev4Str 15 | .RevReturnType = Str 16 | Rev4Nat = Patch Nat, Impl=Reversible 17 | Rev4Nat 18 | .reverse self = -self 19 | .RevReturnType = Neg 20 | 21 | reverse x = x.reverse() # |R <: Reversible| R -> R.RevReturnType 22 | assert False == reverse True 23 | assert "olleh" == reverse "hello" 24 | assert -5 == reverse 5 25 | 26 | # rank-1 27 | # : {(T -> U, (T, T, T)) -> (U, U, U) | T, U: Type} 28 | triple_map|T| f, (l: T, c: T, r: T) = f(l), f(c), f(r) 29 | 30 | assert triple_map(id, (1, 2, 3)) == (1, 2, 3) 31 | assert triple_map(add1, (1, 2, 3)) == (2, 3, 4) 32 | 33 | # rank-2 34 | # : {(F, (T, U, V)) -> (W, X, Y) | F, T, U, V, W, X, Y: Type; F <: T -> W; F <: U -> X; F <: V -> Y} 35 | triple_map2|T, U, V| f, (l: T, c: U, r: V) = f(l), f(c), f(r) 36 | 37 | assert triple_map2(id, (True, "a", 5)) == (True, "a", 5) 38 | assert triple_map2(reverse, (True, "hello", 5)) == (False, "olleh", -5) 39 | -------------------------------------------------------------------------------- /doc/JA/syntax/type/advanced/mut_struct.md: -------------------------------------------------------------------------------- 1 | # 可変構造型 2 | 3 | `T!`型は任意の`T`型オブジェクトを入れられて差し替え可能なボックス型であると説明した。 4 | 5 | ```erg 6 | Particle! State: {"base", "excited"}! = Class(..., Impl: Phantom State) 7 | Particle!. 8 | # このメソッドはStateを"base"から"excited"に遷移させる 9 | apply_electric_field!(ref! self("base" ~> "excited"), field: Vector) = ... 10 | ``` 11 | 12 | `T!`型は、データの差し替えは行えるが、その構造を変えることはできない。 13 | より現実のプログラムの振舞いに近い言い方をすれば、(ヒープ上の)サイズを変更できない。このような型を、不変構造(可変)型と呼ぶ。 14 | 15 | 実は、不変構造型では表すことのできないデータ構造が存在する。 16 | 例えば、可変長配列である。`[T; N]!`型は任意の`[T; N]`であるオブジェクトを入れることができるが、`[T; N+1]`型オブジェクトなどに差し替えることはできない。 17 | 18 | すなわち、長さを変えられないのである。長さを変えるためには、型自体の構造を変化させなくてはならない。 19 | 20 | それを実現するのが可変構造(可変)型である。 21 | 22 | ```erg 23 | v = [Str; !0].new() 24 | v.push! "Hello" 25 | v: [Str; !1] 26 | ``` 27 | 28 | 可変構造型では可変化する型引数に`!`を付ける。上の場合は、`[Str; !0]`型を`[Str; !1]`型などに変更することができる。すなわち、長さを変更できる。 29 | 因みに、`[T; !N]`型は`MutLenArray(T, !N)`型の糖衣構文である。 30 | 31 | 可変構造型はもちろんユーザー定義も可能である。ただし、不変構造型とは構成法に関していくつか違いがあるので注意が必要である。 32 | 33 | ```erg 34 | Nil T = Class(Impl: Phantom T) 35 | List T, !0 = Inherit Nil T 36 | List T, N: Nat! = Class {head = T; rest = List(T, !N-1)]} 37 | List(T, !N). 38 | push! ref! self(N ~> N+1, ...) head: T = 39 | self.update! old -> Self.new {head; old} 40 | ``` 41 | -------------------------------------------------------------------------------- /doc/JA/API/operators.md: -------------------------------------------------------------------------------- 1 | # 演算子 2 | 3 | ## 中置演算子 4 | 5 | ### `_+_`|R; O; A <: Add(R, O)|(x: A, y: R) -> O 6 | 7 | 加算を実行する。 8 | 9 | ### `_-_`|R; O; S <: Sub(R, O)|(x: S, y: R) -> O 10 | 11 | 減算を実行する。 12 | 13 | ### `*`|R; O; M <: Mul R, O|(x: M, y: R) -> O 14 | 15 | 乗算を実行する。 16 | 17 | ### `/`|R; O; D <: Div(R, O)|(x: D, y: R) -> O 18 | 19 | 除算を実行する。 20 | 21 | ## 中置アルファベット演算子 22 | 23 | ### `and`(x: Bool, y: Bool) -> Bool 24 | 25 | and演算を実行する。 26 | 27 | ### `or`(x: Bool, y: Bool) -> Bool 28 | 29 | and演算を実行する。 30 | 31 | ## 前置演算子 32 | 33 | ### `+_`|T <: Num|(x: T) -> T 34 | 35 | デフォルトではidと同じ。 36 | 37 | ### `-_`|T <: Num|(x: T) -> T.Neg 38 | 39 | 例えば、Nat.`-`: Nat -> Negとなり、戻り値が違う。 40 | 41 | ### `!`|T <: Immut|(x: T) -> `T!` 42 | 43 | 不変オブジェクトから可変オブジェクトを生成する。 44 | この演算子自体はProceduralではなく、関数内でも使える。 45 | 46 | ### `..`|T <: Ord|(x: T) -> Range T 47 | 48 | x終わりで下界のないRangeオブジェクトを生成する。 49 | x..xはイテレータとしてxのみ返す。 50 | 51 | ### `..<`|T <: Ord|(x: T) -> Range T 52 | 53 | x.. Range T 61 | 62 | x始まりで上界のないRangeオブジェクトを生成する。 63 | 64 | ### |T <: Ord|(x: T)`<..` -> Range T 65 | -------------------------------------------------------------------------------- /doc/JA/syntax/03_declaration.md: -------------------------------------------------------------------------------- 1 | # Declaration(宣言) 2 | 3 | 宣言は、使用する変数の型を指定する構文です。 4 | 宣言はコード中のどこでも可能ですが、宣言しただけでその変数を参照することはできません。必ず初期化する必要があります。 5 | 代入後の宣言では、代入されたオブジェクトと型が適合するかをチェック可能です。 6 | 7 | ```erg 8 | i: Int 9 | # i: Int = 2のように代入と同時に宣言可能 10 | i = 2 11 | i: Num 12 | i: Nat 13 | i: -2..2 14 | i: {2} 15 | ``` 16 | 17 | 代入後の宣言は`assert`による型チェックと似ていますが、コンパイル時にチェックされるという特徴があります。 18 | 実行時の`assert`による型チェックは「〇〇型かもしれない」で検査が可能ですが、コンパイル時の`:`による型チェックは厳密です。 19 | 「〇〇型である」ことが確定していなくては検査を通らず、エラーとなります。 20 | 21 | ```erg 22 | i = (-1..10).sample!() 23 | assert i in Nat # これは通るかもしれない 24 | i: Int # これは通る 25 | i: Nat # これは通らない(-1はNatの要素ではないから) 26 | ``` 27 | 28 | 関数は以下の4種類の方法で宣言が可能です。どれも戻り値型の省略はできません。 29 | 30 | ```erg 31 | f(x: Int, y: Int): Int 32 | f(Int, Int): Int 33 | f: (x: Int, y: Int) -> Int 34 | f: (Int, Int) -> Int 35 | ``` 36 | 37 | 引数名を明示して宣言した場合、定義時に名前が違うと型エラーとなります。引数名の任意性を与えたい場合は2, 4番目の方法で宣言すると良いでしょう。その場合、型検査で見られるのはメソッド名とその型のみです。 38 | 39 | ```erg 40 | T = Trait { 41 | .f(x: Int, y: Int): Int 42 | } 43 | 44 | C = Class(U, Impl: T) 45 | C.f(a: Int, b: Int): Int = ... # TypeError: `.f` must be type of `(x: Int, y: Int) -> Int`, not `(a: Int, b: Int) -> Int` 46 | ``` 47 | 48 |

49 | Previous | Next 50 |

51 | -------------------------------------------------------------------------------- /doc/JA/syntax/20_naming_rule.md: -------------------------------------------------------------------------------- 1 | # 命名規則 2 | 3 | 変数を定数式として使いたい場合は大文字で始まらなくてはならない。二文字以降は小文字でもよい。 4 | 5 | ```erg 6 | i: Option Type = Int 7 | match i: 8 | t: Type -> log "type" 9 | None -> log "None" 10 | ``` 11 | 12 | 副作用のあるオブジェクトは`!`で終わらなくてはならない。プロシージャとプロシージャルメソッド、そして可変型である。 13 | ただし、`Proc`型自体は可変型ではない。 14 | 15 | ```erg 16 | # Callable == Func or Proc 17 | c: Callable = print! 18 | match c: 19 | p! -> log "proc" # 自明なので`: Proc`を省略可 20 | f -> log "func" 21 | ``` 22 | 23 | 属性を外部に公開したい場合は、`.`を始めにつけて定義する。`.`を初めにつけなかった場合非公開となる。混乱を避けるため同一のスコープ内で共存はできない。 24 | 25 | ```erg 26 | o = {x = 1; .x = 2} # SyntaxError: private and public variables with the same name cannot coexist 27 | ``` 28 | 29 | ## リテラル識別子(Literal Identifiers) 30 | 31 | 以上の規則は、文字列をシングルクォート('')で囲むと回避できる。すなわち、プロシージャルオブジェクトも`!`をつけずに代入することができる。ただしこの場合、値が定数式でも定数とはみなされない。 32 | このようにシングルクォートで囲まれた文字列による識別子をリテラル識別子という。 33 | これは、Pythonなど他言語のAPI(FFI)を呼び出す際に使う。 34 | 35 | ```erg 36 | bar! = pyimport("foo").'bar' 37 | ``` 38 | 39 | Ergでも有効な識別子の場合は、''で囲む必要はない。 40 | 41 | さらに、リテラル識別子中では記号も空白も入れることができるため、通常は識別子として使えない文字列を識別子として使うことができる。 42 | 43 | ```erg 44 | '∂/∂t' y 45 | 'test 1: pass x to y'() 46 | ``` 47 | 48 |

49 | Previous | Next 50 |

51 | -------------------------------------------------------------------------------- /examples/enum.er: -------------------------------------------------------------------------------- 1 | LitExpr = Class {.i = Int}, Impl: Show 2 | LitExpr. 3 | new i = Self::__new__ {.i;} 4 | show &self = "{self.i}" 5 | AddExpr = Class {.lhs = Expr, .rhs = Expr}, Impl: Show 6 | AddExpr. 7 | new lhs, rhs = Self::__new__ {.lhs; .rhs} 8 | show &self = "{self.lhs} + {self.rhs}" 9 | SubExpr = Class {.lhs = Expr, .rhs = Expr}, Impl: Show 10 | SubExpr. 11 | new lhs, rhs = Self::__new__ {.lhs; .rhs} 12 | show &self = "{self.lhs} - {self.rhs}" 13 | PosExpr = Class {.expr = Expr}, Impl: Show 14 | PosExpr. 15 | new expr = Self::__new__ {.expr;} 16 | show &self = "+{self.expr}" 17 | NegExpr = Class {.expr = Expr}, Impl: Show 18 | NegExpr. 19 | new expr = Self::__new__ {.expr;} 20 | show &self = "-{self.expr}" 21 | 22 | Expr = Enum: 23 | LitExpr 24 | AddExpr 25 | SubExpr 26 | NegExpr 27 | Expr. 28 | lit = Self.cons(LitExpr) 29 | add = Self.cons(AddExpr) 30 | eval self = 31 | match self: 32 | l: Expr.LitExpr -> l.i 33 | a: Expr.AddExpr -> a.lhs + a.rhs 34 | s: Expr.SubExpr -> s.lhs - s.rhs 35 | p: Expr.PosExpr -> p.expr 36 | n: Expr.NegExpr -> -n.expr 37 | 38 | expr = Expr.add Expr.lit(1), Expr.lit(2) 39 | print! expr # 1 + 2 40 | assert expr.eval() == 3 41 | -------------------------------------------------------------------------------- /doc/JA/syntax/32_integration_with_Python.md: -------------------------------------------------------------------------------- 1 | # Pythonとの連携 2 | 3 | Pythonから取り込んだオブジェクトはデフォルトですべて`Object`型になります。このままでは比較もできないので、型の絞り込みを行う必要があります。 4 | 5 | ## 標準ライブラリの型指定 6 | 7 | Python標準ライブラリにあるAPIはすべてErg開発チームにより型が指定されています。 8 | 9 | ```erg 10 | time = pyimport "time" 11 | time.sleep! 1 12 | ``` 13 | 14 | ## ユーザースクリプトの型指定 15 | 16 | Pythonの`foo`モジュールに型を付ける`foo.d.er`ファイルを作成します。 17 | Python側でのtype hintは100%の保証にならないので無視されます。 18 | 19 | ```python 20 | # foo.py 21 | X = ... 22 | def bar(x): 23 | ... 24 | def baz(): 25 | ... 26 | ``` 27 | 28 | ```erg 29 | # foo.d.er 30 | foo = pyimport "foo" 31 | .X = declare foo.'X', Int 32 | .bar = declare foo.'bar', Int -> Int 33 | .baz! = declare foo.'baz', () => Int 34 | ``` 35 | 36 | ```erg 37 | foo = pyimport "foo" 38 | assert foo.bar(1) in Int 39 | ``` 40 | 41 | これは、実行時に型チェックを行うことで型安全性を担保しています。`declare`関数は概ね以下のように動作します。 42 | 43 | ```erg 44 | declare|S: Subroutine| sub!: S, T = 45 | # 実は、=>はブロックの副作用がなければ関数にキャストできる 46 | x => 47 | assert x in T.Input 48 | y = sub!(x) 49 | assert y in T.Output 50 | y 51 | ``` 52 | 53 | これは実行時オーバーヘッドとなるので、PythonスクリプトをErgの型システムで静的に型解析するプロジェクトが計画されています。 54 | 55 |

56 | Previous | Next 57 |

58 | -------------------------------------------------------------------------------- /doc/JA/syntax/type/advanced/projection.md: -------------------------------------------------------------------------------- 1 | # Projection Type(射影型) 2 | 3 | 射影型は、次のコードにおける`Self.AddO`のような型を表します。 4 | 5 | ```erg 6 | Add R, O = Trait { 7 | .`_+_` = Self, R -> O 8 | } 9 | BinAdd = Subsume Add(Self, Self.AddO), { 10 | .AddO = Type 11 | } 12 | 13 | IntIsBinAdd = Patch(Int, Impl: BinAdd) 14 | IntIsBinAdd. 15 | AddO = Int 16 | ``` 17 | 18 | `Add(R, O)`型は何らかのオブジェクトとの加算が定義されている型、`BinAdd`は自身のクラスとの加算(閉じた加算)が定義されている型といえます。メソッドは型属性であるべきなので、`+`の型宣言はインデント以下に記述します。 19 | 引数のない`Add`型のミソとなるのが`.AddO: Type`という宣言で、これがないと右辺型がエラーになります。 20 | 21 | ```erg 22 | BinAdd = Add(Self, Self.AddO) # TypeError: trait object 'BinAdd' has no attribute 'AddO' 23 | ``` 24 | 25 | 射影型である`.AddO`型の実体は、`Add`のサブタイプである型が持ちます。例えば、`Int.AddO = Int`, `Odd.AddO = Even`です。 26 | 27 | ```erg 28 | assert Int < Add 29 | assert Int.AddO == Int 30 | assert Odd < Add 31 | assert Odd.AddO == Even 32 | ``` 33 | 34 | ## Appendix: 射影型の型推論 35 | 36 | ```erg 37 | f x: BinAdd = x + x 38 | 39 | f 10 40 | ``` 41 | 42 | 上のコードを例にして考えます。 43 | グローバル名前空間には以下の`+`の実装が存在します。 44 | 45 | ```erg 46 | `_+_`: {(A, R) -> O | R; O; A <: Add(R, O)} 47 | ``` 48 | 49 | `BinAdd = Add(Self, Self.AddO)`なので、`Add`型であるオブジェクトに対しては````_+_`: {(A, A) -> A.AddO | A <: Add(A, A.AddO)}```と置換できます。 50 | 51 | ```erg 52 | f|A <: BinAdd|(x: A): A.AddO = x + x 53 | ``` 54 | -------------------------------------------------------------------------------- /doc/JA/API/modules/external/alstruct.md: -------------------------------------------------------------------------------- 1 | # alstruct 2 | 3 | 代数的構造を表すトレイトや、それにかかるパッチを提供するモジュール。 4 | 5 | * member 6 | 7 | ## BinOp 8 | 9 | ```erg 10 | BinOp Op: Kind 2 = Subsume Op(Self, Self.ReturnTypeOf Op), Additional: { 11 | .ReturnTypeof = TraitType -> Type 12 | } 13 | 14 | Nat <: BinOp Add 15 | assert Nat.ReturnTypeof(Add) == Nat 16 | assert Nat.ReturnTypeof(Sub) == Int 17 | assert Nat.ReturnTypeof(Mul) == Nat 18 | assert Nat.ReturnTypeof(Div) == Positive Ratio 19 | ``` 20 | 21 | ## SemiGroup 22 | 23 | ```erg 24 | SemiGroup Op: Kind 2 = Op(Self, Self) 25 | 26 | IntIsSemiGroupAdd = Patch Int, Impl=SemiGroup Add 27 | 28 | Int <: SemiGroup Add 29 | ``` 30 | 31 | ## Functor 32 | 33 | ```erg 34 | ## * Identity law: x.map(id) == x 35 | ## * Composition law: x.map(f).map(g) == x.map(f.then g) 36 | Functor = Trait { 37 | .map|T, U: Type| = (Self(T), T -> U) -> Self U 38 | } 39 | ``` 40 | 41 | ## Applicative 42 | 43 | ```erg 44 | ## * Identity law: x.app(X.pure(id)) == x 45 | Applicative = Subsume Functor, Additional: { 46 | .pure|T: Type| = T -> Self T 47 | .app|T, U: Type| = (Self(T), Self(T -> U)) -> Self U 48 | } 49 | ``` 50 | 51 | ## Monad 52 | 53 | ```erg 54 | Monad = Subsume Applicative, Additional: { 55 | .bind|T, U: Type| = (Self(T), T -> Self U) -> Self U 56 | } 57 | ``` 58 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "erg" 3 | version = "0.2.2" 4 | description = "The Erg programming language" 5 | authors = ["Shunsuke Shibayama "] 6 | license = "MIT OR Apache-2.0" 7 | edition = "2021" 8 | repository = "https://github.com/erg-lang/erg" 9 | documentation = "https://docs.rs/erg" 10 | homepage = "https://erg-lang.github.io/" 11 | keywords = ["erg", "programming-language"] 12 | 13 | [workspace] 14 | members = [ 15 | "compiler/erg_common", 16 | "compiler/erg_compiler", 17 | "compiler/erg_parser", 18 | ] 19 | 20 | [features] 21 | # when "debug" feature is turned on, that of the following crates will also be turned on. 22 | debug = [ 23 | "erg_common/debug", 24 | "erg_parser/debug", 25 | "erg_compiler/debug", 26 | ] 27 | japanese = [ 28 | "erg_common/japanese", 29 | "erg_parser/japanese", 30 | "erg_compiler/japanese", 31 | ] 32 | 33 | [dependencies] 34 | erg_common = { version = "0.2.2", path = "./compiler/erg_common" } 35 | erg_parser = { version = "0.2.2", path = "./compiler/erg_parser" } 36 | erg_compiler = { version = "0.2.2", path = "./compiler/erg_compiler" } 37 | 38 | # [workspace] 39 | # member = ["cm", "dyne"] 40 | 41 | # [profile.release] 42 | # panic = 'abort' 43 | 44 | # [[bin]] 45 | # name = "cm" 46 | # path = "src/compiler/main.rs" 47 | -------------------------------------------------------------------------------- /compiler/erg_common/stdin.rs: -------------------------------------------------------------------------------- 1 | use std::cell::RefCell; 2 | use std::io::{stdin, BufRead, BufReader}; 3 | 4 | use crate::Str; 5 | 6 | pub struct StdinReader { 7 | pub lineno: usize, 8 | buf: Vec, 9 | } 10 | 11 | impl StdinReader { 12 | pub fn read(&mut self) -> Str { 13 | let mut buf = "".to_string(); 14 | let stdin = stdin(); 15 | let mut reader = BufReader::new(stdin.lock()); 16 | reader.read_line(&mut buf).unwrap(); 17 | self.lineno += 1; 18 | self.buf.push(buf.into()); 19 | self.buf.last().unwrap().clone() 20 | } 21 | 22 | pub fn reread(&self) -> Str { 23 | self.buf.last().unwrap().clone() 24 | } 25 | 26 | pub fn reread_lines(&self, ln_begin: usize, ln_end: usize) -> Vec { 27 | self.buf[ln_begin - 1..=ln_end - 1].to_vec() 28 | } 29 | } 30 | 31 | thread_local! { 32 | pub static READER: RefCell = RefCell::new(StdinReader{ lineno: 0, buf: vec![] }); 33 | } 34 | 35 | pub fn read() -> Str { 36 | READER.with(|s| s.borrow_mut().read()) 37 | } 38 | 39 | pub fn reread() -> Str { 40 | READER.with(|s| s.borrow().reread()) 41 | } 42 | 43 | pub fn reread_lines(ln_begin: usize, ln_end: usize) -> Vec { 44 | READER.with(|s| s.borrow_mut().reread_lines(ln_begin, ln_end)) 45 | } 46 | -------------------------------------------------------------------------------- /doc/EN/syntax/28_spread_syntax.md: -------------------------------------------------------------------------------- 1 | # Spread assignment 2 | 3 | In a spread assignment, a variable can be prefixed with `...` in front of the variable, all the remaining elements can be expanded into the variable. This is called a spread assignment. 4 | 5 | ```erg 6 | [x, ... .y] = [1, 2, 3] 7 | assert x == 1 8 | assert y == [2, 3]. 9 | x, ... .y = (1, 2, 3) 10 | assert x == 1 11 | assert y == (2, 3) 12 | ``` 13 | 14 | ## Extract assignment 15 | 16 | If nothing is written after `...`, the remaining elements are ignored and an assignment is made. This type of expansion assignment is specifically called an extract assignment. 17 | Extract assignment is a useful syntax for bringing certain attributes local to a module or record. 18 | 19 | ```erg 20 | {sin; cos; tan; ...} = import "math" 21 | ``` 22 | 23 | This way, `sin`, `cos`, `tan` can be used locally from then on. 24 | 25 | You can do the same with records. 26 | 27 | ```erg 28 | record = {x = 1; y = 2} 29 | {x; y; ...} = record 30 | ``` 31 | 32 | If you want to expand all of them, use `{*} = record`, this is equivalent to `open` in OCaml and so on. 33 | 34 | ```erg 35 | record = {x = 1; y = 2} 36 | {*} = record 37 | assert x == 1 and y == 2 38 | ``` 39 | 40 |

41 | Previous | Next 42 |

43 | -------------------------------------------------------------------------------- /src/scripts/repl_server.py: -------------------------------------------------------------------------------- 1 | # Append __ to all variables to prevent name collisions in exec 2 | # All strings must be quoted by single quotes to prevent shell interpretation 3 | import socket as __socket 4 | import sys as __sys 5 | import importlib as __importlib 6 | import io as __io 7 | 8 | __server_socket = __socket.socket() 9 | __server_socket.bind(('0.0.0.0', 8736)) 10 | __server_socket.listen(1) 11 | (__client_socket, __client_address) = __server_socket.accept() 12 | 13 | __already_loaded = False 14 | __res = '' 15 | 16 | while True: 17 | __order = __client_socket.recv(1024).decode() 18 | if __order == 'quit' or __order == 'exit': 19 | __client_socket.send('closed'.encode()) 20 | break 21 | elif __order == 'load': 22 | __sys.stdout = __io.StringIO() 23 | try: 24 | if __already_loaded: 25 | __res = str(exec('__importlib.reload(o)')) 26 | else: 27 | __res = str(exec('import o')) 28 | except e: 29 | __res = str(e) 30 | __already_loaded = True 31 | __out = __sys.stdout.getvalue().strip() 32 | __res = __out + '\n' + __res 33 | __client_socket.send(__res.encode()) 34 | else: 35 | __client_socket.send('unknown operation'.encode()) 36 | 37 | __client_socket.close() 38 | __server_socket.close() 39 | -------------------------------------------------------------------------------- /doc/JA/syntax/type/advanced/erasure.md: -------------------------------------------------------------------------------- 1 | # 型消去(Type erasure) 2 | 3 | 型消去とは、型引数に`_`を指定し、その情報をあえて捨てることです。型消去は多相型を持つ言語の多くが併せて持つ機能ですが、Ergの文法に即して言えば型引数消去といった方が正確でしょう。 4 | 5 | もっともよく見られる型消去された型の例は`[T, _]`でしょう。配列はコンパイル時にその長さが分からない場合もあります。例えば、コマンドライン引数を指す`sys.argv`は`[Str, _]`型です。コマンドライン引数の長さをErgのコンパイラは知りようがないため、長さに関する情報は諦めなくてはならないのです。 6 | しかし、型消去された型は、されていない型のスーパータイプになる(e.g. `[T; N] < [T; _]`)ため、より多くのオブジェクトを受け取れるようになります。 7 | `[T; N]`型のオブジェクトはもちろん`[T; _]`型のメソッドを使用できますが、使用後`n`の情報は消去されます。長さが変わってしまっているかもしれないからです。長さが変わらないならばシグネチャで示さなくてはなりません。 8 | 9 | ```erg 10 | # 配列の長さが変わらないことが保証される関数(sortなど) 11 | f: [T; N] -> [T; N] 12 | # されない関数(filterなど) 13 | g: [T; n] -> [T; _] 14 | ``` 15 | 16 | 型指定自体で`_`を使うとその型は`Object`までアップキャストされます。 17 | 型でない型引数(Int, Bool型など)の場合、`_`としたパラメータは未定義になります。 18 | 19 | ```erg 20 | i: _ # i: Object 21 | [_; _] == [Object; _] == Array 22 | ``` 23 | 24 | 型消去は型指定の省略とは違います。一度型引数情報を消去してしまうと、再びアサーションしなければ情報は戻りません。 25 | 26 | ```erg 27 | implicit = (1..5).iter().map(i -> i * 2).to_arr() 28 | explicit = (1..5).iter().map(i -> i * 2).into(Array(Nat)) 29 | ``` 30 | 31 | Rustでは以下のコードに対応します。 32 | 33 | ```rust 34 | let partial = (1..6).iter().map(|i| i * 2).collect::>(); 35 | ``` 36 | 37 | Ergでは型の部分省略はできず、代わりに高階カインド多相を使用します。 38 | 39 | ```erg 40 | # collectはカインドを受け取る高階カインドのメソッド 41 | hk = (1..5).iter().map(i -> i * 2).collect(Array) 42 | hk: Array(Int) 43 | ``` 44 | -------------------------------------------------------------------------------- /doc/JA/faq_technical.md: -------------------------------------------------------------------------------- 1 | # 技術的なFAQ 2 | 3 | 本項はErg言語を使用する上での技術的な質問に答えるものです。すなわち、WhatやWhichで始まる質問、Yes/Noで答えられる質問を載せています。 4 | 5 | 根本的な文法の決定経緯については[こちら](./dev_guide/faq_syntax.md)を、なぜこの言語を作ったのか、この機能はどのように実装されているのかなど、より大きな話題は[こちら](./dev_guide/../faq_general.md)を参照してください。 6 | 7 | ## Ergに例外機構はないのですか? 8 | 9 | A: ありません。Ergでは代わりに`Result`型を使います。なぜErgに例外機構がないのかは[こちら](./dev_guide/faq_syntax.md#なぜergには例外機構がないのですか)を参照してください。 10 | 11 | ## ErgにはTypeScriptのAnyに相当する型はないのですか? 12 | 13 | A: ありません。すべてのオブジェクトは少なくとも`Object`クラスに属しますが、この型は最小限の属性を提供するのみの型で、Anyのように好き放題はできません。 14 | `Object`クラスは`match`などによる動的検査を通し目的の型に変換して使用します。Javaなどの`Object`と同じ類です。 15 | Ergの世界では、TypeScriptのようにAPIの定義を辿ったらAnyだったという絶望・混沌は生まれないのです。 16 | 17 | ## Never, {}, None, (), NotImplemented, Ellipsisは何が違うのですか? 18 | 19 | A: `Never`は「起こりえない」型です。実行時エラーを出すサブルーチンが、`Never`(または`Never`の合併型)を戻り値型とします。これを検知するとプログラムはすぐさま停止します。`Never`型は定義上すべての型のサブクラスでもありますが、`Never`型オブジェクトは決してErgコード上に出現しませんし、生成もされません。`{}`は`Never`と等価です。 20 | `Ellipsis`は省略を表すオブジェクトで、Python由来です。 21 | `NotImplemented`もPython由来です。これは未実装を表すマーカーとして使われますが、Ergではエラーを出す`todo`関数の方を推奨します。 22 | `None`は`NoneType`のインスタンスです。`Option`型でよく使われます。 23 | `()`はユニット型であり、そのインスタンス自身でもあります。これはプロシージャの戻り値など「意味のない値」を返したいとき使われます。 24 | 25 | ## なぜ`x = p!()`は有効なのに`f() = p!()`はEffectErrorとなるのですか? 26 | 27 | `!`は副作用の産物につけるマーカーではなく、副作用を起こしうるオブジェクトに付けるマーカーだからです。 28 | プロシージャ`p!`や可変型`T!`は副作用を起こす可能性がありますが、例えば`p!()`の戻り値が`Int`型だった場合、それ自体はもう副作用を起こしません。 29 | -------------------------------------------------------------------------------- /doc/JA/syntax/22_subroutine.md: -------------------------------------------------------------------------------- 1 | # Subroutine signatures 2 | 3 | ## Func 4 | 5 | ```erg 6 | some_func(x: T, y: U) -> V 7 | some_func: (T, U) -> V 8 | ``` 9 | 10 | ## Proc 11 | 12 | ```erg 13 | some_proc!(x: T, y: U) => V 14 | some_proc!: (T, U) => V 15 | ``` 16 | 17 | ## Func Method 18 | 19 | メソッド型は、外部からは`Self`で指定できない。 20 | 21 | ```erg 22 | .some_method(self, x: T, y: U) => () 23 | # Self.(T, U) => ()はselfの所有権を奪う 24 | .some_method: Ref(Self).(T, U) => () 25 | ``` 26 | 27 | ## Proc Method (dependent) 28 | 29 | 以下で、型`T!`は`N: Nat`という型引数を取るとする。外部から指定する場合は型変数を使用する。 30 | 31 | ```erg 32 | T!: Nat -> Type 33 | # ~>は適用前後の型引数の状態を示す(このときselfは可変参照でなくてはならない) 34 | T!(N).some_method!: (Ref! T!(N ~> N+X), X: Nat) => () 35 | ``` 36 | 37 | 注意として、`.some_method`の型は`|N, X: Nat| Ref!(T(N ~> N+X)).({X}) => ()`となる。 38 | `ref!`がついていない、すなわち適用後所有権が奪われるメソッドでは、型引数の遷移(`~>`)を使用できない。 39 | 40 | 所有権が奪われる場合は以下のようになる。 41 | 42 | ```erg 43 | # Nを使わないなら_で省略可 44 | # .some_method!: |N, X: Nat| T!(N).({X}) => T!(N+X) 45 | .some_method!|N, X: Nat|(self(N), X: Nat) => T!(N+X) 46 | ``` 47 | 48 | ## Operator 49 | 50 | ``で囲むことで通常の関数と同じように定義できる。 51 | `and`や`or`などの中置アルファベット演算子は囲むことで中置演算子として定義できる。 52 | 53 | ```erg 54 | and(x, y, z) = x and y and z 55 | `_+_`(x: Foo, y: Foo) = x.a + y.a 56 | `-_`(x: Foo) = Foo.new(-x.a) 57 | ``` 58 | 59 |

60 | Previous | Next 61 |

62 | -------------------------------------------------------------------------------- /doc/EN/syntax/type/08_value.md: -------------------------------------------------------------------------------- 1 | # Value Type 2 | 3 | Value types are Erg built-in types that can be evaluated at compile time, specifically: 4 | 5 | ``` erg 6 | Value = ( 7 | Int 8 | or Nat 9 | or Ratio 10 | or Float 11 | or Complex 12 | or Bool 13 | or Str 14 | or NoneType 15 | or Array Const 16 | or Tuple Const 17 | or Set Const 18 | or ConstFunc(Const, _) 19 | or ConstProc(Const, _) 20 | or ConstMethod(Const, _) 21 | ) 22 | ``` 23 | 24 | Value-type objects, constants, and compile-time subroutines applied to them are called __constant expressions__. 25 | 26 | ``` erg 27 | 1, 1.0, 1+2im, True, None, "aaa", [1, 2, 3], Fib(12) 28 | ``` 29 | 30 | Be careful with subroutines. Subroutines may or may not be value types. 31 | Since the substance of a subroutine is just a pointer, it can be treated as a value [1](#1), but when compiling something that is not a subroutine cannot be used in a constant context. is not a value type because it doesn't make much sense. 32 | 33 | Types classified as value types may be added in the future. 34 | 35 | --- 36 | 37 | 1 The term "value type" in Erg differs from the definition in other languages. There is no concept of memory within pure Erg semantics, and it is incorrect to state that it is a value type because it is placed on the stack, or that it is not a value type because it is actually a pointer. A value type only means that it is a `Value` type or its subtypes. [↩](#f1) 38 | -------------------------------------------------------------------------------- /doc/EN/syntax/32_integration_with_Python.md: -------------------------------------------------------------------------------- 1 | # Integration with Python 2 | 3 | All objects imported from Python are by default of type `Object`. Since no comparisons can be made at this point, it is necessary to refine the type. 4 | 5 | ## Type Specification in the Standard Library 6 | 7 | All APIs in the Python standard library are type specified by the Erg development team. 8 | 9 | ```erg 10 | time = pyimport "time" 11 | time.sleep! 1 12 | ``` 13 | 14 | ## Type Specification for User Scripts 15 | 16 | Create a `foo.d.er` file that types the Python `foo` module. 17 | Type hints on the Python side are ignored since they are not 100% guaranteed. 18 | 19 | ```python 20 | # foo.py 21 | X = ... 22 | def bar(x): 23 | ... 24 | def baz(): 25 | ... 26 | ... 27 | ``` 28 | 29 | ```erg 30 | # foo.d.er 31 | foo = pyimport "foo" 32 | .X = declare foo.'X', Int 33 | .bar = declare foo.'bar', Int -> Int 34 | .baz! = declare foo.'baz', () => Int 35 | ``` 36 | 37 | ```erg 38 | foo = pyimport "foo" 39 | assert foo.bar(1) in Int 40 | ``` 41 | 42 | This ensures type safety by performing type checking at runtime. The ``declare`` function works roughly as follows. 43 | 44 | ```erg 45 | declare|S: Subroutine| sub!: S, T = 46 | # Actually, => can be cast to a function without block side effects 47 | x => 48 | assert x in T.Input 49 | y = sub!(x) 50 | assert y in T.Output 51 | y 52 | ``` 53 | 54 | Since this is a runtime overhead, a project is planned to statically type analyze Python scripts with Erg's type system. 55 | 56 |

57 | Previous | Next 58 |

59 | -------------------------------------------------------------------------------- /doc/JA/syntax/12_dict.md: -------------------------------------------------------------------------------- 1 | # Dict 2 | 3 | Dictはキーと値のペアを持つコレクションです。 4 | 5 | ```erg 6 | ids = {"Alice": 145, "Bob": 214, "Charlie": 301} 7 | assert ids["Alice"] == 145 8 | ``` 9 | 10 | キーはHashであるならば文字列でなくても構いません。 11 | 12 | ```erg 13 | # rangeオブジェクトをキーにするのは非推奨(スライスと混同される) 14 | r = {1..3: "1~3", 4..6: "4~6", 7..9: "7~9"} 15 | assert r[1..3] == "1~3" 16 | l = {[]: "empty", [1]: "1"} 17 | assert l[[]] == "empty" 18 | ``` 19 | 20 | Dictに順番は関係ありません。また、重複する要素を持つことも出来ません。この点でDictは[Set](./14_set.md)と似ています。 21 | Dictは値付きのSetと言うこともできるでしょう。 22 | 23 | ```erg 24 | {"Alice": 145, "Bob": 214, "Charlie": 301} == {"Alice": 145, "Charlie": 301, "Bob": 214} 25 | ``` 26 | 27 | DictリテラルからDictを生成する場合、キーの重複がないかチェックされます。 28 | 重複がある場合コンパイルエラーとなります。 29 | 30 | ```erg 31 | {"Alice": 145, "Alice": 1} # KeyError: Duplicate key "Alice" 32 | ``` 33 | 34 | 空のDictは`{:}`で生成します。`{}`は空の配列を表すことに注意してください。 35 | 36 | ```erg 37 | mut_dict = !{:} 38 | mut_dict.insert! "Alice", 145 39 | mut_dict.insert! "Bob", 214 40 | assert mut_dict["Alice"] == 145 41 | ``` 42 | 43 | ## Heterogeneous Dict 44 | 45 | キー・値の型は単一でなくてもよく、そのような辞書を __非等質な辞書(heterogenous dict)__ といいます。 46 | 47 | ```erg 48 | d: {Str: Int, Int: Str} = {”a”: 1, 1: “a”} 49 | assert d[”a”] == 1 50 | assert d[1] == “a” 51 | ``` 52 | 53 | しかし、違う型のキーに同じ型の値、または同じ型のキーに違う型の値をあてることはできません。 54 | このような場合は代わりにOr型(Union)を使います。 55 | 56 | ```erg 57 | invalid1 = {1: “a”, “a”: “b”} 58 | invalid2 = {1: “a”, 2: 2} 59 | 60 | # Ergの型推論はOr型を推論しないので、型指定が必要 61 | valid1: {Int or Str: Str} = {1: “a”, “a”: “b”} 62 | valid2: {Int: Int or Str} = {1: “a”, 2: 2} 63 | ``` 64 | 65 |

66 | Previous | Next 67 |

68 | -------------------------------------------------------------------------------- /doc/JA/syntax/type/16_subtyping.md: -------------------------------------------------------------------------------- 1 | # 部分型付け 2 | 3 | Ergでは、クラス同士の包含関係は比較演算子`<`, `>`で判定可能です。 4 | 5 | ```erg 6 | Nat < Int 7 | Int < Object 8 | 1.._ < Nat 9 | {1, 2} > {1} 10 | {=} > {x = Int} 11 | {I: Int | I >= 1} < {I: Int | I >= 0} 12 | ``` 13 | 14 | `<:`演算子とは別の意味を持つことに注意してください。左辺のクラスが右辺の型のサブタイプであると宣言するもので、コンパイル時にのみ意味を持ちます。 15 | 16 | ```erg 17 | C <: T # T: StructuralType 18 | f|D <: E| ... 19 | 20 | assert F < G 21 | ``` 22 | 23 | また、多相型の部分型指定について、例えば`Self(R, O) <: Add(R, O)`などの場合、`Self <: Add`と指定することもできます。 24 | 25 | ## 構造型、クラスの型関係 26 | 27 | 構造型は構造的型付けを実現するための型であり、構造が同じならば同じオブジェクトとみなされます。 28 | 29 | ```erg 30 | T = Structural {i = Int} 31 | U = Structural {i = Int} 32 | 33 | assert T == U 34 | t: T = {i = 1} 35 | assert t in T 36 | assert t in U 37 | ``` 38 | 39 | 対してクラスは記名的型付けを実現するための型であり、型およびインスタンスを構造的に比較することができません。 40 | 41 | ```erg 42 | C = Class {i = Int} 43 | D = Class {i = Int} 44 | 45 | assert C == D # TypeError: cannot compare classes 46 | c = C.new {i = 1} 47 | assert c in C 48 | assert not c in D 49 | ``` 50 | 51 | ## サブルーチンの部分型付け 52 | 53 | サブルーチンの引数、戻り値は、単一のクラスのみを取る。 54 | すなわち、構造型やトレイトを関数の型として直接指定することはできない。 55 | 部分型指定を使って「その型のサブタイプである単一のクラス」として指定する必要がある。 56 | 57 | ```erg 58 | # OK 59 | f1 x, y: Int = x + y 60 | # NG 61 | f2 x, y: Add = x + y 62 | # OK 63 | # Aは何らかの具体的なクラス 64 | f3 x, y: A = x + y 65 | ``` 66 | 67 | サブルーチンの型推論もこのルールに従っている。サブルーチン中の変数で型が明示されていないものがあったとき、コンパイラはまずその変数がいずれかのクラスのインスタンスでないかチェックし、そうでない場合はスコープ中のトレイトの中から適合するものを探す。それでも見つからない場合、コンパイルエラーとなる。このエラーは構造型を使用することで解消できるが、無名型を推論するのはプログラマの意図しない結果である可能性があるため、プログラマが明示的に`Structural`で指定する設計となっている。 68 | 69 | ## クラスのアップキャスト 70 | 71 | ```erg 72 | i: Int 73 | i as (Int or Str) 74 | i as (1..10) 75 | i as {I: Int | I >= 0} 76 | ``` 77 | -------------------------------------------------------------------------------- /doc/JA/syntax/type/advanced/phantom.md: -------------------------------------------------------------------------------- 1 | # 幽霊型(Phantom class) 2 | 3 | 幽霊型は、コンパイラに注釈を与えるためだけに存在するマーカートレイトである。 4 | 幽霊型の使い方として、リストの構成をみる。 5 | 6 | ```erg 7 | Nil = Class() 8 | List T, 0 = Inherit Nil 9 | List T, N: Nat = Class {head = T; rest = List(T, N-1)} 10 | ``` 11 | 12 | このコードはエラーとなる。 13 | 14 | ```erg 15 | 3 | List T, 0 = Inherit Nil 16 | ^^^ 17 | TypeConstructionError: since Nil does not have a parameter T, it is not possible to construct List(T, 0) with Nil 18 | hint: use 'Phantom' trait to consume T 19 | ``` 20 | 21 | このエラーはつまり、`List(_, 0).new Nil.new()`とされたときに`T`の型推論ができないという文句である。Ergでは型引数を未使用のままにすることができないのである。 22 | このような場合は何でもよいので`T`型を右辺で消費する必要がある。サイズが0の型、例えば長さ0のタプルならば実行時のオーバーヘッドもなく都合がよい。 23 | 24 | ```erg 25 | Nil T = Class((T; 0)) 26 | List T, 0 = Inherit Nil T 27 | List T, N: Nat = Class {head = T; rest = List(T, N-1)} 28 | ``` 29 | 30 | このコードはコンパイルを通る。だが少しトリッキーで意図が分かりづらい上に、型引数が型のとき以外では使えない。 31 | 32 | このようなときにちょうどよいのが幽霊型である。幽霊型はサイズ0の型を一般化した型である。 33 | 34 | ```erg 35 | Nil T = Class(Impl: Phantom T) 36 | List T, 0 = Inherit Nil T 37 | List T, N: Nat = Class {head = T; rest = List(T, N-1)} 38 | 39 | nil = Nil(Int).new() 40 | assert nil.__size__ == 0 41 | ``` 42 | 43 | `Phantom`が`T`型を保持する。しかし実際には`Phantom T`型のサイズは0であり、`T`型のオブジェクトを保持してはいない。 44 | 45 | また、`Phantom`は型以外にも任意の型引数を消費することができる。以下の例では`State`という`Str`のサブタイプオブジェクトである型引数を`Phantom`が保持している。 46 | この場合も、`state`はオブジェクトの実体に現れないハリボテの型変数である。 47 | 48 | ```erg 49 | VM! State: {"stopped", "running"}! = Class(..., Impl: Phantom! State) 50 | VM!("stopped"). 51 | start ref! self("stopped" ~> "running") = 52 | self.do_something!() 53 | self::set_phantom!("running") 54 | ``` 55 | 56 | `state`は`update_phantom!`メソッドか`set_phantom!`メソッドを介して更新する。 57 | これは`Phantom!`(`Phantom`の可変版)の標準パッチが提供するメソッドで、使い方は可変型の`update!`, `set!`と同じである。 58 | -------------------------------------------------------------------------------- /doc/JA/syntax/type/advanced/recursive_type_inferring.md: -------------------------------------------------------------------------------- 1 | # 再帰型の型推論 2 | 3 | 再帰型の型推論では、任意回の呼び出しで生成されるオブジェクトの集合を計算することとなる。 4 | これは実質的には無限回の操作で生成される空間と同義である。 5 | `fn T`をサブルーチン`fn`に対する`T`型オブジェクトの適用による戻り値型とするとき、関数呼び出しをn回行って導出される型をfn^n Tと表す。つまり、fn(fn(...(fn(T)))) == fn^n Tである。 6 | 複数引数の場合、前の呼び出しの結果が第1引数となる場合、つまりfn(fn(fn(fn(x, y_1)..., y_n-2) y_n-1) y_n)はfn^n X Y^nと表す。 7 | 同様に、前の呼び出しの結果が第2引数となる場合、つまりfn(x_1 fn(x_2 ...fn(x_n y)))はfn^n X^n Yまたは(fn X)^n Yと表す。 8 | 例としては階乗関数`fact n: Nat = n * fact n-1`がある。`fact: 1.. * fact (1.. - {1}) == (1.. *)^n {1}`である。 9 | 10 | 再帰型ではいくらでも呼び出しうるため、関数の戻り値に使われている関数fnの無眼回適用で生成されるfn^∞ Tが戻り値型である。 11 | 現在実装されている推論規則は以下の通り。 12 | 13 | 指定のない限り、x, y, z: Nat 14 | 15 | * id^∞ t == {t} 16 | * ({0} +)^∞ x..y == x..y 17 | * ({0} -)^∞ x..y = -y..-x 18 | * ({1} *)^∞ x..y == x..y 19 | * ({z} +)^∞ x..y == Nat 20 | * ({z} -)^∞ x..y = Int 21 | * ({""} +)^∞ {s} == {s} 22 | * ({s = Str len = 1..} +)^∞ {\_ = Str} == Str 23 | 24 | ## 非依存化 25 | 26 | Independizationは依存型を一般の型に戻す操作である。例として、{1} -> Natなどがある。 27 | 普通のダウンキャストの場合は、{1} -> {0, 1} -> {0, 1, 2}などとなる場合がある。これはその名前空間で定義のある依存型による。 28 | 依存型は無限にあるため、定義のあるものにしかダウンキャストしないのである。 29 | しかしIndependizationは一意的である。 30 | 非依存化は依存型の推論が失敗した場合に行われる。 31 | {1, True}など、別々のクラスに属するオブジェクト同士の非依存化は失敗(コンパイルエラー)する。 32 | {-1, 0, 1}など同一のクラスであれば成功する。その際、クラスは可能な限り子クラスになる(この場合はInt)。 33 | 型変数を含んだ型、例えば{True} or '0は、型変数を含まない方が非依存化されたあと消去される(この場合はBool)。 34 | もともとErgのランタイムにはクラスしか存在しないので、この操作は型消去の一種であり、情報は失われるが健全性が壊れることはない(TODO:証明を与える)。 35 | 36 | ## 依存推論のテスト 37 | 38 | ```erg 39 | func 0, 0, _ = True 40 | func 0, _, _ = False 41 | func(i, x, a) = 42 | # a[i-1] を選ばない場合 (func(i-1, x, a) が OK なら OK) 43 | if func(i-1, x, a): 44 | return True 45 | # a[i-1] を選ぶ場合 (func(i-1, x-a[i-1], a) が OK なら OK) 46 | if func(i-1, x-a[i-1], a): 47 | return True 48 | 49 | False 50 | ``` 51 | -------------------------------------------------------------------------------- /compiler/erg_common/lazy_buffer.rs: -------------------------------------------------------------------------------- 1 | // Copied and modified from https://github.com/rust-itertools/itertools/blob/master/src/lazy_buffer.rs 2 | // MIT license | Apache 2.0 license 3 | // License files are placed at the root. 4 | 5 | use std::ops::Index; 6 | 7 | #[derive(Debug, Clone)] 8 | pub struct LazyBuffer { 9 | pub it: I, 10 | done: bool, 11 | buffer: Vec, 12 | } 13 | 14 | impl LazyBuffer 15 | where 16 | I: Iterator, 17 | { 18 | pub fn new(it: I) -> LazyBuffer { 19 | LazyBuffer { 20 | it, 21 | done: false, 22 | buffer: Vec::new(), 23 | } 24 | } 25 | 26 | pub fn len(&self) -> usize { 27 | self.buffer.len() 28 | } 29 | 30 | pub fn get_next(&mut self) -> bool { 31 | if self.done { 32 | return false; 33 | } 34 | let next_item = self.it.next(); 35 | match next_item { 36 | Some(x) => { 37 | self.buffer.push(x); 38 | true 39 | } 40 | None => { 41 | self.done = true; 42 | false 43 | } 44 | } 45 | } 46 | 47 | pub fn prefill(&mut self, len: usize) { 48 | let buffer_len = self.buffer.len(); 49 | 50 | if !self.done && len > buffer_len { 51 | let delta = len - buffer_len; 52 | 53 | self.buffer.extend(self.it.by_ref().take(delta)); 54 | self.done = self.buffer.len() < len; 55 | } 56 | } 57 | } 58 | 59 | impl Index for LazyBuffer 60 | where 61 | I: Iterator, 62 | I::Item: Sized, 63 | Vec: Index, 64 | { 65 | type Output = as Index>::Output; 66 | 67 | fn index(&self, _index: J) -> &Self::Output { 68 | self.buffer.index(_index) 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /doc/EN/syntax/22_subroutine.md: -------------------------------------------------------------------------------- 1 | # Subroutine Signatures 2 | 3 | ## Func 4 | 5 | ```erg 6 | some_func(x: T, y: U) -> V 7 | some_func: (T, U) -> V 8 | ``` 9 | 10 | ## Proc 11 | 12 | ```erg 13 | some_proc!(x: T, y: U) => V 14 | some_proc!: (T, U) => V 15 | ``` 16 | 17 | ## Func Method 18 | 19 | The method type cannot be specified externally with ``Self``. 20 | 21 | ```erg 22 | .some_method(self, x: T, y: U) => () 23 | # Self.(T, U) => () takes ownership of self 24 | .some_method: Ref(Self). (T, U) => () 25 | ``` 26 | 27 | ## Proc Method (dependent) 28 | 29 | In the following, assume that the type `T!` takes the type argument `N: Nat`. To specify it externally, use a type variable. 30 | 31 | ```erg 32 | T!: Nat -> Type 33 | # ~> indicates the state of the type argument before and after application (in this case, self must be a variable reference) 34 | T!(N).some_method!: (Ref! T!(N ~> N+X), X: Nat) => () 35 | ``` 36 | 37 | As a note, the type of `.some_method` is `Ref!(T(N ~> N+X)). ({X}) => () | N, X: Nat`. 38 | For methods that do not have `ref!`, i.e., are deprived of ownership after application, the type argument transition (`~>`) cannot be used. 39 | 40 | If ownership is taken, it is as follows. 41 | 42 | ```erg 43 | # If you don't use N, you can omit it with _. 44 | # .some_method!: |N, X: Nat| T!(N).({X}) => T!(N+X) 45 | .some_method!|N, X: Nat|(self(N), X: Nat) => T!(N+X) 46 | ``` 47 | 48 | ## Operator 49 | 50 | It can be defined as a normal function by enclosing it with ``. 51 | 52 | Neuter alphabetic operators such as `and` and `or` can be defined as neuter operators by enclosing them with ``. 53 | 54 | ```erg 55 | and(x, y, z) = x and y and z 56 | `_+_`(x: Foo, y: Foo) = x.a + y.a 57 | `-_`(x: Foo) = Foo.new(-x.a) 58 | ``` 59 | 60 | 63 | -------------------------------------------------------------------------------- /doc/JA/syntax/27_comprehension.md: -------------------------------------------------------------------------------- 1 | # Comprehension(内包表記) 2 | 3 | `[expr | (name <- iterable)+ (predicate)*]`で配列、 4 | `{expr | (name <- iterable)+ (predicate)*}`でセット、 5 | `{key: value | (name <- iterable)+ (predicate)*}`でDictが作れる。 6 | 7 | `|`で区切られた節のうち最初の部分をレイアウト節(配置節)といい、2番目の部分をバインド節(束縛節)、3番目の部分をガード節(条件節)という。 8 | ガード節は省略可能であるがバインド節は省略できず、バインド節より先にガード節を置くことはできない。 9 | 10 | e.g. 11 | 12 | ```erg 13 | assert [i | i <- [0, 1, 2]] == [0, 1, 2] 14 | assert [i / 2 | i <- 0..2] == [0.0, 0.5, 1.0] 15 | assert [(i, j) | i <- 0..2; j <- 0..2; (i + j) % 2 == 0] == [(0, 0), (0, 2), (1, 1), (2, 0), (2, 2)] 16 | assert {i % 2 | i <- 0..9} == {0, 1} 17 | assert {k: v | k <- ["a", "b"]; v <- [1, 2]} == {"a": 1, "b": 2} 18 | ``` 19 | 20 | Ergの内包表記はHaskellに影響を受けているが、若干の違いがある。 21 | Haskellのリスト内包表記の場合、変数の順番は結果に違いをもたらすが、Ergでは関係がない。 22 | 23 | ```haskell 24 | -- Haskell 25 | [(i, j) | i <- [1..3], j <- [3..5]] == [(1,3),(1,4),(1,5),(2,3),(2,4),(2,5),(3,3),(3,4),(3,5)] 26 | [(i, j) | j <- [3..5], i <- [1..3]] == [(1,3),(2,3),(3,3),(1,4),(2,4),(3,4),(1,5),(2,5),(3,5)] 27 | ``` 28 | 29 | ```erg 30 | # Erg 31 | assert [(i, j) | i <- 1..<3; j <- 3..<5] == [(i, j) | j <- 3..<5; i <- 1..<3] 32 | ``` 33 | 34 | これはPythonと同じである。 35 | 36 | ```python 37 | # Python 38 | assert [(i, j) for i in range(1, 3) for j in range(3, 5)] == [(i, j) for j in range(3, 5) for i in range(1, 3)] 39 | ``` 40 | 41 | ## 篩型 42 | 43 | 内包表記と似たものに、篩型がある。篩型は`{Name: Type | Predicate}`という形式で作られる型(列挙型)である。 44 | 篩型の場合、Nameは1つまででレイアウトは指定できず(ただしタプル型などにすれば複数の値は扱える)、Predicateはコンパイル時計算できるもの、つまり定数式でなくてはならない。 45 | 46 | ```erg 47 | Nat = {I: Int | I >= 0} 48 | # 述語式がandだけの場合、;で代替できる 49 | # Nat2D = {(I, J): (Int, Int) | I >= 0; J >= 0} 50 | Nat2D = {(I, J): (Int, Int) | I >= 0 and J >= 0} 51 | ``` 52 | 53 |

54 | Previous | Next 55 |

56 | -------------------------------------------------------------------------------- /doc/JA/syntax/type/11_enum.md: -------------------------------------------------------------------------------- 1 | # Enumerative Type(列挙型) 2 | 3 | 列挙型(Enum type)はSetによって生成されます。 4 | 列挙型はそのままでも型指定で使えるが、クラス化したりパッチを定義したりしてメソッド定義もできます。 5 | 列挙型による部分型システムを列挙的部分型付けといいます。 6 | 7 | ```erg 8 | Bool = {True, False} 9 | Status = {"ok", "error"} 10 | ``` 11 | 12 | `1..12`は`{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}`と書き換えられるので、要素が有限の場合は本質的に列挙型と区間型は等価です。 13 | 14 | ```erg 15 | Binary! = Class {0, 1}!. 16 | invert! ref! self = 17 | if! self == 0: 18 | do! 19 | self.set! 1 20 | do! 21 | self.set! 0 22 | 23 | b = Binary!.new !0 24 | b.invert!() 25 | ``` 26 | 27 | 因みに、Ergの列挙型は他言語でよくある列挙型を包摂する概念です。 28 | 29 | ```rust 30 | // Rust 31 | enum Status { Ok, Error } 32 | ``` 33 | 34 | ```erg 35 | # Erg 36 | Status = {"Ok", "Error"} 37 | ``` 38 | 39 | Rustとの相違点は、構造的部分型を採用しているというところにあります。 40 | 41 | ```rust 42 | // StatusとExtraStatusの間にはなんの関係もない 43 | enum Status { Ok, Error } 44 | enum ExtraStatus { Ok, Error, Unknown } 45 | 46 | // メソッドを実装可能 47 | impl Status { 48 | // ... 49 | } 50 | impl ExtraStatus { 51 | // ... 52 | } 53 | ``` 54 | 55 | ```erg 56 | # Status > ExtraStatusであり、Statusの要素はExtraStatusのメソッドを使える 57 | Status = Trait {"Ok", "Error"} 58 | # ... 59 | ExtraStatus = Trait {"Ok", "Error", "Unknown"} 60 | # ... 61 | ``` 62 | 63 | patchingによってメソッドの追加もできます。 64 | 65 | 明示的に包含関係を示したい場合、または既存のEnum型に選択肢を追加したい場合は`or`演算子を使います。 66 | 67 | ```erg 68 | ExtraStatus = Status or {"Unknown"} 69 | ``` 70 | 71 | 要素の属するクラスがすべて同一である列挙型を等質(homogenous)な列挙型といいます。 72 | デフォルトでは、等質な列挙型を要件型とするクラスは、要素が属しているクラスのサブクラスとして扱えます。 73 | あえてそうしたくない場合は、ラッパークラスとするとよいでしょう。 74 | 75 | ```erg 76 | Abc = Class {"A", "B", "C"} 77 | Abc.new("A").is_uppercase() 78 | 79 | OpaqueAbc = Class {inner = {"A", "B", "C"}}. 80 | new inner: {"A", "B", "C"} = Self.new {inner;} 81 | OpaqueAbc.new("A").is_uppercase() # TypeError 82 | ``` 83 | -------------------------------------------------------------------------------- /doc/JA/compiler/transpile.md: -------------------------------------------------------------------------------- 1 | # ErgコードはPythonコードにどのようにトランスパイルされるか? 2 | 3 | 正確には、ErgコードはPythonバイトコードにトランスパイルされます。 4 | しかしPythonバイトコードはほぼPythonコードに復元できるので、ここでは等価なPythonコードを例として上げています。 5 | ちなみに、ここで紹介する例は最適化レベルの低いものです。 6 | さらに高度な最適化が施されると、実体を生成する必要のないものは消去されます。 7 | 8 | ## Record, Record type 9 | 10 | namedtupleにトランスパイルされます。 11 | namedtupleについては、[こちら](https://docs.python.jp/3/library/collections.html#collections.namedtuple)を参照してください。 12 | 似たような機能にdataclassがありますが、dataclassは`__eq__`や`__hash__`が自動実装されるなどの影響で少しパフォーマンスが落ちます。 13 | 14 | ```erg 15 | Employee = Class {.name = Str; .id = Int} 16 | 17 | employee = Employee.new({.name = "John Smith"; .id = 100}) 18 | 19 | assert employee.name == "John Smith" 20 | ``` 21 | 22 | ```python 23 | from typing import NamedTuple 24 | 25 | class Employee(NamedTuple): 26 | __records__ = ['name', 'id'] 27 | name: str 28 | id: int 29 | 30 | employee = Employee('John Smith', 100) 31 | 32 | assert employee.name == 'John Smith' 33 | ``` 34 | 35 | また、更に最適化できる場合は単なるタプルに変換されます。 36 | 37 | ## Polymorphic Type 38 | 39 | ## Instant Scope 40 | 41 | 名前空間内での衝突が起きない場合は、単にマングリングして展開されます。 42 | `x::y`などの名前はバイトコードで使用されるものでPythonコードと対応させる事はできませんが、無理やり表現すると以下のようになります。 43 | 44 | ```erg 45 | x = 46 | y = 1 47 | y + 1 48 | ``` 49 | 50 | ```python 51 | x::y = 1 52 | x = x::y + 1 53 | ``` 54 | 55 | 衝突する場合は、内部的にしか参照できない関数を定義して使用します。 56 | 57 | ```erg 58 | x = 59 | y = 1 60 | y + 1 61 | ``` 62 | 63 | ```python 64 | def _(): 65 | x = 1 66 | y = x 67 | return y + 1 68 | x = _() 69 | ``` 70 | 71 | ## Overloading 72 | 73 | マングリングを使用しています。 74 | 75 | ## Visibility 76 | 77 | 公開変数に関してはPythonのデフォルトなので何もしません。 78 | 非公開変数はマングリングで対処しています。 79 | 80 | ```erg 81 | x = 1 82 | y = 83 | x = 2 84 | assert module::x == 2 85 | ``` 86 | 87 | ```python 88 | module::x = 1 89 | y::x = 2 90 | assert module::x == 2 91 | y = None 92 | ``` 93 | -------------------------------------------------------------------------------- /library/std/prelude.er: -------------------------------------------------------------------------------- 1 | @Attach NeImpl 2 | Eq(R |= Self()) = Trait { 3 | .`==` = Self(R).(R) -> Bool 4 | } 5 | 6 | NeImpl R = Patch Eq R 7 | NeImpl(R).`!=`(self, other: R): Bool = not(self == other) 8 | 9 | # Should this return `Ordering`? 10 | @Attach EqImpl, GeImpl, GtImpl, LtImpl 11 | Ord(R |= Self()) = Trait { 12 | .`<=` = Self(R).(R) -> Bool 13 | } 14 | 15 | EqImpl R = Patch Ord(R), Impl: Eq() 16 | EqImpl(R).`==`(self, other: R): Bool = self <= other and other <= self 17 | 18 | GeImpl = Patch Ord() 19 | GeImpl.`>=`(self, other: Self): Bool = other <= self 20 | GtImpl = Patch Ord() 21 | GtImpl.`>`(self, other: Self): Bool = other < self 22 | LtImpl = Patch Ord() 23 | LtImpl.`<`(self, other: Self): Bool = self <= other and self != other 24 | 25 | Add(R |= Self(), O |= Self()) = Trait { 26 | .`_+_` = Self(R, O).(R) -> O 27 | } 28 | Sub(R |= Self(), O |= Self()) = Trait { 29 | .`_-_` = Self(R, O).(R) -> O 30 | } 31 | Mul(R |= Self(), O |= Self()) = Trait { 32 | .`*` = Self(R, O).(R) -> O 33 | } 34 | Div(R |= Self(), O |= Self()) = Trait { 35 | .`/` = Self(R, O).(R) -> O or Panic 36 | } 37 | Num: (R |= Type, O |= Type) -> Type 38 | Num = Add and Sub and Mul 39 | 40 | Seq T = Trait { 41 | .__len__ = Ref(Self(T)).() -> Nat 42 | .get = Ref(Self(T)).(Nat) -> T 43 | } 44 | 45 | `_+_`: |R, O: Type, A <: Add(R, O)| (A, R) -> O 46 | `_-_`: |R, O: Type, S <: Add(R, O)| (S, R) -> O 47 | `*`: |R, O: Type, M <: Add(R, O)| (M, R) -> O 48 | `/`: |R, O: Type, D <: Add(R, O)| (D, R) -> O 49 | 50 | AddForInt = Patch Int, Impl: Add() 51 | AddForInt.`_+_`: (self: Self, other: Int) -> Int 52 | 53 | # TODO: Mul and Div 54 | NumForInterval M, N, O, P: Int = 55 | Patch M..N, Impl: Add(R: O..P, O: M+O..N+P) and Sub(R: O..P, O: M-P..N-O) 56 | NumForInterval(M, N, O, P).`_+_`: (self: Self, other: O..P) -> M+O..N+P 57 | NumForInterval(M, N, O, P).`_-_`: (self: Self, other: O..P) -> M-P..N-O 58 | -------------------------------------------------------------------------------- /doc/JA/syntax/23_closure.md: -------------------------------------------------------------------------------- 1 | # クロージャ 2 | 3 | Ergのサブルーチンには、外部変数を捕捉する「クロージャ」という機能がある。 4 | 5 | ```erg 6 | outer = 1 7 | f x = outer + x 8 | assert f(1) == 2 9 | ``` 10 | 11 | 不変オブジェクトと同じく、可変オブジェクトも捕捉できる。 12 | 13 | ```erg 14 | sum = !0 15 | for! 1..10, i => 16 | sum.add! i 17 | assert sum == 45 18 | 19 | p! x = 20 | sum.add! x 21 | p!(1) 22 | assert sum == 46 23 | ``` 24 | 25 | しかし、関数は可変オブジェクトを捕捉できないので注意が必要である。 26 | 仮に可変オブジェクトが関数内で参照できると、以下のようなコードが書けてしまう。 27 | 28 | ```erg 29 | # !!! このコードは実際にはエラーになる !!! 30 | i = !0 31 | f x = i + x 32 | assert f 1 == 1 33 | i.add! 1 34 | assert f 1 == 2 35 | ``` 36 | 37 | 関数は同じ引数に対して同じ値を返すべきだが、その前提が破れてしまっている。 38 | `i`は呼び出し時に初めて評価されることに注意してほしい。 39 | 40 | 関数定義時点での可変オブジェクトの内容がほしい場合は`.clone`する。 41 | 42 | ```erg 43 | i = !0 44 | immut_i = i.clone().freeze() 45 | f x = immut_i + x 46 | assert f 1 == 1 47 | i.add! 1 48 | assert f 1 == 1 49 | ``` 50 | 51 | ## 可変状態の回避、関数型プログラミング 52 | 53 | ```erg 54 | # Erg 55 | sum = !0 56 | for! 1..10, i => 57 | sum.add! i 58 | assert sum == 45 59 | ``` 60 | 61 | 上と同等のプログラムは、Pythonでは以下のように記述できる。 62 | 63 | ```python 64 | # Python 65 | sum = 0 66 | for i in range(1, 10): 67 | sum += i 68 | assert sum == 45 69 | ``` 70 | 71 | しかしErgではもっとシンプルな書き方を推奨する。 72 | サブルーチンと可変オブジェクトを使って状態を持ち回す代わりに、関数を使用する状態を局所化するスタイルである。これは関数型プログラミングと呼ばれる。 73 | 74 | ```erg 75 | # Functional style 76 | sum = (1..10).sum() 77 | assert sum == 45 78 | ``` 79 | 80 | 上のコードは先程と全く同じ結果となるが、こちらのほうが遥かにシンプルであることが見て取れる。 81 | 82 | `fold`関数を使用すれば、合計以外にも多様な操作を行うことができる。 83 | `fold`はイテレータのメソッドで、各イテレーションごとに引数`f`を実行する。 84 | 結果を蓄積するカウンタの初期値は`init`で指定し、`acc`に蓄積されていく。 85 | 86 | ```erg 87 | # start with 0, result will 88 | sum = (1..10).fold(init: 0, f: (acc, i) -> acc + i) 89 | assert sum == 45 90 | ``` 91 | 92 | Ergは不変オブジェクトによるプログラミングで自然と簡潔な記述となるように設計されている。 93 | 94 |

95 | Previous | Next 96 |

97 | -------------------------------------------------------------------------------- /doc/JA/syntax/type/14_dependent.md: -------------------------------------------------------------------------------- 1 | # 依存型 2 | 3 | 依存型はErgの最大の特徴とも言っても良い機能です。 4 | 依存型とは、値を引数に取る型です。通常の多相型は型のみを引数に取れますが、その制限を緩めたのが依存型といえます。 5 | 6 | 依存型は、`[T; N]`(`Array(T, N)`)などがそれに相当します。 7 | この型は、中身の型`T`だけでなく、中身の個数`N`にも依存して決まる型です。`N`には`Nat`型のオブジェクトが入ります。 8 | 9 | ```erg 10 | a1 = [1, 2, 3] 11 | assert a1 in [Nat; 3] 12 | a2 = [4, 5, 6, 7] 13 | assert a1 in [Nat; 4] 14 | assert a1 + a2 in [Nat; 7] 15 | ``` 16 | 17 | 関数引数で渡した型オブジェクトが戻り値型に関連する場合は、以下のように記述します。 18 | 19 | ```erg 20 | narray: |N: Nat| {N} -> [{N}; N] 21 | narray(N: Nat): [N; N] = [N; N] 22 | assert narray(3) == [3, 3, 3] 23 | ``` 24 | 25 | 依存型を定義する際は、型引数が全て定数でなくてはなりません。 26 | 27 | 依存型そのものは既存の言語にも存在するものですが、Ergでは依存型にプロシージャルメソッドを定義できるという特徴があります。 28 | 29 | ```erg 30 | x = 1 31 | f x = 32 | print! f::x, module::x 33 | 34 | # Phantom型は型引数と同じ値になるPhantomという属性を持っている 35 | T X: Int = Class Impl: Phantom X 36 | T(X). 37 | x self = self::Phantom 38 | 39 | T(1).x() # 1 40 | ``` 41 | 42 | 可変依存型の型引数はメソッドの適用によって遷移させることができます。 43 | 遷移指定は`~>`で行います。 44 | 45 | ```erg 46 | # `Id`は不変型なので遷移させることはできないことに注意 47 | VM!(State: {"stopped", "running"}! |= _, Id: Nat |= _) = Class(..., Impl: Phantom! State) 48 | VM!(). 49 | # 変わらない変数は`_`を渡せば省略可能, デフォルト引数にしておけば書く必要すらない 50 | start! ref! self("stopped" ~> "running") = 51 | self.initialize_something!() 52 | self::set_phantom!("running") 53 | 54 | # 型引数ごとに切り出すこともできる(定義されたモジュール内でのみ) 55 | VM!.new() = VM!(!"stopped", 1).new() 56 | VM!("running" ~> "running").stop! ref! self = 57 | self.close_something!() 58 | self::set_phantom!("stopped") 59 | 60 | vm = VM!.new() 61 | vm.start!() 62 | vm.stop!() 63 | vm.stop!() # TypeError: VM!(!"stopped", 1) doesn't have .stop!() 64 | # hint: VM!(!"running", 1) has .stop!() 65 | ``` 66 | 67 | 既存の型を組み込んだり継承して依存型を作ることもできます。 68 | 69 | ```erg 70 | MyArray(T, N) = Inherit [T; N] 71 | 72 | # .arrayと連動してself: Self(T, N)の型が変わる 73 | MyStruct!(T, N: Nat!) = Class {.array: [T; !N]} 74 | ``` 75 | -------------------------------------------------------------------------------- /doc/JA/faq_general.md: -------------------------------------------------------------------------------- 1 | # Erg FAQ 2 | 3 | このFAQは一般のErg入門者向けです。 4 | 個別の(よくある)技術的な問題については[こちら](./faq_technical.md)を、文法の決定経緯(なぜこのような文法になったのか)などについては 5 | [こちら](./dev_guide/why.md)を参照してください。 6 | 7 | ## ErgはPython互換言語というのはどういう意味なのですか? 8 | 9 | ~~A: Ergの実行系であるEVM(Erg VirtualMachine)はPythonバイトコードを拡張したErgバイトコードを実行します。これは静的型付けシステムなどをPythonバイトコードに導入したものです(引数を取らない命令に引数を導入したり、空き番号に独自命令を実装しています)。これにより、ErgはPythonのコードをシームレスに呼び出し、かつ高速な実行を実現しています。~~ 10 | 11 | A: ErgスクリプトはPythonのバイトコードにトランスパイルされます。つまり、Pythonと同じインタープリタ上で動作します。もともとはPythonインタープリタ(CPython)を拡張した上位互換処理系を開発し、コンパイラと合わせて「Erg」とする予定でしたが、処理系の開発がコンパイラに対して大きく遅れたため、コンパイラのみ先行公開する運びとしました。現在処理系は鋭意開発中です。 12 | 13 | ## Ergはどの言語から影響を受けましたか? 14 | 15 | 両手でも数え切れないほどの言語から影響を受けていますが、中でも特に強く影響を受けているのはPython/Rust/Nim/Haskellです。 16 | Pythonからはオフサイドルールと互換言語として多くの意味論、Rustからは式指向とトレイト、Nimからはプロシージャ、Haskellからは関数型プログラミング関連の機能を受け継いでいます。 17 | 18 | ## Pythonを呼び出せる言語はJuliaなどがあります。なぜErgを作ったのですか? 19 | 20 | A: Ergの設計動機の1つに、手軽に使えてなおかつ強力な型システムを持った言語がほしいというものがありました。すなわち、型推論、カインド、依存型などを持った言語です。 21 | Juliaは型付けができますが、実際のところは動的型付け言語であり、静的型付け言語のコンパイル時エラー検出というメリットを享受できません。 22 | 23 | ## Ergは関数型プログラミングやオブジェクト指向プログラミングなど複数のスタイルをサポートしています。これは、Pythonの”There should be one-- and preferably only one --obvious way to do it.”に反しているのではないですか? 24 | 25 | A: Ergでは、その言葉はもう少し狭い意味で捉えられます。例えば、一般にErgのAPIにエイリアスはありません。Ergはこの意味では"only one way"です。 26 | 関数型やOOPなどのもう少し大きな意味・枠組みでは、1つのやり方しかないというのは必ずしも利便性をもたらすとは限りません。 27 | 例えば、JavaScriptにはイミュータブルなプログラム作成を支援するライブラリが複数あり、C言語ではガベージコレクションのライブラリが複数あります。 28 | しかし、このような基本的な機能にまでライブラリが複数あると、選定に時間を取られるだけでなく、別々のライブラリを使うコード同士の統合に著しい困難が生じます。 29 | 純粋関数型言語であるHaskellでさえ、オブジェクト指向をサポートするライブラリが存在します。 30 | プログラマは、なければ自前で作ってしまうものなのです。それならば、標準で提供してしまったほうがよいと考えます。 31 | これは、Pythonの"Battery included"にも適合します。 32 | 33 | ## Ergの名前の由来はなんですか? 34 | 35 | cgs単位系のエネルギーの単位ergから名前をつけられています。プログラマーにエネルギーを与える人間工学的(ergonomic)な言語というダブルミーニングです(後付けですが)。 36 | 37 | 他にもいくつか候補はありましたが、もっとも短いこと(Rubyの作者Matz曰く、言語の名前は短い方が良いとのことです)、ググラビリティがそれなりに高いことからこれに決定されました。 38 | -------------------------------------------------------------------------------- /compiler/erg_common/cache.rs: -------------------------------------------------------------------------------- 1 | use std::borrow::{Borrow, ToOwned}; 2 | use std::cell::RefCell; 3 | use std::hash::Hash; 4 | use std::rc::Rc; 5 | 6 | use crate::set::Set; 7 | use crate::{RcArray, Str}; 8 | 9 | #[derive(Debug)] 10 | pub struct Cache(RefCell>>); 11 | 12 | impl Default for Cache { 13 | fn default() -> Self { 14 | Self::new() 15 | } 16 | } 17 | 18 | impl Cache { 19 | pub fn new() -> Self { 20 | Self(RefCell::new(Set::new())) 21 | } 22 | } 23 | 24 | impl Clone for Cache { 25 | fn clone(&self) -> Self { 26 | Self(self.0.clone()) 27 | } 28 | } 29 | 30 | impl Clone for Cache { 31 | fn clone(&self) -> Self { 32 | Self(self.0.clone()) 33 | } 34 | } 35 | 36 | impl Cache { 37 | pub fn get(&self, s: &str) -> Str { 38 | if let Some(cached) = self.0.borrow().get(s) { 39 | return cached.clone().into(); 40 | } // &self.0 is dropped 41 | let s = Str::rc(s); 42 | self.0.borrow_mut().insert(s.clone().into_rc()); 43 | s 44 | } 45 | } 46 | 47 | impl Cache<[T]> { 48 | pub fn get(&self, q: &[T]) -> Rc<[T]> { 49 | if let Some(cached) = self.0.borrow().get(q) { 50 | return cached.clone(); 51 | } // &self.0 is dropped 52 | let s = RcArray::from(q); 53 | self.0.borrow_mut().insert(s.clone()); 54 | s 55 | } 56 | } 57 | 58 | impl Cache { 59 | pub fn get(&self, q: &Q) -> Rc 60 | where 61 | Rc: Borrow, 62 | Q: ToOwned, 63 | { 64 | if let Some(cached) = self.0.borrow().get(q) { 65 | return cached.clone(); 66 | } // &self.0 is dropped 67 | let s = Rc::from(q.to_owned()); 68 | self.0.borrow_mut().insert(s.clone()); 69 | s 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /doc/EN/improved_points.md: -------------------------------------------------------------------------------- 1 | # Improvements from Python 2 | 3 | ## Perform static analysis (static type checking, variable and property checking) 4 | 5 | The benefit of static type checking cannot be emphasized enough now, but checking for the existence of variables and properties is also a part that comes into play quite a bit. 6 | 7 | ## Strict scope handling 8 | 9 | In Python, statements do not have scopes. 10 | Therefore, variables defined in a `for` or `if` have outside effects. You cannot name variables casually. 11 | 12 | ```python 13 | for i in range(10): 14 | x = 1 15 | print(i + x) 16 | print(x) # 1 17 | ``` 18 | 19 | In Erg, all blocks have scope and are completely isolated. 20 | 21 | ## Clear distinction between mutable and immutable objects 22 | 23 | Python is not clear on the distinction between mutable and immutable / heap and value objects, so you have to keep in mind that tuples are immutable but lists are mutable... You need to keep in mind that tuples are immutable, but lists are mutable... and so on. 24 | Also, if you want to make your own classes immutable, you have to go through a tedious process. 25 | 26 | ```python 27 | # Can you believe this code is valid for the past versions of Python? 28 | i = 256 29 | assert i is 256 30 | i = 257 31 | assert i is not 257 32 | ``` 33 | 34 | ## Traits 35 | 36 | Just like Java's interface, you can do contract-based programming. 37 | 38 | Python also has ABC (Abstract Base Class), but this kind of structure works best with static typing. 39 | 40 | ## Resolve dependencies statically 41 | 42 | This prevents the annoying experience of running a program for a long time and then running it with an error due to missing modules. 43 | 44 | ## Built-in package manager 45 | 46 | Reproducible builds with a standardized directory structure and build files. 47 | Lock file generation and version control are of course provided. 48 | There is no need to choice or mix anaconda, pyenv, poetry, etc. for each project. 49 | -------------------------------------------------------------------------------- /doc/EN/syntax/20_naming_rule.md: -------------------------------------------------------------------------------- 1 | # Naming Conventions 2 | 3 | If a variable is to be used as a constant expression, it must begin with a capital letter. The second and succeeding letters may be in lowercase. 4 | 5 | ```erg 6 | i: Option Type = Int 7 | match i: 8 | t: Type -> log "type" 9 | None -> log "None" 10 | ``` 11 | 12 | Objects with side-effects must end with `!` must end with `!`. They are procedures, procedural methods, and mutable types. 13 | However, the `Proc` type itself is not a mutable type. 14 | 15 | ```erg 16 | # Callable == Func or Proc 17 | c: Callable = print! 18 | match c: 19 | p! -> log "proc" # can omit `: Proc` since it is self-explanatory 20 | f -> log "func" 21 | ``` 22 | 23 | If you want to expose the attribute to the outside world, define it with `.`. `.` attribute is not prefixed, the attribute is not public. To avoid confusion, they cannot coexist in the same scope. 24 | 25 | ```erg 26 | o = {x = 1; .x = 2} # SyntaxError: private and public variables with the same name cannot coexist 27 | ``` 28 | 29 | ## Literal Identifiers 30 | 31 | The above rule can be avoided by enclosing the string in single quotes (''). That is, a procedural object can also be assigned without `!`. In this case, however, even if the value is a constant expression, it is not considered a constant. 32 | Such a string identifier enclosed in single quotes is called a literal identifier. 33 | This is used when calling the API (FFI) of other languages such as Python. 34 | 35 | ```erg 36 | bar! = pyimport("foo").'bar' 37 | ``` 38 | 39 | Identifiers that are also valid in Erg do not need to be enclosed in ''. 40 | 41 | Furthermore, literal identifiers can contain both symbols and spaces, so strings that cannot normally be used as identifiers can be used as identifiers. 42 | 43 | ```erg 44 | '∂/∂t' y 45 | 'test 1: pass x to y'() 46 | ``` 47 | 48 |

49 | Previous | Next 50 |

51 | -------------------------------------------------------------------------------- /doc/EN/syntax/03_declaration.md: -------------------------------------------------------------------------------- 1 | # Declaration 2 | 3 | Declaration is the syntax for specifying the type of variable to be used. 4 | Declarations can be made anywhere in the code, but declarations alone do not refer to the variables. They must be initialized. 5 | After the assignment, the declaration can be checked to ensure that the type is compatible with the object to which it is assigned. 6 | 7 | ```erg 8 | i: Int 9 | # Can be declared at the same time as the assignment, like i: Int = 2 10 | i = 2 11 | i: Num 12 | i: Nat 13 | i: -2..2 14 | i: {2} 15 | ``` 16 | 17 | Declaration after assignment is similar to type checking by `assert`, but has the feature that it is checked at compile time. 18 | Type checking by `assert` at runtime can be checked for "may be type Foo", but type checking by `:` at compile time is strict: if the type is not determined to be "type Foo", it will not pass the check and an error will occur. 19 | 20 | ```erg 21 | i = (-1..10).sample! 22 | assert i in Nat # this may pass 23 | i: Int # this will pass 24 | i: Nat # this will not pass (-1 is not an element of Nat) 25 | ``` 26 | 27 | Functions can be declared in four different ways. None of them can omit the return type. 28 | 29 | ```erg 30 | f(x: Int, y: Int): Int 31 | f(Int, Int): Int 32 | f: (x: Int, y: Int) -> Int 33 | f: (Int, Int) -> Int 34 | ``` 35 | 36 | If you declare the argument names explicitly, a type error will result if the names are different at definition time. If you want to give the argument names arbitrary names, you can declare them in the second or fourth way. In that case, only the method name and its type will be seen by type checking. 37 | 38 | ```erg 39 | T = Trait { 40 | .f(x: Int, y: Int): Int 41 | } 42 | 43 | C = Class(U, Impl: T) 44 | C.f(a: Int, b: Int): Int = ... # TypeError: `.f` must be type of `(x: Int, y: Int) -> Int`, not `(a: Int, b: Int) -> Int` 45 | ``` 46 | 47 |

48 | Previous | Next 49 |

50 | -------------------------------------------------------------------------------- /compiler/erg_common/rccell.rs: -------------------------------------------------------------------------------- 1 | use std::cell::{Ref, RefCell, RefMut}; 2 | use std::fmt; 3 | use std::hash::{Hash, Hasher}; 4 | use std::rc::Rc; 5 | 6 | #[derive(Debug)] 7 | pub struct RcCell(Rc>); 8 | 9 | impl PartialEq for RcCell { 10 | #[inline] 11 | fn eq(&self, other: &Self) -> bool { 12 | self.0 == other.0 13 | } 14 | } 15 | 16 | impl Clone for RcCell { 17 | fn clone(&self) -> RcCell { 18 | Self(Rc::clone(&self.0)) 19 | } 20 | } 21 | 22 | impl Eq for RcCell {} 23 | 24 | impl Hash for RcCell { 25 | fn hash(&self, state: &mut H) { 26 | self.borrow().hash(state); 27 | } 28 | } 29 | 30 | impl Default for RcCell { 31 | fn default() -> Self { 32 | Self::new(Default::default()) 33 | } 34 | } 35 | 36 | impl fmt::Display for RcCell { 37 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 38 | write!(f, "{}", self.borrow()) 39 | } 40 | } 41 | 42 | impl RcCell { 43 | pub fn new(t: T) -> Self { 44 | Self(Rc::new(RefCell::new(t))) 45 | } 46 | 47 | #[inline] 48 | pub fn into_inner(self) -> T { 49 | let refcell = match Rc::try_unwrap(self.0) { 50 | Ok(refcell) => refcell, 51 | Err(_rc) => panic!("unwrapping failed"), 52 | }; 53 | RefCell::into_inner(refcell) 54 | } 55 | } 56 | 57 | impl RcCell { 58 | #[inline] 59 | pub fn copy(&self) -> Self { 60 | Self(self.0.clone()) 61 | } 62 | 63 | #[inline] 64 | pub fn borrow(&self) -> Ref<'_, T> { 65 | RefCell::borrow(&self.0) 66 | } 67 | 68 | #[inline] 69 | pub fn borrow_mut(&self) -> RefMut<'_, T> { 70 | RefCell::borrow_mut(&self.0) 71 | } 72 | } 73 | 74 | impl RcCell { 75 | #[inline] 76 | pub fn clone_inner(&self) -> T { 77 | self.borrow().clone() 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /doc/EN/syntax/12_dict.md: -------------------------------------------------------------------------------- 1 | # Dict 2 | 3 | Dict is a collection of key/value pairs. 4 | 5 | ```erg 6 | ids = {"Alice": 145, "Bob": 214, "Charlie": 301} 7 | assert ids["Alice"] == 145 8 | ``` 9 | 10 | The key does not have to be a string if it is a `Hash` object. 11 | 12 | ```erg 13 | # deprecated to use a range object as a key (confused with slice) 14 | r = {1..3: "1~3", 4..6: "4~6", 7..9: "7~9"} 15 | assert r[1..3] == "1~3" 16 | l = {[]: "empty", [1]: "1"} 17 | assert l[[]] == "empty" 18 | ``` 19 | 20 | Order does not matter for Dict. It also cannot have duplicate elements. In this respect, Dict is similar to Set. 21 | You could say that a Dict is a Set with values. 22 | 23 | ```erg 24 | {"Alice": 145, "Bob": 214, "Charlie": 301} == {"Alice": 145, "Charlie": 301, "Bob": 214} 25 | ``` 26 | 27 | When generating a dict from a dict literal, it is checked for duplicate keys. 28 | Any duplicates will result in a compile error. 29 | 30 | ```erg 31 | {"Alice": 145, "Alice": 1} # KeyError: Duplicate key "Alice" 32 | ``` 33 | 34 | Empty Dict is created with `{:}`. Note that `{}` denotes an empty set. 35 | 36 | ```erg 37 | mut_dict = !{:} 38 | mut_dict.insert! "Alice", 145 39 | mut_dict.insert! "Bob", 214 40 | assert mut_dict["Alice"] == 145 41 | ``` 42 | 43 | ## Heterogeneous Dict 44 | 45 | There need not be a single key/value type. Such a dictionary is called a __heterogenous dict_. 46 | 47 | ```erg 48 | d: {Str: Int, Int: Str} = {"a": 1, 1: "a"} 49 | assert d["a"] == 1 50 | assert d[1] == "a" 51 | ``` 52 | 53 | However, it is not possible to assign values of the same type to keys of different types, or values of different types to keys of the same type. 54 | In such cases, use the type Or instead. 55 | 56 | ```erg 57 | invalid1 = {1: "a", "a": "b"} 58 | invalid2 = {1: "a", 2: 2} 59 | 60 | # Erg type inference does not infer Or type, so type specification is required 61 | valid1: {Int or Str: Str} = {1: "a", "a": "b"} 62 | valid2: {Int: Int or Str} = {1: "a", 2: 2} 63 | ``` 64 | 65 |

66 | Previous | Next 67 |

68 | -------------------------------------------------------------------------------- /doc/JA/syntax/33_package_system.md: -------------------------------------------------------------------------------- 1 | # パッケージシステム 2 | 3 | Ergのパッケージはアプリケーションであるappパッケージとライブラリであるlibパッケージに大別できます。 4 | appパッケージのエントリポイントは`src/app.er`です。`app.er`内に定義された`main`関数が実行されます。 5 | libパッケージのエントリポイントは`src/lib.er`です。パッケージをインポートすることは`lib.er`をインポートすることと等価になります。 6 | 7 | パッケージにはモジュールという下位構造があります。Ergにおいてモジュールとはすなわち、Ergファイルもしくはそれで構成されたディレクトリです。外部のErgファイル/ディレクトリはモジュールオブジェクトとして操作可能な対象になるのです。 8 | 9 | ディレクトリをモジュールとして認識させるには、ディレクトリ内に`(ディレクトリ名).er`ファイルを置く必要があります。 10 | これはPythonの`__init__.py`と同じようなものですが、`__init__.py`と違ってディレクトリの外に置きます。 11 | 12 | 例として、以下のようなディレクトリ構成を考えてみましょう。 13 | 14 | ```console 15 | └─┬ ./src 16 | ├─ app.er 17 | ├─ foo.er 18 | ├─ bar.er 19 | └─┬ bar 20 | ├─ baz.er 21 | └─ qux.er 22 | ``` 23 | 24 | `app.er`では`foo`モジュールと`bar`モジュールをインポートできます。`bar`ディレクトリがモジュールとして認識できるのは`bar.er`ファイルがあるためです。 25 | `foo`モジュールはファイルからなるモジュールで、`bar`モジュールはディレクトリからなるモジュールです。`bar`モジュールはさらに`baz`, `qux`モジュールを内部に持ちます。 26 | このモジュールは単に`bar`モジュールの属性であり、`app.er`からは以下のようにアクセスできます。 27 | 28 | ```erg 29 | # app.er 30 | foo = import "foo" 31 | bar = import "bar" 32 | baz = bar.baz 33 | # or `baz = import "bar/baz"` 34 | 35 | main args = 36 | ... 37 | ``` 38 | 39 | サブモジュールにアクセスするための区切り文字が`/`であることに注意してください。これは、`bar.baz.er`のようなファイル名があり得るためです。 40 | このようなファイル名は推奨されません。Ergでは`.er`のプレフィックスが意味を持つためです。 41 | 例えば、テスト用のモジュールです。`.test.er`で終わるファイルは(ホワイトボックス)テスト用のモジュールであり、テスト実行時に`@Test`でデコレーションされたサブルーチンが実行されます。 42 | 43 | ```console 44 | └─┬ ./src 45 | ├─ app.er 46 | ├─ foo.er 47 | └─ foo.test.er 48 | ``` 49 | 50 | ```erg 51 | # app.er 52 | foo = import "foo" 53 | 54 | main args = 55 | ... 56 | ``` 57 | 58 | また、`.private.er`で終わるファイルはプライベートモジュールであり、同一ディレクトリのモジュールからしかアクセスできません。 59 | 60 | ```console 61 | └─┬ 62 | ├─ foo.er 63 | ├─ bar.er 64 | └─┬ bar 65 | ├─ baz.private.er 66 | └─ qux.er 67 | ``` 68 | 69 | ```erg 70 | # foo.er 71 | bar = import "bar" 72 | bar.qux 73 | bar.baz # AttributeError: module 'baz' is private 74 | ``` 75 | 76 | ```erg 77 | # qux.er 78 | baz = import "baz" 79 | ``` 80 | 81 |

82 | Previous | Next 83 |

84 | -------------------------------------------------------------------------------- /doc/JA/syntax/type/17_type_casting.md: -------------------------------------------------------------------------------- 1 | # キャスト 2 | 3 | ## アップキャスト 4 | 5 | Pythonはダックタイピングを採用する言語のため、キャストという概念はありません。アップキャストはする必要がなく、ダウンキャストも基本的にはありません。 6 | しかしErgは静的に型付けされるため、キャストを行わなければいけない場合があります。 7 | 簡単な例では、`1 + 2.0`が挙げられます。Ergの言語仕様上は`+`(Int, Ratio)、すなわちInt(<: Add(Ratio, Ratio))の演算は定義されていません。というのも、`Int <: Ratio`であるため、1はRatioのインスタンスである1.0にアップキャストされるからです。 8 | 9 | ~~Erg拡張バイトコードはBINARY_ADDに型情報を加えますが、この際の型情報はRatio-Ratioとなります。この場合はBINARY_ADD命令がIntのキャストを行うため、キャストを指定する特別な命令は挿入されません。なので、例えば子クラスでメソッドをオーバーライドしても、親を型に指定すれば型強制(type coercion)が行われ、親のメソッドで実行されます(コンパイル時に親のメソッドを参照するように名前修飾が行われます)。コンパイラが行うのは型強制の妥当性検証と名前修飾のみです。ランタイムがオブジェクトをキャストすることはありません(現在のところ。実行最適化のためにキャスト命令が実装される可能性はあります)。~~ 10 | 11 | ```erg 12 | @Inheritable 13 | Parent = Class() 14 | Parent. 15 | greet!() = print! "Hello from Parent" 16 | 17 | Child = Inherit Parent 18 | Child. 19 | # オーバーライドする際にはOverrideデコレータが必要 20 | @Override 21 | greet!() = print! "Hello from Child" 22 | 23 | greet! p: Parent = p.greet!() 24 | 25 | parent = Parent.new() 26 | child = Child.new() 27 | 28 | greet! parent # "Hello from Parent" 29 | greet! child # "Hello from Parent" 30 | ``` 31 | 32 | この挙動はPythonとの非互換性を生むことはありません。そもそもPythonでは変数に型が指定されないので、いわば全ての変数が型変数で型付けされている状態となります。型変数は適合する最小の型を選ぶので、Ergで型を指定しなければPythonと同じ挙動が達成されます。 33 | 34 | ```erg 35 | @Inheritable 36 | Parent = Class() 37 | Parent. 38 | greet!() = print! "Hello from Parent" 39 | 40 | Child = Inherit Parent 41 | Child. 42 | greet!() = print! "Hello from Child" 43 | 44 | greet! some = some.greet!() 45 | 46 | parent = Parent.new() 47 | child = Child.new() 48 | 49 | greet! parent # "Hello from Parent" 50 | greet! child # "Hello from Child" 51 | ``` 52 | 53 | 継承関係にある型同士では`.from`, `.into`が自動実装されるので、それを使うこともできます。 54 | 55 | ```erg 56 | assert 1 == 1.0 57 | assert Ratio.from(1) == 1.0 58 | assert 1.into() == 1.0 59 | ``` 60 | 61 | ## ダウンキャスト 62 | 63 | ダウンキャストは一般に安全ではなく、変換方法も自明ではないため、代わりに`TryFrom.try_from`の実装で実現します。 64 | 65 | ```erg 66 | IntTryFromFloat = Patch Int 67 | IntTryFromFloat. 68 | try_from r: Float = 69 | if r.ceil() == r: 70 | then: r.ceil() 71 | else: Error "conversion failed" 72 | ``` 73 | -------------------------------------------------------------------------------- /doc/JA/syntax/type/advanced/GADTs.md: -------------------------------------------------------------------------------- 1 | # 一般化代数的データ型(Generalized Algebraic Data Types, GADTs) 2 | 3 | ErgはOr型をクラス化することで一般化代数的データ型(GADTs)を作成出来ます。 4 | 5 | ```erg 6 | Nil T = Class(Impl: Phantom T) 7 | Cons T = Class {head = T; rest = List T}, Impl=Unpack 8 | List T: Type = Class(Nil T or Cons T) 9 | List. 10 | nil() | T = Self(T).new Nil(T).new() 11 | cons head, rest | T = Self(T).new Cons(T).new(head, rest) 12 | head self = match self: 13 | {head; ...}: Cons _ -> head 14 | _: Nil -> panic "empty list" 15 | {nil; cons; ...} = List 16 | 17 | print! cons(1, cons(2, nil())).head() # 1 18 | print! nil.head() # RuntimeError: "empty list" 19 | ``` 20 | 21 | `List(T).nil() = ...`ではなく`List.nil|T|() = ...`としているのは、使用時に型指定が不要になるからです。 22 | 23 | ```erg 24 | i = List.nil() 25 | _: List Int = cons 1, i 26 | ``` 27 | 28 | ここで定義した`List T`はGADTsですが、素朴な実装であり、GADTsの真価を発揮していません。 29 | 例えば、上の`.head`メソッドはもし中身が空なら実行時エラーを出しますが、この検査はコンパイル時に行うことができます。 30 | 31 | ```erg 32 | List: (Type, {"Empty", "Nonempty"}) -> Type 33 | List T, "Empty" = Class(Impl: Phantom T) 34 | List T, "Nonempty" = Class {head = T; rest = List(T, _)}, Impl=Unpack 35 | List. 36 | nil() | T = Self(T, "Empty").new Nil(T).new() 37 | cons head, rest | T = Self(T, "Nonempty").new {head; rest} 38 | List(T, "Nonempty"). 39 | head {head; ...} = head 40 | {nil; cons; ...} = List 41 | 42 | print! cons(1, cons(2, nil())).head() # 1 43 | print! nil().head() # TypeError 44 | ``` 45 | 46 | 巷でよく説明されるGADTsの例は、以上のように中身が空か否か型で判定できるリストです。 47 | Ergではさらに精密化して、長さを持つリストを定義することができます。 48 | 49 | ```erg 50 | List: (Type, Nat) -> Type 51 | List T, 0 = Class(Impl: Phantom T) 52 | List T, N = Class {head = T; rest = List(T, N-1)}, Impl=Unpack 53 | List. 54 | nil() | T = Self(T, 0).new Nil(T).new() 55 | cons head, rest | T, N = Self(T, N).new {head; rest} 56 | List(_, N | N >= 1). 57 | head {head; ...} = head 58 | List(_, N | N >= 2). 59 | pair {head = first; rest = {head = second; ...}} = [first, second] 60 | {nil; cons; ...} = List 61 | 62 | print! cons(1, cons(2, nil)).pair() # [1, 2] 63 | print! cons(1, nil).pair() # TypeError 64 | print! cons(1, nil).head() # 1 65 | print! nil.head() # TypeError 66 | ``` 67 | -------------------------------------------------------------------------------- /doc/JA/syntax/type/12_refinement.md: -------------------------------------------------------------------------------- 1 | # 篩型(Refinement Type) 2 | 3 | Refinement type(篩型、ふるいがた)は、述語式によって制約付けられた型です。列挙型や区間型は篩型の一種です。 4 | 5 | 篩型の標準形は`{Elem: Type | (Pred)*}`です。これは、`Pred`を満たす`Elem`を要素とする型である、という意味です。 6 | 篩型に使えるのは[Const型](./advanced/const.md)のみです。 7 | 8 | ```erg 9 | Nat = 0.._ 10 | Odd = {N: Int | N % 2 == 1} 11 | Char = StrWithLen 1 12 | # StrWithLen 1 == {_: StrWithLen N | N == 1} 13 | [Int; 3] == {_: Array Int, N | N == 3} 14 | Array3OrMore == {A: Array _, N | N >= 3} 15 | ``` 16 | 17 | 複数のPredがあるとき、`;`か`and`, `or`で区切れます。`;`と`and`は同じ意味です。 18 | 19 | `Odd`の要素は`1, 3, 5, 7, 9, ...`です。 20 | 篩にかけるように既存の型の一部を要素とする型になることから篩型と呼ばれます。 21 | 22 | `Pred`は(左辺)述語式と呼ばれます。これは代入式と同じく意味のある値を返すものではなく、左辺にはパターンしか置けません。 23 | すなわち、`X**2 - 5X + 6 == 0`のような式は篩型の述語式としては使えません。この点において、右辺式の述語式とは異なります。 24 | 25 | ```erg 26 | {X: Int | X**2 - 5X + 6 == 0} # SyntaxError: the predicate form is invalid. Only names can be on the left-hand side 27 | ``` 28 | 29 | あなたが二次方程式の解法を知っているならば、上の篩型は`{2, 3}`と同等になるだろうと予想できるはずです。 30 | しかしErgコンパイラは代数学の知識をほとんど持ち合わせていないので、右の述語式を解決できないのです。 31 | 32 | ## Smart Cast 33 | 34 | `Odd`を定義したのはいいですが、このままではリテラル以外ではあまり使えないようにみえます。通常の`Int`オブジェクトの中の奇数を`Odd`に昇格させる、つまり`Int`を`Odd`にダウンキャストするためには、`Odd`のコンストラクタを通す必要があります。 35 | 篩型の場合、通常のコンストラクタ`.new`はパニックする可能性があり、`.try_new`という`Result`型を返す補助的なコンストラクタもあります。 36 | 37 | ```erg 38 | i = Odd.new (0..10).sample!() 39 | i: Odd # or Panic 40 | ``` 41 | 42 | また、`match`中で型指定として使用することもできます。 43 | 44 | ```erg 45 | # i: 0..10 46 | i = (0..10).sample!() 47 | match i: 48 | o: Odd -> 49 | log "i: Odd" 50 | n: Nat -> # 0..10 < Nat 51 | log "i: Nat" 52 | ``` 53 | 54 | ただし、Ergは現在のところ`Odd`でなかったから`Even`、などといった副次的な判断はできません。 55 | 56 | ## 列挙型、区間型と篩型 57 | 58 | 今まで紹介した列挙型と区間型は、篩型の糖衣構文です。 59 | `{a, b, ...}`は`{I: Typeof(a) | I == a or I == b or ... }`に、`a..b`は`{I: Typeof(a) | I >= a and I <= b}`に脱糖されます。 60 | 61 | ```erg 62 | {1, 2} == {I: Int | I == 1 or I == 2} 63 | 1..10 == {I: Int | I >= 1 and I <= 10} 64 | 1..<10 == {I: Int | I >= 1 and I < 10} == {I: Int | I >= 1 and I <= 9} 65 | ``` 66 | 67 | ## 篩パターン 68 | 69 | `_: {X}`を`X`と書き換えられるように(定数パターン)、`_: {X: T | Pred}`は`X: T | Pred`と書き換えることができます。 70 | 71 | ```erg 72 | # メソッド.mは長さ3以上の配列に定義される 73 | Array(T, N | N >= 3) 74 | .m(&self) = ... 75 | ``` 76 | -------------------------------------------------------------------------------- /doc/JA/syntax/type/overloading.md: -------------------------------------------------------------------------------- 1 | # Overloading 2 | 3 | Ergでは __アドホック多相__ をサポートしない。すなわち、関数・カインドの多重定義(オーバーロード)ができない。が、トレイトクラスとパッチを組み合わせることでオーバーロードの挙動を再現できる。 4 | トレイトクラスのかわりにトレイトを使用しても良いが、その場合`.add1`を実装している型全てが対象になってしまう。 5 | 6 | ```erg 7 | Add1 = Trait { 8 | .add1: Self.() -> Self 9 | } 10 | IntAdd1 = Patch Int, Impl=Add1 11 | IntAdd1. 12 | add1 self = self + 1 13 | RatioAdd1 = Patch Ratio, Impl=Add1 14 | RatioAdd1. 15 | add1 self = self + 1.0 16 | 17 | add1|X <: Add1| x: X = x.add1() 18 | assert add1(1) == 2 19 | assert add1(1.0) == 2.0 20 | ``` 21 | 22 | このような、ある型のサブタイプすべてを受け入れることによる多相を __サブタイピング多相__ と呼ぶ。Ergにおけるサブタイピング多相は列多相も含む。 23 | 24 | 各型での処理が完全に同じなら下のように書くこともできる。上の書き方は、クラスによって挙動を変える(が、戻り値型は同じ)場合に使う。 25 | 型引数を使う多相を __パラメトリック多相__ という。パラメトリック多相は下のように部分型指定と併用する場合が多く、その場合はパラメトリック多相とサブタイピング多相の合わせ技ということになる。 26 | 27 | ```erg 28 | add1|T <: Int or Str| x: T = x + 1 29 | assert add1(1) == 2 30 | assert add1(1.0) == 2.0 31 | ``` 32 | 33 | また、引数の数が違うタイプのオーバーロードはデフォルト引数で再現できる。 34 | 35 | ```erg 36 | C = Class {.x = Int; .y = Int} 37 | C. 38 | new(x, y |= 0) = Self::__new__ {.x; .y} 39 | 40 | assert C.new(0, 0) == C.new(0) 41 | ``` 42 | 43 | 引数の数によって型が違うなど全く挙動が変わる関数は定義できないが、そもそも振る舞いが異なるならば別の名前を付けるべきであるというスタンスをErgは取る。 44 | 45 | 結論として、Ergがオーバーロードを禁止してサブタイピング+パラメトリック多相を採用したのは以下の理由からである。 46 | 47 | まず、オーバーロードされた関数は定義が分散する。このため、エラーが発生した際に原因となる箇所を報告するのが難しい。 48 | また、サブルーチンをインポートすることによって、すでに定義されたサブルーチンの挙動が変わる恐れもある。 49 | 50 | ```erg 51 | {id; ...} = import "foo" 52 | ... 53 | id x: Int = x 54 | ... 55 | id x: Ratio = x 56 | ... 57 | id "str" # TypeError: id is not implemented for Str 58 | # But... where did this error come from? 59 | ``` 60 | 61 | 次に、デフォルト引数との相性が悪い。デフォルト引数のある関数がオーバーロードされているとき、どれが優先されるかという問題がある。 62 | 63 | ```erg 64 | f x: Int = ... 65 | f(x: Int, y |= 0) = ... 66 | 67 | f(1) # which is chosen? 68 | ``` 69 | 70 | さらに、宣言との相性が悪い。 71 | 宣言`f: Num -> Num`は、どちらの定義のことを指しているのか特定できない。`Int -> Ratio`と`Ratio -> Int`は包含関係がないためである。 72 | 73 | ```erg 74 | f: Num -> Num 75 | f(x: Int): Ratio = ... 76 | f(x: Ratio): Int = ... 77 | ``` 78 | 79 | そして、文法の一貫性を損なう。Ergは変数の再代入を禁止するが、オーバーロードの文法は再代入のように見えてしまう。 80 | 無名関数に置換することもできない。 81 | 82 | ```erg 83 | # same as `f = x -> body` 84 | f x = body 85 | 86 | # same as... what? 87 | f x: Int = x 88 | f x: Ratio = x 89 | ``` 90 | -------------------------------------------------------------------------------- /doc/JA/API/modules/unit.md: -------------------------------------------------------------------------------- 1 | # module `unit` 2 | 3 | `unit`モジュールは数値計算でよく使われる単位を型として定義したモジュールです。 4 | Ergの数値型は`Nat`, `Int`, `Ratio`などがあります。しかしこれらの型は「何を意味する数値なのか」という情報を持っておらず、メートルとヤード同士の足し算などといったナンセンスな計算を行えてしまいます。 5 | `unit`モジュールを使うことにより、単位の違う数値を関数に渡すといったミスを防げます。 6 | このようなミスは実際に起っており、[単位系の取り間違いで火星探査機が行方不明](http://www.sydrose.com/case100/287/)になるなど、深刻なバグを引き起こしかねません。 7 | 数値計算を行う上でコードの堅牢性を高めたいならばこのモジュールを使用しておくべきです。 8 | 9 | ```erg 10 | {*} = import "unit" 11 | 12 | x = 6m # `x = Meter.new(6)`と等価 13 | t = 3s # `t = Sec.new(3)`と等価 14 | # m/sは速度の単位オブジェクトで、Velocity型 15 | print! x/t # 2m/s 16 | print! x + 4m # 10m 17 | print! x + 2s # TypeError: `+`(Meter, Sec) is not implemented 18 | ``` 19 | 20 | `m`, `s`, `m/s`というオブジェクトは単位オブジェクトと呼ばれます。それ自体で1m, 1s, 1m/sという意味を持ちます。`m/s`はmとsの合成によって生まれた単位オブジェクトといえます。 21 | 22 | unitでは以下の単位を型として定義しています。SI(国際単位系)と呼ばれるものです。 23 | 24 | * 長さ:Meter(単位定数: m) 25 | * 質量:KiloGram(単位定数: kg, g = 0.001kg) 26 | * 時間:Sec (分、時間、日、年などはSecから生成されたminute, hour, day, yearなどの定数がある) 27 | * 電流: Amper(単位定数: a) 28 | * 温度: Kelvin(単位定数: k, Fahren, Celsius型もあり、相互変換可能) 29 | * 物質量: Mol(単位定数: mol) 30 | * 光度: Candela(単位定数: cd) 31 | 32 | また、`Unit1`, `UnitMul`, `UnitDiv`という型が定義されており、これを使用して基本型を合成し新しい単位を作成する事が可能です。 33 | 例えば、振動数の単位ヘルツ(hertz)は振動周期(秒)の逆数で定義されているので、`UnitDiv(Unit1, Sec)`です。 34 | この型を意味のある型とみなしたい(専用のメソッドを加えたい、など)ときは、[パッチ](./../../syntax/type/07_patch.md)を作成すると良いでしょう。 35 | 36 | ```erg 37 | Hertz = Patch UnitDiv(Unit1, Sec) 38 | SquareMeter = Patch UnitMul(Meter, Meter) 39 | ``` 40 | 41 | 補助単位も予めいくつか定義されています。 42 | 43 | * 振動数: Hertz(hz) 44 | * 力: Newton(newton) 45 | * エネルギー: Joule(j) 46 | * 仕事率: Watt(w) 47 | * 電位: Volt(v) 48 | * 電気抵抗: Ohm(ohm) 49 | * 速度: Velocity(m/s) 50 | * 面積: SquareMeter(m**2) 51 | * 体積: CubicMeter(m**3) (litre = 10e-3 m**3) 52 | * 角度: Degree(deg) (rad = 180/pi deg) 53 | * 長さ: Feet, Yard, Inch, Mile, Ly, Au, Angstrom 54 | * 重さ: Pond 55 | 56 | また、接頭辞も定義しています。 57 | 58 | * Femto = 1e-15 59 | * Pico = 1e-12 60 | * Nano = 1e-9 61 | * Micro = 1e-6 62 | * Milli = 1e-3 63 | * Centi = 1e-2 64 | * Deci = 1e-1 65 | * Hecto = 1e+2 66 | * Kilo = 1e+3 67 | * Mega = 1e+6 68 | * Giga = 1e+9 69 | * Tera = 1e+12 70 | * Peta = 1e+15 71 | * Exa = 1e+18 72 | 73 | ※名前の由来に反して、Ergでは基本的にMKS単位系を採用しています。CGS単位系のunitモジュールが欲しい場合は、外部ライブラリ([cgs](https://github.com/mtshiba/cgs)等)を使用してください。 74 | -------------------------------------------------------------------------------- /doc/JA/syntax/21_lambda.md: -------------------------------------------------------------------------------- 1 | # 無名関数(anonymous function) 2 | 3 | 無名関数は、関数オブジェクトを名付けずその場で生成するための文法である。 4 | 5 | ```erg 6 | # `->`は無名関数演算子 7 | # same as `f x, y = x + y` 8 | f = (x, y) -> x + y 9 | # same as `g(x, y: Int): Int = x + y` 10 | g = (x, y: Int): Int -> x + y 11 | ``` 12 | 13 | 引数が1つの場合は`()`を省略できる。 14 | 15 | ```erg 16 | assert [1, 2, 3].map_collect(i -> i + 1) == [2, 3, 4] 17 | assert ((i, j) -> [i, j])(1, 2) == [1, 2] 18 | ``` 19 | 20 | 下の場合`0..9, (i -> ...)`であって`(0..9, i) -> ...`ではない。 21 | `->`は左辺に一つだけ引数をとる。複数の引数は一つのタプルとして受け取る。 22 | 23 | ```erg 24 | for 0..9, i: Int -> 25 | ... 26 | ``` 27 | 28 | 無名関数では、空白による構文解釈の差異が存在する。 29 | 30 | ```erg 31 | # この場合は`T(() -> Int)`と解釈される 32 | i: T () -> Int 33 | # この場合は(U()) -> Intと解釈される 34 | k: U() -> Int 35 | ``` 36 | 37 | 無名関数は引数なしでも使える。`=>`は無名プロシージャ演算子。 38 | 39 | ```erg 40 | p! = () => print! "`p!` was called" 41 | # `() ->`, `() =>`には`do`, `do!`という糖衣構文がある 42 | # p! = do! print! "`p!` was called" 43 | p!() # `p!` was called 44 | ``` 45 | 46 | 引数なし関数は遅延初期化に使える。 47 | 48 | ```erg 49 | time = import "time" 50 | date = import "datetime" 51 | now = if! True: 52 | do!: 53 | time.sleep! 1000 54 | date.now!() 55 | do date.new("1970", "1", "1", "00", "00") 56 | ``` 57 | 58 | 型付け、パターンマッチもできる。このため、`match`関数はほとんど無名関数の力で実現されている。 59 | `match`関数の引数に与える無名関数は上から順番にトライされる。ので、上の方は特殊なケースを、下に行くほど一般的なケースを記述する必要がある。順番を間違えると(可能な限り)コンパイラがWarningを出す。 60 | 61 | ```erg 62 | n = (Complex or Ratio or Int).sample!() 63 | i = match n: 64 | PI -> PI # 定数PIに等しい場合 65 | (i: 1..10) -> i # 1~10のIntの場合 66 | (i: Int) -> i # Intの場合 67 | (c: Complex) -> c.real() # Complexの場合。Int < Complexだが、フォールバックできる 68 | _ -> panic "cannot convert to Int" # 以上のいずれにも該当しない場合。matchは全パターンを網羅していなくてはならない 69 | ``` 70 | 71 | エラーハンドリングも`?`か`match`を使用して行うのが一般的である。 72 | 73 | ```erg 74 | res: ParseResult Int 75 | match res: 76 | i: Int -> i 77 | err: Error -> panic err.msg 78 | 79 | res2: Result Int, Error 80 | match res2: 81 | ok: Not Error -> log Typeof ok 82 | err: Error -> panic err.msg 83 | ``` 84 | 85 | ## 無名多相関数 86 | 87 | ```erg 88 | # same as id|T| x: T = x 89 | id = |T| x: T -> x 90 | ``` 91 | 92 |

93 | Previous | Next 94 |

95 | -------------------------------------------------------------------------------- /doc/JA/python/class_system.md: -------------------------------------------------------------------------------- 1 | # Pythonのクラスシステム(Ergとの比較) 2 | 3 | ## メソッド 4 | 5 | メソッドは前方参照していてもかまわないが、これは特別なテクニックが使われているわけではなく、 6 | メソッドの実在が動的に検査されるためである。 7 | (Ergではメソッドの実在は静的に検査される。前方参照するためには関数を定数にしなくてはならない。) 8 | 9 | ```python 10 | >>> class C: 11 | ... def f(self, x): 12 | ... if x == 0: return 0 13 | ... else: return self.g(x) 14 | ... def g(self, x): return self.f(x - 1) 15 | ``` 16 | 17 | ## 継承、オーバーライド 18 | 19 | オーバーライドされたあるメソッドmは単に変数の再代入のように上書きされ、 20 | 親クラスのmを参照するメソッドは子クラスではオーバーライドされたmを参照するようになる。 21 | 22 | ```python 23 | >>> class C: 24 | ... def f(self): return 1 25 | ... def g(self): return self.f() 26 | ... 27 | >>> class D(C): 28 | ... def f(self): return 2 29 | ... 30 | >>> D().g() 31 | 2 32 | ``` 33 | 34 | なので、明らかに間違ってオーバーライドされても実行時までエラーとならない。 35 | 36 | ```python 37 | >>> class C: 38 | ... def f(self): return 1 39 | ... def g(self): return self.f() + 1 40 | ... 41 | >>> class D(C): 42 | ... def f(self): return "a" 43 | ... 44 | >>> D().g() 45 | Traceback (most recent call last): 46 | File "", line 1, in 47 | File "", line 3, in g 48 | TypeError: can only concatenate str (not "int") to str 49 | ``` 50 | 51 | Ergでは親クラスとの整合性が静的に検査される。 52 | オーバーライド時には`Override`デコレータを付与する必要があり、オーバーライドする関数の型はされる関数の型の部分型とならなくてはならない。 53 | 54 | ```erg 55 | >>> C = Class() 56 | ... .f self = 1 57 | ... .g self = self.f() + 1 58 | ... 59 | >>> D = Inherit C 60 | ... .f self = "a" 61 | ... 62 | Error[#XX]: File "", line 5, in D 63 | .f(self) is already defined in C. To override f, it must be added `Override` decorator and its type must be `Self.() -> Nat` or the subtype of that 64 | .f(self)は既にCで定義されています。オーバーライドするためには`Override`デコレータを付与し、`Self.() -> Nat`型かそのサブタイプである必要があります。 65 | ``` 66 | 67 | ## 型チェック 68 | 69 | 型チェックは概ね関数引数の型チェックに尽きる。 70 | Pythonでは、大半の操作がメソッド呼び出しである。呼び出し時にオブジェクトの属するクラスにメソッドがついていなればそれまでである。 71 | 72 | ```python 73 | def f(x): 74 | return x.m() 75 | 76 | class C: 77 | def m(self): return None 78 | 79 | c = C() 80 | f(c) 81 | f(1) # TypeError 82 | ``` 83 | 84 | ```erg 85 | # f: |T, X <: {.m = Self.() -> T}| X -> T 86 | f(x) = x.m() 87 | 88 | C = Class() 89 | C.m(self) = None 90 | 91 | c = C.new() 92 | f(c) 93 | f(1) # TypeError: f takes a type has method `.m` as an argument, but passed Nat 94 | ``` 95 | -------------------------------------------------------------------------------- /doc/JA/compiler/errors.md: -------------------------------------------------------------------------------- 1 | # Erg Compiler Errors 2 | 3 | ## AssignError 4 | 5 | イミュータブル変数を書き換えようとすると発生します。 6 | 7 | ## AttributeError 8 | 9 | 存在しない属性にアクセスしようとすると発生します。 10 | 11 | ## SideEffectError 12 | 13 | 副作用が許可されていないスコープ(関数、不変型など)で副作用を起こすコードを記述すると発生します。 14 | 15 | ## OwnershipError 16 | 17 | 既にムーブ済みの変数にアクセスしようとすると発生します。 18 | 19 | ## BorrowError 20 | 21 | あるオブジェクトに対する借用が存在している間にもう一つ可変参照を取得しようとすると発生します。 22 | 23 | ## CyclicError 24 | 25 | 明らかに停止しない循環を起こしている場合に発生します。 26 | 27 | ```erg 28 | i: Int = i 29 | 30 | f(): Int = g() 31 | g() = f() 32 | 33 | h(): Int = module::h() 34 | 35 | T = U 36 | U = T 37 | ``` 38 | 39 | ## BytecodeError 40 | 41 | 読み込んだバイトコードが破損していた場合に発生します。 42 | 43 | ## CompileSystemError 44 | 45 | コンパイラ内部でエラーが起きた場合に発生します。 46 | 47 | ## EnvironmentError 48 | 49 | インストール時にアクセス権限がなかった場合などで発生します。 50 | 51 | ## FeatureError 52 | 53 | 正式に提供されていない試験的機能を検出した際に発生します。 54 | 55 | ## ImportError 56 | 57 | ## IndentationError 58 | 59 | 不正なインデントを検出すると発生します。 60 | SyntaxErrorの派生です。 61 | 62 | ## NameError 63 | 64 | 存在しない変数にアクセスすると発生します。 65 | 66 | ## NotImplementedError 67 | 68 | 定義は存在し、実装のないAPIを呼び出すと発生します。 69 | TypeErrorの派生です。 70 | 71 | ## PatternError 72 | 73 | 不正なパターンを検出すると発生します。 74 | SyntaxErrorの派生です。 75 | 76 | ## SyntaxError 77 | 78 | 不正な文法を検出すると発生します。 79 | 80 | ## TabError 81 | 82 | インデント/スペースとしてタブ文字を使うと発生します。 83 | SyntaxErrorの派生です。 84 | 85 | ## TypeError 86 | 87 | オブジェクトの型が合わない際に発生します。 88 | 89 | ## UnboundLocalError 90 | 91 | 変数を定義前に使用すると発生します。 92 | 正確には、あるスコープ内で定義された変数がそれ以前に使われていると発生します。 93 | 94 | ```erg 95 | i = 0 96 | f x = 97 | y = i + x 98 | i = 1 99 | y + i 100 | ``` 101 | 102 | このコードでは`y = i + x`の`i`が未定義変数になります。 103 | しかし、定数の場合は定義前に別の関数中で呼び出し可能です。 104 | 105 | ```erg 106 | f() = g() 107 | g() = f() 108 | ``` 109 | 110 | ## Erg Compiler Warnings 111 | 112 | ## SyntaxWarning 113 | 114 | 文法上は問題ありませんが、冗長だったり一般的でないコードを検出した際に発生します(不要な`()`など)。 115 | 116 | ```erg 117 | if (True): # SyntaxWarning: unnecessary parentheses 118 | ... 119 | ``` 120 | 121 | ## DeprecationWarning 122 | 123 | 参照したオブジェクトが非推奨である場合に発生します。 124 | (開発者はこのWarningを発生させる際、必ず代替手段をHintとして提示してください) 125 | 126 | ## FutureWarning 127 | 128 | 将来的に問題が起こりそうなコードを検出すると発生します。 129 | このWarningはバージョンの互換性(ライブラリ含む)の問題や文法・APIの変更によって起こります。 130 | 131 | ## ImportWarning 132 | -------------------------------------------------------------------------------- /doc/JA/dev_guide/unify_terms.md: -------------------------------------------------------------------------------- 1 | # 用語の統一 2 | 3 | ## Accessibility, Visibility (参照性、可視性) 4 | 5 | Visibility(可視性)を使用する。 6 | 7 | ## Complement(否定型、補型) 8 | 9 | 否定型を使用する。Complementの結果Not型になるとは限らない。 10 | 11 | ## Diff(差型、除外型、直差型) 12 | 13 | 除外型を使用する。Diffの結果Not型になるとは限らない。 14 | 15 | ## Intersection(共通部分型、交差型、直積型) 16 | 17 | 交差型を使用する。直積型は使用しない。タプルを直積型とみなす用法もあるためである。 18 | ただし、属性的部分型の観点からはErgのAnd型と本質的に等価な概念である。 19 | また、Intersectionの結果And型になるとは限らない。例えば`{1, 2, 3} and {1, 2} == {1, 2}`である。 20 | 21 | ## Nominal subtypingの訳語 22 | 23 | 記名的/名目的/公称的部分型付けがあるが、記名的部分型付けを使用する。 24 | 25 | ## Ratio型の訳語 26 | 27 | 有理数型を使用する。Floatは別途提供されているので、浮動小数点数型とは呼ばない。 28 | 29 | ## Union(合併型、直和型) 30 | 31 | 合併型を使用する。Unionの結果Or型になるとは限らない。 32 | 33 | ## 型境界(Type bound)、型制約(Type constraint) 34 | 35 | 量化型、篩型に与えられている述語式のリスト。型境界を使用する。 36 | 37 | ## サブルーチン、ルーチン、サブプログラム 38 | 39 | サブルーチンを使用する。 40 | 41 | ## 参照透過である/でない、副作用あり/なし 42 | 43 | 副作用あり/なしを使用する。 44 | 45 | ## 識別子、代数、変数、名前、シンボル 46 | 47 | 元来の意味としては、 48 | 49 | * シンボル(Symbol): 文字列オブジェクトでない(""で囲まれていない)ソースコードにベタ書きされた文字(記号や制御文字などを除く)。RubyやLispなどでのプリミティブ型としてのシンボルが存在するが、Ergではオブジェクト扱いされない。 50 | * 識別子(Identifier): シンボルのうち、予約語でなく、何らかのオブジェクトを指すもの(また指し得るもの)。例えばPythonではclassやdefは識別子として使えない。Ergには予約語がないため、一部の記号を除くすべてのシンボルが識別子として使える。 51 | * 名前(Name): 識別子とほぼ同じ意味。Ergにおいては代数と同じ意味で使われることもある。 52 | * 代数名(Algebra name): Ergにおいては識別子と同等の意味。C言語では関数名は識別子だが代数名ではない。「代数」は`=`(変数代入演算子)または`=`(定数代入演算子)でオブジェクトを代入できるという言語機能自体を指す。 53 | 54 | ```erg 55 | 代数名 <: (名前 == 識別子) <: シンボル 56 | 変数 + 定数 == 代数 57 | ``` 58 | 59 | ただし、本来「代数」と呼ばれるべきものは「変数」と呼ばれる場合が多い。これは数学用語の影響である。 60 | 値の内容が変わりうる変数はミュータブル変数、値の内容が変わらない変数はイミュータブル変数である。 61 | なお、定数は必ずイミュータブルである。 62 | 63 | Ergでは代数名、名前は使用せず、識別子で統一する。 64 | ただし一般的には`v = 1`の`v`は「変数v」("Variable v")と呼び、`C = 1`の`C`は「定数C」("Constant C")と呼ぶ。 65 | 66 | ## 属性、フィールド、プロパティ(Attribute, Field, Property) 67 | 68 | Attribute、属性を使用する。 69 | 因みにレコードはクラス無しで要素属性のあるオブジェクトを定義できる機能のことである。 70 | 71 | ## 適用(Application)、呼び出し(Call) 72 | 73 | サブルーチンオブジェクトに引数を与えて結果を得ること。 74 | 呼び出し(Call)を使用する。Applicationは「応用ソフトウェア」の用法があるためである。 75 | 76 | ## 配列(Array)、リスト(List) 77 | 78 | Arrayを使用する。Ergの配列は(一般的には)メモリ上で連続的に配置されるからである。 79 | Listはいわゆる連結リスト、またはPythonのデータ型としてのリストを指すこととする。 80 | 81 | ## プロシージャ、手続き 82 | 83 | プロシージャに統一する。サブルーチンは関数(と演算子)、プロシージャ、メソッドの総称。Callableはさらに`__call__`を実装しているものすべて。 84 | 85 | ## ラムダ関数、ラムダ式、匿名関数、無名関数 86 | 87 | 無名関数で統一する。英語では字数短縮のためLambdaを使用してよいが、正式名はAnonymous functionである。 88 | また、Ergの無名関数は匿名なわけではないので、匿名関数は使わない。 89 | -------------------------------------------------------------------------------- /doc/EN/faq_technical.md: -------------------------------------------------------------------------------- 1 | # Technical FAQ 2 | 3 | This section answers technical questions about using the Erg language. In other words, it contains questions that begin with What or Which, and questions that can be answered with Yes/No. 4 | 5 | For more information on how the grammar was determined, see [here](./dev_guide/faq_syntax.md) for the underlying syntax decisions, and [here](./dev_guide/../faq_general.md). 6 | 7 | ## Is there an exception mechanism in Erg? 8 | 9 | A: No. Erg uses the `Result` type instead. See [here](./dev_guide/faq_syntax.md) for why Erg does not have an exception mechanism. 10 | 11 | ## Does Erg have a type equivalent to TypeScript's `Any`? 12 | 13 | A: No, there is not. All objects belong to at least the `Object` class, but this type only provides a minimal set of attributes, so you can't do whatever you want with it like you can with Any. 14 | The `Object` class is converted to the desired type through dynamic inspection by `match`, etc. It is the same kind of `Object` in Java and other languages. 15 | In the Erg world, there is no chaos and hopelessness like in TypeScript, where the API definition is ``Any''. 16 | 17 | ## What is the difference between Never, {}, None, (), NotImplemented, and Ellipsis? 18 | 19 | A: `Never` is an "impossible" type. A subroutine that produces a runtime error has `Never` (or a merger type of `Never`) as its return type. The program will stop as soon as it detects this. Although the `Never` type is by definition also a subclass of all types, `Never` type objects never appear in Erg code and are never created. `{}` is equivalent to `Never`. 20 | `Ellipsis` is an object that represents an ellipsis, and comes from Python. 21 | `NotImplemented` is also from Python. It is used as a marker for not implemented, but Erg prefers the `todo` function which produces an error. 22 | `None` is an instance of `NoneType`. It is often used with the `Option` type. 23 | `()` is a unit type and an instance of itself. It is used when you want to return a "meaningless value" such as the return value of a procedure. 24 | 25 | ## Why is `x = p!()` valid but `f() = p!()` causes an EffectError? 26 | 27 | `!` is not a marker for the product of a side-effect, but for an object that can cause a side-effect. 28 | Procedure `p!` and mutable type `T!` can cause side effects, but if the return value of `p!()`, for example, is of type `Int`, it itself no longer causes side effects. 29 | -------------------------------------------------------------------------------- /doc/JA/syntax/25_object_system.md: -------------------------------------------------------------------------------- 1 | # Object(対象体) 2 | 3 | 変数に代入できる全てのデータ。`Object`クラスの持つ属性は以下の通り。 4 | 5 | * `.__repr__`: オブジェクトの(リッチでない)文字列表現を返す 6 | * `.__sizeof__`: オブジェクトのサイズ(ヒープ確保分含む)を返す 7 | * `.__dir__`: オブジェクトの属性を一覧にして返す 8 | * `.__hash__`: オブジェクトのハッシュ値を返す 9 | * `.__getattribute__`: オブジェクトの属性を取得して返す 10 | * `.clone`: オブジェクトのクローン(メモリ上に独立な実体を持つ)を生成して返す 11 | * `.copy`: オブジェクトのコピー(メモリ上で同じものをさす)を返す 12 | 13 | ## Record(レコード) 14 | 15 | レコードリテラル(`{attr = value; ...}`)で生成されるオブジェクト。 16 | このオブジェクトは`.clone`や`.__sizeof__`などの基本的なメソッドを持つ。 17 | 18 | ```erg 19 | obj = {.x = 1} 20 | assert obj.x == 1 21 | 22 | obj2 = {...x; .y = 2} 23 | assert obj2.x == 1 and obj2.y == 2 24 | ``` 25 | 26 | ## Attribute(属性) 27 | 28 | オブジェクトと関連付けられたオブジェクト。特に自身(`self`)を暗黙の第一引数にとるサブルーチン属性はメソッド(method)と呼ばれる。 29 | 30 | ```erg 31 | # private_attrには`.`がないことに注意 32 | record = {.public_attr = j; private_attr = 2; .method = self -> self.i + 1} 33 | record.public_attr == 2 34 | record.private_attr # AttributeError: private_attr is private 35 | assert record.method() == 3 36 | ``` 37 | 38 | ## Element(要素) 39 | 40 | 特定の型に属するオブジェクト(e.g. `1`は`Int`型の要素)。全てのオブジェクトは、少なくとも`{=}`型の要素である。 41 | クラスの要素の場合特にインスタンス(Instance)と呼ぶこともある。 42 | 43 | ## Subroutine(サブルーチン) 44 | 45 | 関数またはプロシージャのインスタンスであるオブジェクトを示す(メソッドも含む)。サブルーチンを表すクラスは`Subroutine`である。 46 | より一般に`.__call__`を実装するオブジェクトは`Callable`(呼び出し可能オブジェクト)と呼ばれる。 47 | 48 | ## Callable(呼び出し可能オブジェクト) 49 | 50 | `.__call__`を実装するオブジェクト。`Subroutine`のスーパークラス。 51 | 52 | ## Type(型) 53 | 54 | 要求属性を定義し、オブジェクトを共通化するオブジェクト。 55 | 大きく分けて多相型(Polymorphic Type)と単相型(Monomorphic Type)の2つがある。典型的な単相型は`Int`, `Str`などで、多相型には`Option Int`, `[Int; 3]`などがある。 56 | さらにオブジェクトの状態変更をするメソッドを定義した型は可変型(Mutable type)と呼ばれ、可変な属性に`!`をつける必要がある(e.g. 動的配列: `[T; !_]`)。 57 | 58 | ## Class(クラス) 59 | 60 | `.__new__`, `.__init__`メソッドなどを持つ型。クラスベースのオブジェクト指向を実現する。 61 | 62 | ## Function(関数、写像) 63 | 64 | 外部変数(静的変数除く)のread権限はあるが、外部変数のread/write権限がないサブルーチン。つまり、外部に副作用を及ぼせない。 65 | Ergの関数(Function)は副作用を許さないのでPythonのそれとは定義が異なる。 66 | 67 | ## Procedure(手続) 68 | 69 | 外部変数のread権限および`self`、静的変数のread/write権限があり、全てのサブルーチンの使用が許可されている。外部に副作用を及ぼせる。 70 | 71 | ## Method(メソッド) 72 | 73 | 第一引数に`self`を暗黙的にとるサブルーチン。単なる関数/プロシージャとは別の型となっている。 74 | 75 | ## Entity(エンティティ) 76 | 77 | サブルーチンおよび型ではないオブジェクト。 78 | 単相型エンティティ(`1`, `"a"`など)は値オブジェクト、多相型エンティティ(`[1, 2, 3], {"a": 1}`)はコンテナオブジェクトとも呼ばれる。 79 | 80 |

81 | Previous | Next 82 |

83 | -------------------------------------------------------------------------------- /doc/JA/syntax/type/advanced/shared.md: -------------------------------------------------------------------------------- 1 | # 共有参照(Shared Reference) 2 | 3 | 共有参照は気をつけて扱わねばならない言語機能の一つです。 4 | 例えばTypeScriptでは以下のようなコードが型検査を通ってしまいます。 5 | 6 | ```typescript 7 | class NormalMember {} 8 | class VIPMember extends NormalMember {} 9 | 10 | let vip_area: VIPMember[] = [] 11 | let normal_area: NormalMember[] = vip_area 12 | 13 | normal_area.push(new NormalMember()) 14 | console.log(vip_area) # [NormalMember] 15 | ``` 16 | 17 | 一般会員がVIPエリアに侵入してしまっています。これは明らかなバグですが、何がいけなかったのでしょうか。 18 | 原因は共有参照の[変性](./variance.md)です。`normal_area`は`vip_area`をコピーして作成されていますが、その際に型が変わってしまっています。 19 | しかし`VIPMember`は`NormalMember`を継承しているので`VIPMember[] <: NormalMember[]`となり、これは問題ないとされてしまっているのです。 20 | `VIPMember[] <: NormalMember[]`という関係は、不変オブジェクトの場合は問題ありません。しかし上のように破壊的な操作を行ってしまうと、綻びが発生します。 21 | 22 | Ergでは、所有権システムのおかげでこのようなコードは弾かれます。 23 | 24 | ```erg 25 | NormalMember = Class() 26 | VIPMember = Class() 27 | 28 | vip_area = [].into [VIPMember; !_] 29 | normal_area: [NormalMember; !_] = vip_area 30 | 31 | normal_area.push!(NormalMember.new()) 32 | log vip_area # OwnershipError: `vip_room` was moved to `normal_room` 33 | ``` 34 | 35 | しかし、オブジェクトの所有権が一箇所にしかない状態は不便である場合もあります。 36 | そのためにErgは`SharedCell! T!`という型があり、これが共有状態を表します。 37 | 38 | ```erg 39 | $p1 = SharedCell!.new(!1) 40 | $p2 = $p1.mirror!() 41 | $p3 = SharedCell!.new(!1) 42 | # $p1 == $p2とすると、中身の型Int!の比較が行われる 43 | assert $p1 == $p2 44 | assert $p1 == $p3 45 | # $p1と$p2が同じものを指しているかは、`.addr!`で確認する 46 | assert $p1.addr!() == $p2.addr!() 47 | assert $p1.addr!() != $p3.addr!() 48 | $p1.add! 1 49 | assert $p1 == 2 50 | assert $p2 == 2 51 | assert $p3 == 1 52 | ``` 53 | 54 | `SharedCell!`型のオブジェクトは先頭に`$`を付ける必要があります。また、その性質上、定数にすることはできません。 55 | 56 | `SharedCell! T!`型は`T!`型のサブタイプでもあり、`T!`型のメソッドを呼び出すことができます。`SharedCell! T!`型固有のメソッドは`.addr!`と`.mirror!`、`.try_take`のみです。 57 | 58 | 重要な事実として、`SharedCell! T!`は非変(non-variant)です。すなわち、型引数の違いによる包含関係が定義されません。 59 | 60 | ```erg 61 | $vip_area = SharedCell!.new([].into [VIPMember; !_]) 62 | $normal_area: SharedCell!([NormalMember; !_]) = $vip_area.mirror!() # TypeError: expected SharedCell!([NormalMember; !_]), but got SharedCell!([VIPMember; !_]) 63 | # hint: SharedCell!(T) is non-variant, which means it cannot have a supertype or a subtype. 64 | ``` 65 | 66 | しかし、以下のコードは問題ありません。最後の行では、型変換されたのは引数の`VIPMember`の方です。 67 | 68 | ```erg 69 | $normal_area = SharedCell!.new([].into [NormalMember; !_]) 70 | $normal_area.push!(NormalMember.new()) # OK 71 | $normal_area.push!(VIPMember.new()) # OK 72 | ``` 73 | -------------------------------------------------------------------------------- /doc/EN/syntax/27_comprehension.md: -------------------------------------------------------------------------------- 1 | # Comprehension 2 | 3 | An array can be created by `[expr | (name <- iterable)+ (predicate)*]`, 4 | And a set can be created by `{expr | (name <- iterable)+ (predicate)*}`. 5 | 6 | Dict can be created by `{key: value | (name <- iterable)+ (predicate)*}`. 7 | 8 | The first part of a clause delimited by `|` is called a layout clause, the second part is called a bind clause, and the third part is called a guard clause. 9 | The guard clause can be omitted, but not the bind clause, and the guard clause cannot be placed before the bind clause. 10 | 11 | e.g. 12 | 13 | ```erg 14 | assert [i | i <- [0, 1, 2]] == [0, 1, 2]] 15 | assert [i / 2 | i <- 0..2] == [0.0, 0.5, 1.0]] 16 | assert [(i, j) | i <- 0..2; j <- 0..2; (i + j) % 2 == 0] == [(0, 0), (0, 2), (1, 1), (2, 0), (2, 2)] 17 | assert {i % 2 | i <- 0..9} == {0, 1} 18 | assert {k: v | k <- ["a", "b"]; v <- [1, 2]} == {"a": 1, "b": 2} 19 | ``` 20 | 21 | Erg's comprehension notation is influenced by Haskell, but there are some differences. 22 | In Haskell's list comprehensions, the order of variables makes a difference in the result, but not in Erg. 23 | 24 | ```haskell 25 | -- Haskell 26 | [(i, j) | i <- [1..3], j <- [3..5]] == [(1,3),(1,4),(1,5),(2,3),(2,4),(2,5),(3,3),(3,4),(3,5)] 27 | [(i, j) | j <- [3..5], i <- [1..3]] == [(1,3),(2,3),(3,3),(1,4),(2,4),(3,4),(1,5),(2,5),(3,5)] 28 | ``` 29 | 30 | ```erg 31 | # Erg 32 | assert [(i, j) | i <- 1. <3; j <- 3.. <5] == [(i, j) | j <- 3.. <5; i <- 1.. <3] 33 | ``` 34 | 35 | これはPythonと同じである。 36 | 37 | ```python 38 | # Python 39 | assert [(i, j) for i in range(1, 3) for j in range(3, 5)] == [(i, j) for j in range(3, 5) for i in range(1, 3)] 40 | ``` 41 | 42 | ## Refinement type 43 | 44 | Similar to comprehensions are refinement types. A refinement type is a type (enumerated type) in the form `{Name: Type | Predicate}`. 45 | In the case of a refinement type, Name is limited to one and the layout cannot be specified (but multiple values can be handled by using a tuple type, for example), and Predicate must be a compile-time computation, i.e., a constant expression. 46 | 47 | ```erg 48 | Nat = {I: Int | I >= 0} 49 | # If the predicate expression is and only, it can be replaced by ;. 50 | # Nat2D = {(I, J): (Int, Int) | I >= 0; J >= 0} 51 | Nat2D = {(I, J): (Int, Int) | I >= 0 and J >= 0} 52 | ``` 53 | 54 |

55 | Previous | Next 56 |

57 | -------------------------------------------------------------------------------- /doc/JA/compiler/trait_method_resolving.md: -------------------------------------------------------------------------------- 1 | # パッチメソッドの解決 2 | 3 | `Nat`は0以上の`Int`、つまり`Int`のサブタイプである。 4 | 本来`Nat`はPythonのクラス階層には存在しない。Ergはこのパッチのメソッドをどうやって解決するのだろうか? 5 | 6 | ```erg 7 | 1.times do 8 | log "hello, world" 9 | ``` 10 | 11 | `.times`は`NatImpl`のパッチメソッドである。 12 | `1`は`Int`のインスタンスであるので、まず`Int`のMRO(Method Resolution Order)を辿って探索する。 13 | Ergは`Int`のMROに`Int`, `Object`を持っている。これはPython由来である(Pythonにおいて`int.__mro__ == [int, object]`)。 14 | `.times`メソッドはそのどちらにも存在しない。ここからは、そのサブタイプの探索に入る。 15 | 16 | ~ 17 | 18 | 整数は明らかにその上位型に実数や複素数、ひいては数全体を持つはずだが、Pythonと互換性をもつレイヤーではその事実は現れない。 19 | だが実際にErgでは`1 in Complex`や`1 in Num`は`True`となる。 20 | `Complex`に至っては、`Int`と継承関係にないクラスであるのに、型として互換性があると判断されている。一体どうなっているのか。 21 | 22 | ~ 23 | 24 | あるオブジェクトに対して、その属する型は無数に存在する。 25 | だが実際に考えなくてはならないのはメソッドを持つ型、すなわち名前を持つ型のみである。 26 | 27 | Ergコンパイラは、全ての提供メソッドとその実装を持つパッチ・型のハッシュマップを持っている。 28 | このテーブルは型が新たに定義されるたびに更新される。 29 | 30 | ```erg 31 | provided_method_table = { 32 | ... 33 | "foo": [Foo], 34 | ... 35 | ".times": [Nat, Foo], 36 | ... 37 | } 38 | ``` 39 | 40 | `.times`メソッドを持つ型は`Nat`, `Foo`である。これらの中から、`{1}`型に適合するものを探す。 41 | 適合判定は二種類ある。篩型判定とレコード型判定である。篩型判定から行われる。 42 | 43 | ## 篩型判定 44 | 45 | 候補の型が`1`の型`{1}`と互換性があるか確認する。篩型の中で`{1}`と互換性があるのは、`{0, 1}`, `0..9`などである。 46 | `0..1 or 3..4`, `-1..2 and 0..3`などの有限要素の代数演算型は、基底型として宣言すると篩型に正規化される(つまり、`{0, 1, 3, 4}`, `{0, 1, 2}`にする)。 47 | 今回の場合、`Nat`は`0.._ == {I: Int | I >= 0}`であるので、`{1}`は`Nat`と互換性がある。 48 | 49 | ## レコード型判定 50 | 51 | 候補の型が1のクラスである`Int`と互換性を持つか確認する。 52 | その他、`Int`のパッチである、またその要求属性を`Int`がすべて持つ場合も互換性がある。 53 | 54 | ~ 55 | 56 | というわけで、`Nat`が適合した。ただ`Foo`も適合してしまった場合は、`Nat`と`Foo`の包含関係によって判定される。 57 | すなわち、サブタイプのメソッドが選択される。 58 | 両者に包含関係がない場合は、コンパイルエラーとなる(これはプログラマーの意図に反したメソッドが実行されないための安全策である)。 59 | エラーを解消させるためには、パッチを明示的に指定する必要がある。 60 | 61 | ```erg 62 | o.method(x) -> P.method(o, x) 63 | ``` 64 | 65 | ## 全称パッチのメソッド解決 66 | 67 | 以下のようなパッチを定義する。 68 | 69 | ```erg 70 | FnType T: Type = Patch T -> T 71 | FnType.type = T 72 | ``` 73 | 74 | `FnType`パッチのもとで以下のようなコードが可能である。これはどのように解決されるのだろうか。 75 | 76 | ```erg 77 | assert (Int -> Int).type == Int 78 | ``` 79 | 80 | まず、`provided_method_table`には`FnType(T)`が以下の形式で登録される。 81 | 82 | ```erg 83 | provided_method_table = { 84 | ... 85 | "type": [FnType(T)], 86 | ... 87 | } 88 | ``` 89 | 90 | `FnType(T)`のパッチする型が適合するかチェックされる。この場合、`FnType(T)`のパッチ型は`Type -> Type`である。 91 | これは`Int -> Int`に適合する。適合したら、単相化を行って置換する(`T -> T`と`Int -> Int`のdiffを取る。`{T => Int}`)。 92 | 93 | ```erg 94 | assert FnType(Int).type == Int 95 | ``` 96 | -------------------------------------------------------------------------------- /doc/JA/syntax/type/advanced/typeof.md: -------------------------------------------------------------------------------- 1 | # Typeof, classof 2 | 3 | `Typeof`はErgの型推論システムを覗くことができる関数であり、その挙動は複雑である。 4 | 5 | ```erg 6 | assert Typeof(1) == {I: Int | I == 1} 7 | i: 1..3 or 5..10 = ... 8 | assert Typeof(i) == {I: Int | (I >= 1 and I <= 3) or (I >= 5 and I <= 10)} 9 | 10 | C = Class {i = Int} 11 | I = C.new {i = 1} 12 | assert Typeof(I) == {X: C | X == I} 13 | J: C = ... 14 | assert Typeof(J) == {i = Int} 15 | 16 | assert {X: C | X == I} < C and C <= {i = Int} 17 | ``` 18 | 19 | `Typeof`関数ではオブジェクトのクラスではなく構造型が返される。 20 | なので、`C = Class T`なるクラスのインスタンス`I: C`に対しては`Typeof(I) == T`となる。 21 | 値クラスに関しては本来対応するレコード型が存在しない。この問題を解消するため、値クラスは`__valueclass_tag__`属性を持っているレコード型ということになっている。 22 | なお、この属性にアクセスすることはできず、ユーザー定義型で`__valueclass_tag__`属性を定義することもできない。 23 | 24 | ```erg 25 | i: Int = ... 26 | assert Typeof(i) == {__valueclass_tag__ = Phantom Int} 27 | s: Str = ... 28 | assert Typeof(s) == {__valueclass_tag__ = Phantom Str} 29 | ``` 30 | 31 | `Typeof`で出力されるのは構造型のみである。構造型には属性型と篩型、(真の)代数演算型があると説明した。 32 | これらは独立な型(推論の優先順位が存在する)であり、推論の重解は発生しない。 33 | 属性型、代数演算型は複数のクラスにまたがる可能性があるが、篩型は単一のクラスのサブタイプである。 34 | Ergは可能な限りオブジェクトの型を篩型として推論し、それができなくなった際は篩型のベースクラスを構造化(後述)した型に拡大する。 35 | 36 | ## 構造化 37 | 38 | すべてのクラスは構造型に変換することができる。これを __構造化__ という。クラスの構造化された型は`Structure`関数で取得できる。 39 | クラスが`C = Class T`で定義されているとき(すべてのクラスはこの形式で定義されている)、`Structure(C) == T`になる。 40 | 41 | ```erg 42 | C = Class {i = Int} 43 | assert Structure(C) == {i = Int} 44 | D = Inherit C 45 | assert Structure(D) == {i = Int} 46 | Nat = Class {I: Int | I >= 0} 47 | assert Structure(Nat) == {I: Int | I >= 0} 48 | Option T = Class (T or NoneType) 49 | assert Structure(Option Int) == Or(Int, NoneType) 50 | assert Structure(Option) # TypeError: only monomorphized types can be structurized 51 | # 実際には__valueclass_tag__を持つレコードは定義できないが、概念上はこうなる 52 | assert Structure(Int) == {__valueclass_tag__ = Phantom Int} 53 | assert Structure(Str) == {__valueclass_tag__ = Phantom Str} 54 | assert Structure((Nat, Nat)) == {__valueclass_tag__ = Phantom(Tuple(Nat, Nat))} 55 | assert Structure(Nat -> Nat) == {__valueclass_tag__ = Phantom(Func(Nat, Nat))} 56 | # マーカークラスも__valueclass_tag__を持つレコード型になる 57 | M = Inherit Marker 58 | assert Structure(M) == {__valueclass_tag__ = Phantom M} 59 | D = Inherit(C and M) 60 | assert Structure(D) == {i = Int; __valueclass_tag__ = Phantom M} 61 | E = Inherit(Int and M) 62 | assert Structure(E) == {__valueclass_tag__ = Phantom(And(Int, M))} 63 | F = Inherit(E not M) 64 | assert Structure(F) == {__valueclass_tag__ = Phantom Int} 65 | ``` 66 | -------------------------------------------------------------------------------- /doc/JA/syntax/29_decorator.md: -------------------------------------------------------------------------------- 1 | # デコレータ(修飾子) 2 | 3 | デコレータは型や関数に特定の状態や振る舞いを追加したり明示するために使われます。 4 | デコレータの文法は以下の通りです。 5 | 6 | ```erg 7 | @deco 8 | X = ... 9 | ``` 10 | 11 | デコレータは、競合しない限り複数つけることができます。 12 | 13 | デコレータは特別なオブジェクトではなく、その実体は単なる1引数関数です。デコレータは以下の疑似コードと等価です。 14 | 15 | ```erg 16 | X = ... 17 | X = deco(X) 18 | ``` 19 | 20 | Ergでは変数の再代入が出来ないので、上のようなコードは通らず、デコレータが必要なのです。 21 | 以下に、頻出の組み込みデコレータを紹介します。 22 | 23 | ## Inheritable 24 | 25 | 定義する型が継承可能クラスであることを示します。引数`scope`に`"public"`を指定すると、外部モジュールのクラスでも継承できるようになります。デフォルトでは`"private"`になっており、外部からは継承できません。 26 | 27 | ## Final 28 | 29 | メソッドをオーバーライド不能にします。クラスに付けると継承不能クラスになりますが、デフォルトなので意味はありません。 30 | 31 | ## Override 32 | 33 | 属性をオーバーライドする際に使用します。Ergではデフォルトで基底クラスと同じ属性を定義しようとするとエラーになります。 34 | 35 | ## Impl 36 | 37 | 引数のトレイトを実装することを示します。 38 | 39 | ```erg 40 | Add = Trait { 41 | .`_+_` = Self.(Self) -> Self 42 | } 43 | Sub = Trait { 44 | .`_-_` = Self.(Self) -> Self 45 | } 46 | 47 | C = Class({i = Int}, Impl: Add and Sub) 48 | C. 49 | @Impl Add 50 | `_+_` self, other = C.new {i = self::i + other::i} 51 | @Impl Sub 52 | `_-_` self, other = C.new {i = self::i - other::} 53 | ``` 54 | 55 | ## Attach 56 | 57 | トレイトにデフォルトで付属するアタッチメントパッチを指定します。 58 | これによって、Rustのトレイトと同じ挙動を再現できます。 59 | 60 | ```erg 61 | # foo.er 62 | Add R, O = Trait { 63 | .`_+_` = Self.(R) -> O 64 | } 65 | @Attach IntIsBinAdd, OddIsBinAdd 66 | BinAdd = Subsume Add(Self, Self.AddO), { 67 | .AddO = Type 68 | } 69 | 70 | IntIsBinAdd = Patch(Int, Impl: BinAdd) 71 | IntIsBinAdd.AddO = Int 72 | OddIsBinAdd = Patch(Odd, Impl: BinAdd) 73 | OddIsBinAdd.AddO = Even 74 | ``` 75 | 76 | こうすると、他のモジュールからトレイトをインポートした際に、アタッチメントパッチが自動で適用されます。 77 | 78 | ```erg 79 | # 本来IntIsBinAdd, OddIsBinAddも同時にインポートする必要があるが、アタッチメントパッチなら省略可 80 | {BinAdd; ...} = import "foo" 81 | 82 | assert Int.AddO == Int 83 | assert Odd.AddO == Even 84 | ``` 85 | 86 | 内部的にはトレイトの`.attach`メソッドを使って結びつけているだけです。コンフリクトする場合はトレイトの`.detach`メソッドで外すことができます。 87 | 88 | ```erg 89 | @Attach X 90 | T = Trait ... 91 | assert X in T.attaches 92 | U = T.detach(X).attach(Y) 93 | assert X not in U.attaches 94 | assert Y in U.attaches 95 | ``` 96 | 97 | ## Deprecated 98 | 99 | 変数の仕様が古く非推奨であることを示します。 100 | 101 | ## Test 102 | 103 | テスト用サブルーチンであることを示します。テスト用サブルーチンは`erg test`コマンドで実行されます。 104 | 105 |

106 | Previous | Next 107 |

108 | -------------------------------------------------------------------------------- /doc/JA/syntax/type/13_algebraic.md: -------------------------------------------------------------------------------- 1 | # Algebraic type (代数演算型) 2 | 3 | 代数演算型は、型を代数のようにみなして演算を施すことで生成される型のことです。 4 | 代数演算型が扱う演算は、Union, Intersection, Diff, Complementなどがあります。 5 | 通常のクラスはUnionのみが行えて、他の演算は型エラーになります。 6 | 7 | ## Union 8 | 9 | Union型では型について複数の可能性を与える事ができる。名前の通り、`or`演算子で生成されます。 10 | 代表的なUnionは`Option`型です。`Option`型は`T or NoneType`のpatch typeで、主に失敗するかもしれない値を表現します。 11 | 12 | ```erg 13 | IntOrStr = Int or Str 14 | assert dict.get("some key") in (Int or NoneType) 15 | 16 | # 暗黙に`T != NoneType`となる 17 | Option T = T or NoneType 18 | ``` 19 | 20 | ## Intersection 21 | 22 | Intersection型は型同士を`and`演算で結合して得られます。 23 | 24 | ```erg 25 | Num = Add and Sub and Mul and Eq 26 | ``` 27 | 28 | 先述したように通常のクラス同士では`and`演算で結合できません。インスタンスは唯一つのクラスに属するからです。 29 | 30 | ## Diff 31 | 32 | Diff型は`not`演算で得られます。 33 | 英文に近い表記としては`and not`とした方が良いですが、`and`, `or`と並べて収まりが良いので`not`だけで使うのが推奨されます。 34 | 35 | ```erg 36 | CompleteNum = Add and Sub and Mul and Div and Eq and Ord 37 | Num = CompleteNum not Div not Ord 38 | 39 | True = Bool not {False} 40 | OneTwoThree = {1, 2, 3, 4, 5, 6} - {4, 5, 6, 7, 8, 9, 10} 41 | ``` 42 | 43 | ## Complement 44 | 45 | Complementは`not`演算で得られますが、これは単項演算です。`not T`型は`{=} not T`の短縮記法です。 46 | `not T`型によるIntersectionはDiffと同等で、`not T`型によるDiffはIntersectionと同等です。 47 | しかしこのような書き方は推奨されません。 48 | 49 | ```erg 50 | # the simplest definition of the non-zero number type 51 | NonZero = Not {0} 52 | # deprecated styles 53 | {True} == Bool and not {False} # 1 == 2 + - 1 54 | Bool == {True} not not {False} # 2 == 1 - -1 55 | ``` 56 | 57 | ## 真の代数演算型 58 | 59 | 代数演算型には、簡約可能な見かけ上の代数演算型とそれ以上簡約できない「真の代数演算型」があります。 60 | そうではない「見かけの代数型」には、Enum型やInterval型、レコード型の`or`や`and`があります。 61 | これらは簡約が可能なので真の代数演算型ではなく、型指定に使うとWarningが出ます。Warningを消すためには簡約化するか型定義を行うかする必要があります。 62 | 63 | ```erg 64 | assert {1, 2, 3} or {2, 3} == {1, 2, 3} 65 | assert {1, 2, 3} and {2, 3} == {2, 3} 66 | assert -2..-1 or 1..2 == {-2, -1, 1, 2} 67 | 68 | i: {1, 2} or {3, 4} = 1 # TypeWarning: {1, 2} or {3, 4} can be simplified to {1, 2, 3, 4} 69 | p: {x = Int, ...} and {y = Int; ...} = {x = 1; y = 2; z = 3} 70 | # TypeWaring: {x = Int, ...} and {y = Int; ...} can be simplified to {x = Int; y = Int; ...} 71 | 72 | Point1D = {x = Int; ...} 73 | Point2D = Point1D and {y = Int; ...} # == {x = Int; y = Int; ...} 74 | q: Point2D = {x = 1; y = 2; z = 3} 75 | ``` 76 | 77 | 真の代数演算型には、`Or`型、`And`型があります。クラス同士の`or`などは`Or`型です。 78 | 79 | ```erg 80 | assert Int or Str == Or(Int, Str) 81 | assert Int and Marker == And(Int, Marker) 82 | ``` 83 | 84 | Diff, Complement型は必ず簡約できるので真の代数演算型ではありません。 85 | -------------------------------------------------------------------------------- /doc/JA/python/bytecode_specification.md: -------------------------------------------------------------------------------- 1 | # Python bytecode specification 2 | 3 | ## Format 4 | 5 | * 0~3 byte(u32): magic number (see common/bytecode.rs for details) 6 | * 4~7 byte(u32): 0 padding 7 | * 8~12 byte(u32): timestamp 8 | * 13~ byte(PyCodeObject): code object 9 | 10 | ## PyCodeObject 11 | 12 | * 0 byte(u8): '0xe3' (this means code's 'c') 13 | * 01~04 byte(u32): number of args (co_argcount) 14 | * 05~08 byte(u32): number of position-only args (co_posonlyargcount) 15 | * 09~12 byte(u32): number of keyword-only args (co_kwonlyargcount) 16 | * 13~16 byte(u32): number of locals (co_nlocals) 17 | * 17~20 byte(u32): stack size (co_stacksize) 18 | * 21~24 byte(u32): flags (co_flags) () 19 | * ? byte: bytecode instructions, ends with '0x53', '0x0' (83, 0): RETURN_VALUE (co_code) 20 | * ? byte(PyTuple): constants used in the code (co_consts) 21 | * ? byte(PyTuple): names used in the code (co_names) 22 | * ? byte(PyTuple): variable names defined in the code, include params (PyTuple) (co_varnames) 23 | * ? byte(PyTuple): variables captured from the outer scope (co_freevars) 24 | * ? byte(PyTuple): variables used in the inner closure (co_cellvars) 25 | * ? byte(PyUnicode or PyShortAscii): file name, where it was loaded from (co_filename) 26 | * ? byte(PyUnicode or PyShortAscii): the name of code itself, default is \ (co_name) 27 | * ?~?+3 byte(u32): number of first line (co_firstlineno) 28 | * ? byte(bytes): line table, represented by PyStringObject? (co_lnotab) 29 | 30 | ## PyTupleObject 31 | 32 | * 0 byte: 0x29 (means ')') 33 | * 01~04 byte(u32): number of tuple items 34 | * ? byte(PyObject): items 35 | 36 | ## PyStringObject 37 | 38 | ** ascii以外の文字を使うとPyUnicodeになる? 39 | ** "あ", "𠮷", "α"だとPyUnicodeになった(もう使われていない?) 40 | 41 | * 0 byte: 0x73 (means 's') 42 | * 1~4 byte: length of string 43 | * 5~ byte: payload 44 | 45 | ## PyUnicodeObject 46 | 47 | * 0 byte: 0x75 (means 'u') 48 | * 1~4 byte: length of string 49 | * 5~ byte: payload 50 | 51 | ## PyShortAsciiObject 52 | 53 | ** shortと言っているが、100文字以上あってもこれになる 54 | ** というかshortじゃないasciiはない(shortはデータ型?) 55 | 56 | * 0 byte: 0xFA (means 'z') 57 | * 1~4 byte: length of string 58 | * 5~ byte: payload 59 | 60 | ## PyInternedObject 61 | 62 | ** intern化したオブジェクトは専用のmapに登録され、isで比較できるようになる 63 | ** 例えば文字列などが長さに関係なく定数時間で比較できる 64 | 65 | * 0 byte: 0x74 (means 't') 66 | 67 | ## PyShortAsciiInternedObject 68 | 69 | * 0 byte: 0xDA (means 'Z') 70 | * 1~4 byte: length of string 71 | * 5~ byte: payload 72 | -------------------------------------------------------------------------------- /doc/EN/syntax/type/16_subtyping.md: -------------------------------------------------------------------------------- 1 | # Subtyping 2 | 3 | In Erg, class inclusion can be determined with the comparison operators `<`, `>`. 4 | 5 | ```erg 6 | Nat < Int 7 | Int < Object 8 | 1... _ < Nat 9 | {1, 2} > {1} 10 | {=} > {x = Int} 11 | {I: Int | I >= 1} < {I: Int | I >= 0} 12 | ``` 13 | 14 | Note that this has a different meaning than the `<:` operator. It declares that the class on the left-hand side is a subtype of the type on the right-hand side, and is meaningful only at compile-time. 15 | 16 | ```erg 17 | C <: T # T: StructuralType 18 | f|D <: E| ... 19 | 20 | assert F < G 21 | ``` 22 | 23 | You can also specify `Self <: Add` for a polymorphic subtype specification, for example ``Self(R, O) <: Add(R, O)``. 24 | 25 | ## Structural types and class type relationships 26 | 27 | Structural types are types for structural typing and are considered to be the same object if they have the same structure. 28 | 29 | ```erg 30 | T = Structural {i = Int} 31 | U = Structural {i = Int} 32 | 33 | assert T == U 34 | t: T = {i = 1} 35 | assert t in T 36 | assert t in U 37 | ``` 38 | 39 | In contrast, classes are types for notational typing and cannot be compared structurally to types and instances. 40 | 41 | ```erg 42 | C = Class {i = Int} 43 | D = Class {i = Int} 44 | 45 | assert C == D # TypeError: cannot compare classes 46 | c = C.new {i = 1} 47 | assert c in C 48 | assert not c in D 49 | ``` 50 | 51 | ## Subtyping of subroutines 52 | 53 | Arguments and return values of subroutines take only a single class. 54 | In other words, you cannot directly specify a structural type or a trace as the type of a function. 55 | It must be specified as "a single class that is a subtype of that type" using the partial type specification. 56 | 57 | ```erg 58 | # OK 59 | f1 x, y: Int = x + y 60 | # NG 61 | f2 x, y: Add = x + y 62 | # OK 63 | # A is some concrete class 64 | f3 x, y: A = x + y 65 | ``` 66 | 67 | Type inference in subroutines also follows this rule. When a variable in a subroutine has an unspecified type, the compiler first checks to see if it is an instance of one of the classes, and if not, looks for a match in the scope of the trace. If it still cannot find one, a compile error occurs. This error can be resolved by using a structural type, but since inferring an anonymous type may have unintended consequences for the programmer, it is designed to be explicitly specified by the programmer with `Structural`. 68 | 69 | ## Class upcasting 70 | 71 | ```erg 72 | i: Int 73 | i as (Int or Str) 74 | i as (1..10) 75 | i as {I: Int | I >= 0} 76 | ``` 77 | -------------------------------------------------------------------------------- /doc/EN/syntax/type/14_dependent.md: -------------------------------------------------------------------------------- 1 | # Dependent Types 2 | 3 | Dependent types are one of the most important features of Erg. 4 | Dependent types are types that take values as arguments. Normal polymorphic types can take only types as arguments, but dependent types loosen that restriction. 5 | 6 | Dependent types, such as `[T; N]`(`Array(T, N)`), are equivalent. 7 | This type depends not only on the type `T` of the contents, but also on the number `N` of the contents. `N` contains objects of type `Nat`. 8 | 9 | ```erg 10 | a1 = [1, 2, 3]. 11 | assert a1 in [Nat; 3]. 12 | a2 = [4, 5, 6, 7] 13 | assert a1 in [Nat; 4]. 14 | assert a1 + a2 in [Nat; 7]. 15 | ``` 16 | 17 | If the type object passed as a function argument is related to a return type, write the following 18 | 19 | ```erg 20 | narray: |N: Nat| {N} -> [{N}; N] 21 | narray(N: Nat): [N; N] = [N; N] 22 | assert narray(3) == [3, 3, 3]. 23 | ``` 24 | 25 | When defining a dependent type, all type arguments must be constants. 26 | 27 | Dependent types already exist in some languages, but Erg has the unique feature of allowing you to define procedural methods on dependent types. 28 | 29 | ```erg 30 | x = 1 31 | f x = 32 | print! f::x, module::x 33 | 34 | # Phantom types have an attribute called Phantom that has the same value as the type argument 35 | T X: Int = Class Impl: Phantom X 36 | T(X). 37 | x self = self::Phantom 38 | 39 | T(1).x() # 1 40 | ``` 41 | 42 | Type arguments of variable-dependent types can be transitioned by applying methods. 43 | Transitions are specified with `~>`. 44 | 45 | ```erg 46 | # Note that `Id` is an immutable type and cannot be transitioned. 47 | VM!(State: {"stopped", "running"}! |= _, Id: Nat |= _) = Class(... State). 48 | VM!(). 49 | # Variables that do not change can be omitted by passing `_`. 50 | start! ref! self("stopped" ~> "running") = 51 | self.initialize_something! 52 | self::set_phantom!("running") 53 | 54 | # You can also cut out each type argument (only within the defined module) 55 | VM!.new() = VM!(!" stopped", 1).new() 56 | VM!("running" ~> "running").stop! ref! self = 57 | self.close_something!() 58 | self::set_phantom!("stopped")) 59 | 60 | vm = VM!.new() 61 | vm.start!() 62 | vm.stop!() 63 | vm.stop!() # TypeError: VM! stopped", 1) doesn't have .stop! 64 | # TypeError: VM! running", 1) has .stop! 65 | ``` 66 | 67 | You can also create dependent types by incorporating or inheriting from existing types. 68 | 69 | ```erg 70 | MyArray(T, N) = Inherit [T; N]. 71 | 72 | # type of self: Self(T, N) in conjunction with .array! 73 | MyStruct!(T, N: Nat!) = Class {.array: [T; !N]} 74 | ``` 75 | --------------------------------------------------------------------------------

61 | Previous | Next 62 |