Merge branch 'main' into clippy

This commit is contained in:
Shunsuke Shibayama 2022-08-17 01:26:00 +09:00 committed by GitHub
commit 4e91cb81cb
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
57 changed files with 1541 additions and 715 deletions

17
CONTRIBUTING.md Normal file
View file

@ -0,0 +1,17 @@
# Contributing to Erg
## Documents
If you are thinking of contributing to Erg, or are interested in the internal structure of Erg, you can take a look at the documents under [doc/dev_guide](./doc/JA/dev_guide/) (currently only Japanese).
## Bug reports
If you find any behavior that you think is a bug in Erg, I would appreciate it if you would [report](https://github.com/erg-lang/erg/issues/new/choose) it. Please make sure that the same bug has not already been reported as an issue.
If you type `cargo run --features debug`, Erg will be built in debug mode. This mode may dump information that may be useful for investigating bugs. I would appreciate it if you could report error logs in this mode.
Also, the environment in which the bug occurred need not be reported if it is clear that the bug was not caused by the environment.
## Asking questions
If you have any questions, please feel free to ask them on the [Discord channel](https://discord.gg/zfAAUbgGr4).

View file

@ -1,6 +1,6 @@
[package] [package]
name = "erg" name = "erg"
version = "0.2.2" version = "0.2.4"
description = "The Erg programming language" description = "The Erg programming language"
authors = ["Shunsuke Shibayama <sbym1346@gmail.com>"] authors = ["Shunsuke Shibayama <sbym1346@gmail.com>"]
license = "MIT OR Apache-2.0" license = "MIT OR Apache-2.0"
@ -31,9 +31,9 @@ japanese = [
] ]
[dependencies] [dependencies]
erg_common = { version = "0.2.2", path = "./compiler/erg_common" } erg_common = { version = "0.2.4", path = "./compiler/erg_common" }
erg_parser = { version = "0.2.2", path = "./compiler/erg_parser" } erg_parser = { version = "0.2.4", path = "./compiler/erg_parser" }
erg_compiler = { version = "0.2.2", path = "./compiler/erg_compiler" } erg_compiler = { version = "0.2.4", path = "./compiler/erg_compiler" }
# [workspace] # [workspace]
# member = ["cm", "dyne"] # member = ["cm", "dyne"]

View file

@ -4,7 +4,7 @@
<img width="500" src="./assets/erg_logo_with_slogan.svg"> <img width="500" src="./assets/erg_logo_with_slogan.svg">
</div> </div>
<br>[Erg](https://erg-lang.github.io/) is a statically typed language that is Python compatible. <br>[Erg](https://erg-lang.github.io/) is a statically typed language that is Python-compatible.
<p align='center'> <p align='center'>
<img alt="Build status" src="https://github.com/erg-lang/erg/actions/workflows/rust.yml/badge.svg"> <img alt="Build status" src="https://github.com/erg-lang/erg/actions/workflows/rust.yml/badge.svg">
@ -14,7 +14,7 @@
## Erg can be recommended to a person that&colon; ## Erg can be recommended to a person that&colon;
* uses Python, but want Rust-like robustness and comfortable compiler support. * uses Python, but wants Rust-like robustness and comfortable compiler support.
* and yet, doesn't need the verbose type specifications & memory management model like Rust. * and yet, doesn't need the verbose type specifications & memory management model like Rust.
* wants a simple and consistent language like ML. * wants a simple and consistent language like ML.
* wants a practical general-purpose language with dependent/refinement types. * wants a practical general-purpose language with dependent/refinement types.
@ -26,7 +26,7 @@
1. Robustness 1. Robustness
Erg has a smart & powerful type system. For example, Erg can do null checking (Option type), division by zero and out-of-range addresses in arrays at compile time. Erg has a smart & powerful type system. For example, Erg can do null checking (Option type), division by zero, and out-of-range addresses in arrays at compile time.
```python ```python
rand = pyimport "random" rand = pyimport "random"
@ -102,6 +102,7 @@
# SyntaxError: cannot call a procedural method in a function # SyntaxError: cannot call a procedural method in a function
# hint: only methods of mutable types can change the state of objects # hint: only methods of mutable types can change the state of objects
# Code that uses a lot of side effects is redundant, so you will naturally write pure code
Counter! = Inherit Int! Counter! = Inherit Int!
Counter!. Counter!.
new i: Int = Self!::__new__ !i new i: Int = Self!::__new__ !i
@ -146,7 +147,7 @@
3│ l.push!(x) 3│ l.push!(x)
^^^^^ ^^^^^
AttributeError: Array object has no attribute `.push!` AttributeError: Array object has no attribute `.push!`
hint: in order to update the internal state of an object, make it mutable by using `!` operator hint: to update the internal state of an object, make it mutable by using `!` operator
hint: `Array` has `push`, see https://erg-lang.github.io/docs/prelude/Array/##push for more information hint: `Array` has `push`, see https://erg-lang.github.io/docs/prelude/Array/##push for more information
hint: `Array!` has `push!`, see https://erg-lang.github.io/docs/prelude/Array!/##push! for more information hint: `Array!` has `push!`, see https://erg-lang.github.io/docs/prelude/Array!/##push! for more information
``` ```

View file

@ -100,6 +100,7 @@
# SyntaxError: 関数の中でプロシージャルメソッドは呼び出せません # SyntaxError: 関数の中でプロシージャルメソッドは呼び出せません
# ヒント: 可変型メソッドだけがオブジェクトの状態を変更できます # ヒント: 可変型メソッドだけがオブジェクトの状態を変更できます
# 副作用を多用するコードは自然と冗長になるため、自然と純粋なコードを書くように動機づけられます
Counter! = Inherit Int! Counter! = Inherit Int!
Counter!. Counter!.
new i: Int = Self!::__new__ !i new i: Int = Self!::__new__ !i

View file

@ -55,7 +55,7 @@
* [ ] Mutable type * [ ] Mutable type
* [x] Dependent mutable method * [x] Dependent mutable method
* [x] Projection type * [x] Projection type
* [ ] Polymorphic projection type * [ ] Polymorphic projection-type
* [x] Subtyping * [x] Subtyping
* [x] Refinement subtyping * [x] Refinement subtyping
* [x] Nominal subtyping * [x] Nominal subtyping
@ -70,13 +70,13 @@
* [x] procedure call * [x] procedure call
* [ ] mutable type * [ ] mutable type
* [x] Implement reference types (for methods) * [x] Implement reference types (for methods)
* [ ] Implement a ownership checker * [ ] Implement an ownership checker
* [x] Implement a move checker * [x] Implement a move checker
* [x] Implement a borrow checker * [x] Implement a borrow checker
* [ ] Implement a cycle-reference detector * [ ] Implement a cycle-reference detector
* [ ] Implement a compiletime evaluator * [ ] Implement a compile-time evaluator
* [ ] Compiletime operator * [ ] Compiletime operator
* [ ] Compiletime function * [ ] Compile-time function
* [ ] Maintain unit tests * [ ] Maintain unit tests
* [ ] Implement a Python parser * [ ] Implement a Python parser
* [ ] Make code readable * [ ] Make code readable

Binary file not shown.

Before

Width:  |  Height:  |  Size: 62 KiB

After

Width:  |  Height:  |  Size: 128 KiB

Before After
Before After

View file

@ -1 +1 @@
<?xml version="1.0" encoding="UTF-8"?><svg id="a" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 146.66 112.27"><defs><style>.b{fill:#040000;}.c{fill:none;}</style></defs><polygon class="c" points="10.39 108.82 30.02 108.82 44.25 57.86 24.62 57.86 10.39 108.82"/><polygon class="c" points="94.93 54.41 114.3 54.41 128.54 3.45 109.17 3.45 94.93 54.41"/><g><polygon class="c" points="10.39 108.82 30.02 108.82 44.25 57.86 24.62 57.86 10.39 108.82"/><polygon class="c" points="94.93 54.41 114.3 54.41 128.54 3.45 109.17 3.45 94.93 54.41"/><path class="b" d="M132.48,0h-34.41l-.96,3.45-14.24,50.96H30.34L44.58,3.45h34.68l.96-3.45H34.08c-2.12,0-3.97,1.41-4.54,3.45h0L15.3,54.41l-.96,3.45L.1,108.81h0c-.48,1.73,.82,3.45,2.62,3.45H48.86l.96-3.45,14.23-50.95h52.26l-14.23,50.95h-34.41l-.96,3.45h45.87c2.12,0,3.97-1.41,4.54-3.45l15.2-54.41L146.55,3.45h0c.48-1.73-.82-3.45-2.62-3.45h-11.46ZM34.77,108.81H15.14l14.23-50.95h19.63l-14.23,50.95ZM117.28,54.41h-19.37L112.14,3.45h19.37l-14.24,50.96Z"/></g></svg> <?xml version="1.0" encoding="UTF-8"?><svg id="_イヤー_1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1055.93 808.51"><defs><style>.cls-1{fill:#1c1d1d;}</style></defs><path class="cls-1" d="M1036.36,.1h-233.99v-.03c-172.6,.39-385.88-.28-557.01,0-15.23,0-28.6,10.14-32.7,24.82L110.17,391.8l-6.95,24.86L.73,783.54c-3.49,12.49,5.9,24.86,18.87,24.86,46.01,.34,143.88-.24,190.45,0v.03c179.69-.17,422.65,.12,600.48,0,15.24,0,28.61-10.15,32.71-24.82,52.7-189.01,159.36-570.2,211.94-758.69h0c3.48-12.47-5.89-24.82-18.83-24.82ZM320.95,24.89h72.86v.03h305.34l-102.5,366.92h-128.51v-.03H218.45L320.95,24.89Zm-109.45,391.78h141.34l-102.49,366.87H109.02l102.49-366.87Zm523.47,366.9h-247.75v.02h-128.52s102.49-366.88,102.49-366.89h376.27l-102.49,366.87Zm109.43-391.73h-139.46L807.44,24.92h139.46l-102.5,366.92Z"/><rect class="cls-1" x="156.88" y="360.45" width="742.17" height="87.6"/><rect class="cls-1" x="248.38" y=".07" width="742.17" height="87.6"/><rect class="cls-1" x="70.13" y="720.83" width="742.17" height="87.6"/></svg>

Before

Width:  |  Height:  |  Size: 997 B

After

Width:  |  Height:  |  Size: 1 KiB

Before After
Before After

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 9.1 KiB

After

Width:  |  Height:  |  Size: 9.3 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 136 KiB

After

Width:  |  Height:  |  Size: 132 KiB

Before After
Before After

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 9.3 KiB

After

Width:  |  Height:  |  Size: 9.5 KiB

Before After
Before After

21
cargo_publish.bat Normal file
View file

@ -0,0 +1,21 @@
@echo off
if %~dp0 == C:%homepath%\GitHub\erg\ (
cd compiler/erg_common
echo publish erg_common ...
cargo publish
timeout 20
cd ../erg_parser
echo publish erg_parser ...
cargo publish
timeout 20
cd ../erg_compiler
echo publish erg_compiler ...
cargo publish
timeout 20
cd ../../
cargo publish
echo completed
) else (
echo Use this command in the project root
)

0
cargo_publish.sh Normal file
View file

View file

@ -1,6 +1,6 @@
[package] [package]
name = "erg_common" name = "erg_common"
version = "0.2.2" version = "0.2.4"
description = "A common components library of Erg" description = "A common components library of Erg"
authors = ["Shunsuke Shibayama <sbym1346@gmail.com>"] authors = ["Shunsuke Shibayama <sbym1346@gmail.com>"]
license = "MIT OR Apache-2.0" license = "MIT OR Apache-2.0"

View file

@ -126,9 +126,15 @@ impl HasType for CodeObj {
fn ref_t(&self) -> &Type { fn ref_t(&self) -> &Type {
&Type::Code &Type::Code
} }
fn ref_mut_t(&mut self) -> &mut Type {
todo!()
}
fn signature_t(&self) -> Option<&Type> { fn signature_t(&self) -> Option<&Type> {
None None
} }
fn signature_mut_t(&mut self) -> Option<&mut Type> {
None
}
} }
impl fmt::Debug for CodeObj { impl fmt::Debug for CodeObj {

View file

@ -317,7 +317,7 @@ impl ErrorCore {
} }
pub fn unreachable(fn_name: &str, line: u32) -> Self { pub fn unreachable(fn_name: &str, line: u32) -> Self {
Self::bug(0, Location::Unknown, fn_name, line) Self::bug(line as usize, Location::Unknown, fn_name, line)
} }
pub fn bug(errno: usize, loc: Location, fn_name: &str, line: u32) -> Self { pub fn bug(errno: usize, loc: Location, fn_name: &str, line: u32) -> Self {

View file

@ -299,14 +299,12 @@ pub trait ImmutableStream<T>: Sized {
// for Runnable::run // for Runnable::run
fn expect_block(src: &str) -> bool { fn expect_block(src: &str) -> bool {
src.ends_with(&['=', ':']) src.ends_with(&['=', ':'])
|| src.ends_with(":=")
|| src.ends_with("->") || src.ends_with("->")
|| src.ends_with("=>") || src.ends_with("=>")
|| src.ends_with("do")
|| src.ends_with("do!")
} }
/// this trait implements REPL (Read-Eval-Print-Loop) automatically /// This trait implements REPL (Read-Eval-Print-Loop) automatically
/// The `exec` method is called for file input, etc.
pub trait Runnable: Sized { pub trait Runnable: Sized {
type Err: ErrorDisplay; type Err: ErrorDisplay;
type Errs: MultiErrorDisplay<Self::Err>; type Errs: MultiErrorDisplay<Self::Err>;
@ -316,6 +314,7 @@ pub trait Runnable: Sized {
fn finish(&mut self); // called when the :exit command is received. fn finish(&mut self); // called when the :exit command is received.
fn clear(&mut self); fn clear(&mut self);
fn eval(&mut self, src: Str) -> Result<String, Self::Errs>; fn eval(&mut self, src: Str) -> Result<String, Self::Errs>;
fn exec(&mut self) -> Result<(), Self::Errs>;
fn ps1(&self) -> String { fn ps1(&self) -> String {
">>> ".to_string() ">>> ".to_string()
@ -333,13 +332,7 @@ pub trait Runnable: Sized {
let mut instance = Self::new(cfg); let mut instance = Self::new(cfg);
let res = match instance.input() { let res = match instance.input() {
Input::File(_) | Input::Pipe(_) | Input::Str(_) => { Input::File(_) | Input::Pipe(_) | Input::Str(_) => {
match instance.eval(instance.input().read()) { instance.exec()
Ok(s) => {
println!("{s}");
Ok(())
}
Err(e) => Err(e),
}
} }
Input::REPL => { Input::REPL => {
let output = stdout(); let output = stdout();
@ -497,6 +490,9 @@ pub trait HasType {
fn ref_t(&self) -> &Type; fn ref_t(&self) -> &Type;
// 関数呼び出しの場合、.ref_t()は戻り値を返し、signature_t()は関数全体の型を返す // 関数呼び出しの場合、.ref_t()は戻り値を返し、signature_t()は関数全体の型を返す
fn signature_t(&self) -> Option<&Type>; fn signature_t(&self) -> Option<&Type>;
// 最後にHIR全体の型変数を消すために使う
fn ref_mut_t(&mut self) -> &mut Type;
fn signature_mut_t(&mut self) -> Option<&mut Type>;
#[inline] #[inline]
fn t(&self) -> Type { fn t(&self) -> Type {
self.ref_t().clone() self.ref_t().clone()

View file

@ -42,30 +42,35 @@ fn reorder_by_key<T: Eq, U>(mut g: Graph<T, U>, idx: Vec<T>) -> Graph<T, U> {
g g
} }
fn dfs<T: Eq + Hash + Clone, U>(g: &Graph<T, U>, v: T, used: &mut Set<T>, idx: &mut Vec<T>) { fn dfs<T: Eq + Hash + Clone, U>(g: &Graph<T, U>, v: T, used: &mut Set<T>, idx: &mut Vec<T>) -> Result<(), ()> {
used.insert(v.clone()); used.insert(v.clone());
for node_id in g.iter().find(|n| n.id == v).unwrap().depends_on.iter() { for node_id in g.iter().find(|n| n.id == v).unwrap().depends_on.iter() {
// detecting cycles
if used.contains(node_id) && !idx.contains(node_id) {
return Err(());
}
if !used.contains(node_id) { if !used.contains(node_id) {
dfs(g, node_id.clone(), used, idx); dfs(g, node_id.clone(), used, idx)?;
} }
} }
idx.push(v); idx.push(v);
Ok(())
} }
/// perform topological sort on a graph /// perform topological sort on a graph
pub fn tsort<T: Eq + Hash + Clone, U>(g: Graph<T, U>) -> Graph<T, U> { pub fn tsort<T: Eq + Hash + Clone, U>(g: Graph<T, U>) -> Result<Graph<T, U>, ()> {
let n = g.len(); let n = g.len();
let mut idx = Vec::with_capacity(n); let mut idx = Vec::with_capacity(n);
let mut used = Set::new(); let mut used = Set::new();
for v in g.iter() { for v in g.iter() {
if !used.contains(&v.id) { if !used.contains(&v.id) {
dfs(&g, v.id.clone(), &mut used, &mut idx); dfs(&g, v.id.clone(), &mut used, &mut idx)?;
} }
} }
reorder_by_key(g, idx) Ok(reorder_by_key(g, idx))
} }
fn _test() { fn _test() -> Result<(), ()> {
let v = vec!["e", "d", "b", "a", "c"]; let v = vec!["e", "d", "b", "a", "c"];
let idx = vec![3, 2, 4, 1, 0]; let idx = vec![3, 2, 4, 1, 0];
assert_eq!(vec!["a", "b", "c", "d", "e"], _reorder_by_idx(v, idx)); assert_eq!(vec!["a", "b", "c", "d", "e"], _reorder_by_idx(v, idx));
@ -83,5 +88,6 @@ fn _test() {
on_2.clone(), on_2.clone(),
]; ];
let dag = vec![en_0, o0_1, on_2, e0_3, ond_4]; let dag = vec![en_0, o0_1, on_2, e0_3, ond_4];
assert_eq!(sorted, tsort(dag)); assert_eq!(sorted, tsort(dag)?);
Ok(())
} }

View file

@ -89,10 +89,15 @@ pub trait HasLevel {
// REVIEW: TyBoundと微妙に役割が被っている // REVIEW: TyBoundと微妙に役割が被っている
#[derive(Debug, Clone, PartialEq, Eq, Hash)] #[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum Constraint { pub enum Constraint {
/// :> T
SupertypeOf(Type), SupertypeOf(Type),
/// <: T
SubtypeOf(Type), SubtypeOf(Type),
/// :> Sub, <: Sup
Sandwiched { sub: Type, sup: Type }, Sandwiched { sub: Type, sup: Type },
/// : T
TypeOf(Type), TypeOf(Type),
Uninited,
} }
impl fmt::Display for Constraint { impl fmt::Display for Constraint {
@ -102,11 +107,20 @@ impl fmt::Display for Constraint {
Self::SubtypeOf(sup) => write!(f, "<: {sup}"), Self::SubtypeOf(sup) => write!(f, "<: {sup}"),
Self::Sandwiched { sub, sup } => write!(f, ":> {sub}, <: {sup}"), Self::Sandwiched { sub, sup } => write!(f, ":> {sub}, <: {sup}"),
Self::TypeOf(ty) => write!(f, ": {}", ty), Self::TypeOf(ty) => write!(f, ": {}", ty),
Self::Uninited => write!(f, "<uninited>"),
} }
} }
} }
impl Constraint { impl Constraint {
pub const fn sandwiched(sub: Type, sup: Type) -> Self {
Self::Sandwiched { sub, sup }
}
pub const fn is_uninited(&self) -> bool {
matches!(self, Self::Uninited)
}
pub fn typ(&self) -> Option<&Type> { pub fn typ(&self) -> Option<&Type> {
match self { match self {
Self::TypeOf(ty) => Some(ty), Self::TypeOf(ty) => Some(ty),
@ -114,6 +128,13 @@ impl Constraint {
} }
} }
pub fn sub_type(&self) -> Option<&Type> {
match self {
Self::SupertypeOf(ty) => Some(ty),
_ => None,
}
}
pub fn super_type(&self) -> Option<&Type> { pub fn super_type(&self) -> Option<&Type> {
match self { match self {
Self::SubtypeOf(ty) => Some(ty), Self::SubtypeOf(ty) => Some(ty),
@ -269,7 +290,23 @@ impl<T: Clone + HasLevel> Free<T> {
} }
} }
pub fn unwrap(self) -> T { pub fn get_name(&self) -> Option<Str> {
match self.0.clone_inner() {
FreeKind::Linked(_) => panic!("the value is linked"),
FreeKind::Unbound { .. } => None,
FreeKind::NamedUnbound { name, .. } => Some(name),
}
}
pub fn unwrap_unbound(self) -> (Option<Str>, usize, Constraint) {
match self.0.clone_inner() {
FreeKind::Linked(_) => panic!("the value is linked"),
FreeKind::Unbound { constraint, lev, .. } => (None, lev, constraint),
| FreeKind::NamedUnbound { name, lev, constraint } => (Some(name), lev, constraint),
}
}
pub fn unwrap_linked(self) -> T {
match self.0.clone_inner() { match self.0.clone_inner() {
FreeKind::Linked(t) => t, FreeKind::Linked(t) => t,
FreeKind::Unbound { .. } | FreeKind::NamedUnbound { .. } => { FreeKind::Unbound { .. } | FreeKind::NamedUnbound { .. } => {
@ -289,6 +326,14 @@ impl<T: Clone + HasLevel> Free<T> {
}) })
} }
pub fn crack_constraint(&self) -> Ref<'_, Constraint> {
Ref::map(self.0.borrow(), |f| match f {
FreeKind::Linked(_) => panic!("the value is linked"),
FreeKind::Unbound { constraint, .. }
| FreeKind::NamedUnbound { constraint, .. } => constraint,
})
}
pub fn type_of(&self) -> Option<Type> { pub fn type_of(&self) -> Option<Type> {
self.0.borrow().constraint().and_then(|c| c.typ().cloned()) self.0.borrow().constraint().and_then(|c| c.typ().cloned())
} }
@ -307,6 +352,30 @@ impl<T: Clone + HasLevel> Free<T> {
) )
} }
pub fn constraint_is_typeof(&self) -> bool {
matches!(
&*self.0.borrow(),
FreeKind::Unbound { constraint, .. }
| FreeKind::NamedUnbound { constraint, .. } if constraint.typ().is_some()
)
}
pub fn constraint_is_supertypeof(&self) -> bool {
matches!(
&*self.0.borrow(),
FreeKind::Unbound { constraint, .. }
| FreeKind::NamedUnbound { constraint, .. } if constraint.sub_type().is_some()
)
}
pub fn constraint_is_subtypeof(&self) -> bool {
matches!(
&*self.0.borrow(),
FreeKind::Unbound { constraint, .. }
| FreeKind::NamedUnbound { constraint, .. } if constraint.super_type().is_some()
)
}
pub fn is_linked(&self) -> bool { pub fn is_linked(&self) -> bool {
matches!(&*self.0.borrow(), FreeKind::Linked(_)) matches!(&*self.0.borrow(), FreeKind::Linked(_))
} }
@ -812,6 +881,13 @@ impl TyParam {
_ => true, _ => true,
} }
} }
pub fn update_constraint(&self, new_constraint: Constraint) {
match self {
Self::Type(t) => { t.update_constraint(new_constraint) },
_ => {}
}
}
} }
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
@ -824,6 +900,7 @@ pub enum TyParamOrdering {
NotEqual, // Less or Greater NotEqual, // Less or Greater
GreaterEqual, // Greater or Equal GreaterEqual, // Greater or Equal
Any, Any,
NoRelation,
} }
use TyParamOrdering::*; use TyParamOrdering::*;
@ -877,7 +954,7 @@ impl TyParamOrdering {
GreaterEqual => LessEqual, GreaterEqual => LessEqual,
Equal => NotEqual, Equal => NotEqual,
NotEqual => Equal, NotEqual => Equal,
Any => Any, Any | NoRelation => Any,
} }
} }
} }
@ -1692,6 +1769,8 @@ pub enum Type {
}, // e.g. T.U }, // e.g. T.U
ASTOmitted, // call中のcalleeの型など、不要な部分に付ける ASTOmitted, // call中のcalleeの型など、不要な部分に付ける
Failure, // when failed to infer Failure, // when failed to infer
/// used to represent `TyParam` is not initialized (see `erg_compiler::context::instantiate_tp`)
Uninited,
} }
impl fmt::Display for Type { impl fmt::Display for Type {
@ -1802,6 +1881,10 @@ impl HasType for Type {
fn ref_t(&self) -> &Type { fn ref_t(&self) -> &Type {
self self
} }
#[inline]
fn ref_mut_t(&mut self) -> &mut Type {
self
}
fn inner_ts(&self) -> Vec<Type> { fn inner_ts(&self) -> Vec<Type> {
match self { match self {
Self::Ref(t) | Self::RefMut(t) | Self::VarArgs(t) => { Self::Ref(t) | Self::RefMut(t) | Self::VarArgs(t) => {
@ -1817,6 +1900,9 @@ impl HasType for Type {
fn signature_t(&self) -> Option<&Type> { fn signature_t(&self) -> Option<&Type> {
None None
} }
fn signature_mut_t(&mut self) -> Option<&mut Type> {
None
}
} }
impl HasLevel for Type { impl HasLevel for Type {
@ -2044,7 +2130,7 @@ impl Type {
Self::poly("Iter", vec![TyParam::t(t)]) Self::poly("Iter", vec![TyParam::t(t)])
} }
pub fn refer(t: Type) -> Self { pub fn ref_(t: Type) -> Self {
Self::Ref(Box::new(t)) Self::Ref(Box::new(t))
} }
@ -2315,6 +2401,14 @@ impl Type {
Self::Quantified(QuantifiedType::new(unbound_t, bounds)) Self::Quantified(QuantifiedType::new(unbound_t, bounds))
} }
pub fn is_mono_q(&self) -> bool {
match self {
Self::FreeVar(fv) if fv.is_linked() => fv.crack().is_mono_q(),
Self::MonoQVar(_) => true,
_ => false,
}
}
pub fn mutate(self) -> Self { pub fn mutate(self) -> Self {
match self { match self {
Self::Int => Self::IntMut, Self::Int => Self::IntMut,
@ -2403,10 +2497,14 @@ impl Type {
pub fn rec_eq(&self, other: &Self) -> bool { pub fn rec_eq(&self, other: &Self) -> bool {
match (self, other) { match (self, other) {
(Self::FreeVar(v), other) | (other, Self::FreeVar(v)) => match &*v.borrow() { (Self::FreeVar(v), other) => match &*v.borrow() {
FreeKind::Linked(t) => t.rec_eq(other), FreeKind::Linked(t) => t.rec_eq(other),
_ => self == other, _ => self == other,
}, },
(self_, Self::FreeVar(v)) => match &*v.borrow() {
FreeKind::Linked(t) => t.rec_eq(self_),
_ => self_ == other,
},
(Self::Ref(l), Self::Ref(r)) | (Self::RefMut(l), Self::RefMut(r)) => l.rec_eq(r), (Self::Ref(l), Self::Ref(r)) | (Self::RefMut(l), Self::RefMut(r)) => l.rec_eq(r),
(Self::Subr(l), Self::Subr(r)) => { (Self::Subr(l), Self::Subr(r)) => {
match (&l.kind, &r.kind) { match (&l.kind, &r.kind) {
@ -2578,6 +2676,7 @@ impl Type {
Self::MonoProj { .. } => "MonoProj", Self::MonoProj { .. } => "MonoProj",
Self::ASTOmitted => "ASTOmitted", Self::ASTOmitted => "ASTOmitted",
Self::Failure => "<Failure>", Self::Failure => "<Failure>",
Self::Uninited => "<Uninited>",
} }
} }
@ -2662,7 +2761,7 @@ impl Type {
pub fn typarams(&self) -> Vec<TyParam> { pub fn typarams(&self) -> Vec<TyParam> {
match self { match self {
Self::FreeVar(f) if f.is_linked() => f.crack().typarams(), Self::FreeVar(f) if f.is_linked() => f.crack().typarams(),
Self::FreeVar(_unbound) => todo!(), Self::FreeVar(_unbound) => vec![],
Self::Ref(t) | Self::RefMut(t) => vec![TyParam::t(*t.clone())], Self::Ref(t) | Self::RefMut(t) => vec![TyParam::t(*t.clone())],
Self::And(param_ts) | Self::Or(param_ts) | Self::Not(param_ts) => { Self::And(param_ts) | Self::Or(param_ts) | Self::Not(param_ts) => {
param_ts.iter().map(|t| TyParam::t(t.clone())).collect() param_ts.iter().map(|t| TyParam::t(t.clone())).collect()
@ -2745,6 +2844,13 @@ impl Type {
_ => None, _ => None,
} }
} }
pub fn update_constraint(&self, new_constraint: Constraint) {
match self {
Self::FreeVar(fv) => { fv.update_constraint(new_constraint); },
_ => {},
}
}
} }
pub mod type_constrs { pub mod type_constrs {
@ -2770,6 +2876,11 @@ pub mod type_constrs {
Type::mono_q(name) Type::mono_q(name)
} }
#[inline]
pub fn mono_proj<S: Into<Str>>(lhs: Type, rhs: S) -> Type {
Type::mono_proj(lhs, rhs)
}
#[inline] #[inline]
pub fn poly<S: Into<Str>>(name: S, params: Vec<TyParam>) -> Type { pub fn poly<S: Into<Str>>(name: S, params: Vec<TyParam>) -> Type {
Type::poly(name, params) Type::poly(name, params)
@ -2890,6 +3001,7 @@ impl From<&Type> for TypeCode {
"Proc" => Self::Proc, "Proc" => Self::Proc,
_ => Self::Other, _ => Self::Other,
}, },
Type::Refinement(refine) => Self::from(&*refine.t),
_ => Self::Other, _ => Self::Other,
} }
} }
@ -3148,6 +3260,8 @@ impl TypePair {
{ {
Self::ProcProc Self::ProcProc
} }
(Type::Refinement(refine), r) => Self::new(&*refine.t, r),
(l, Type::Refinement(refine)) => Self::new(l, &*refine.t),
(_, _) => Self::Others, (_, _) => Self::Others,
} }
} }

View file

@ -233,6 +233,9 @@ impl HasType for ValueObj {
fn ref_t(&self) -> &Type { fn ref_t(&self) -> &Type {
panic!("cannot get reference of the const") panic!("cannot get reference of the const")
} }
fn ref_mut_t(&mut self) -> &mut Type {
panic!("cannot get mutable reference of the const")
}
/// その要素だけの集合型を返す、クラスが欲しい場合は.classで /// その要素だけの集合型を返す、クラスが欲しい場合は.classで
#[inline] #[inline]
fn t(&self) -> Type { fn t(&self) -> Type {
@ -246,6 +249,9 @@ impl HasType for ValueObj {
fn signature_t(&self) -> Option<&Type> { fn signature_t(&self) -> Option<&Type> {
None None
} }
fn signature_mut_t(&mut self) -> Option<&mut Type> {
None
}
} }
impl ValueObj { impl ValueObj {

View file

@ -1,6 +1,6 @@
[package] [package]
name = "erg_compiler" name = "erg_compiler"
version = "0.2.2" version = "0.2.4"
description = "Centimetre: the Erg compiler" description = "Centimetre: the Erg compiler"
authors = ["Shunsuke Shibayama <sbym1346@gmail.com>"] authors = ["Shunsuke Shibayama <sbym1346@gmail.com>"]
license = "MIT OR Apache-2.0" license = "MIT OR Apache-2.0"
@ -15,8 +15,8 @@ debug = [ "erg_common/debug", "erg_parser/debug" ]
japanese = [ "erg_common/japanese", "erg_parser/japanese" ] japanese = [ "erg_common/japanese", "erg_parser/japanese" ]
[dependencies] [dependencies]
erg_common = { version = "0.2.2", path = "../erg_common" } erg_common = { version = "0.2.4", path = "../erg_common" }
erg_parser = { version = "0.2.2", path = "../erg_parser" } erg_parser = { version = "0.2.4", path = "../erg_parser" }
[lib] [lib]
path = "lib.rs" path = "lib.rs"

View file

@ -130,6 +130,10 @@ impl Runnable for Compiler {
self.code_generator.clear(); self.code_generator.clear();
} }
fn exec(&mut self) -> Result<(), Self::Errs> {
todo!()
}
fn eval(&mut self, src: Str) -> Result<String, CompileErrors> { fn eval(&mut self, src: Str) -> Result<String, CompileErrors> {
let codeobj = self.compile(src, "eval")?; let codeobj = self.compile(src, "eval")?;
Ok(codeobj.code_info()) Ok(codeobj.code_info())

File diff suppressed because it is too large Load diff

View file

@ -48,10 +48,10 @@ impl SideEffectChecker {
self.check_def(def, true); self.check_def(def, true);
} }
Expr::Call(call) => { Expr::Call(call) => {
for parg in call.args.pos_args().iter() { for parg in call.args.pos_args.iter() {
self.check_expr(&parg.expr, true); self.check_expr(&parg.expr, true);
} }
for kwarg in call.args.kw_args().iter() { for kwarg in call.args.kw_args.iter() {
self.check_expr(&kwarg.expr, true); self.check_expr(&kwarg.expr, true);
} }
} }
@ -169,11 +169,11 @@ impl SideEffectChecker {
.push(EffectError::has_effect(expr, self.full_path())); .push(EffectError::has_effect(expr, self.full_path()));
} }
call.args call.args
.pos_args() .pos_args
.iter() .iter()
.for_each(|parg| self.check_expr(&parg.expr, allow_self_effect)); .for_each(|parg| self.check_expr(&parg.expr, allow_self_effect));
call.args call.args
.kw_args() .kw_args
.iter() .iter()
.for_each(|kwarg| self.check_expr(&kwarg.expr, allow_self_effect)); .for_each(|kwarg| self.check_expr(&kwarg.expr, allow_self_effect));
} }

View file

@ -64,9 +64,9 @@ pub fn readable_name(name: &str) -> &str {
"__pow__" => "`**`", "__pow__" => "`**`",
"__mod__" => "`%`", "__mod__" => "`%`",
"__rng__" => "`..`", "__rng__" => "`..`",
"__lrng__" => "`<..`", "__lorng__" => "`<..`",
"__rrng__" => "`..<`", "__rorng__" => "`..<`",
"__lrrng__" => "`<..<`", "__orng__" => "`<..<`",
"__and__" => "`and`", "__and__" => "`and`",
"__or__" => "`or`", "__or__" => "`or`",
"__in__" => "`in`", "__in__" => "`in`",
@ -373,7 +373,6 @@ impl TyCheckError {
expect: &Type, expect: &Type,
found: &Type, found: &Type,
) -> Self { ) -> Self {
let name = readable_name(name);
Self::new(ErrorCore::new(0, TypeError, loc, switch_lang!( Self::new(ErrorCore::new(0, TypeError, loc, switch_lang!(
format!("the type of {name} is mismatched:\nexpected: {GREEN}{expect}{RESET}\nbut found: {RED}{found}{RESET}"), format!("the type of {name} is mismatched:\nexpected: {GREEN}{expect}{RESET}\nbut found: {RED}{found}{RESET}"),
format!("{name}の型が違います。\n予期した型: {GREEN}{expect}{RESET}\n与えられた型: {RED}{found}{RESET}") format!("{name}の型が違います。\n予期した型: {GREEN}{expect}{RESET}\n与えられた型: {RED}{found}{RESET}")
@ -387,7 +386,6 @@ impl TyCheckError {
expect: &Type, expect: &Type,
found: &Type, found: &Type,
) -> Self { ) -> Self {
let name = readable_name(name);
Self::new(ErrorCore::new(0, TypeError, loc, switch_lang!( Self::new(ErrorCore::new(0, TypeError, loc, switch_lang!(
format!("the return type of {name} is mismatched:\nexpected: {GREEN}{expect}{RESET}\nbut found: {RED}{found}{RESET}"), format!("the return type of {name} is mismatched:\nexpected: {GREEN}{expect}{RESET}\nbut found: {RED}{found}{RESET}"),
format!("{name}の戻り値の型が違います。\n予期した型: {GREEN}{expect}{RESET}\n与えられた型: {RED}{found}{RESET}") format!("{name}の戻り値の型が違います。\n予期した型: {GREEN}{expect}{RESET}\n与えられた型: {RED}{found}{RESET}")
@ -395,7 +393,6 @@ impl TyCheckError {
} }
pub fn uninitialized_error(loc: Location, caused_by: Str, name: &str, t: &Type) -> Self { pub fn uninitialized_error(loc: Location, caused_by: Str, name: &str, t: &Type) -> Self {
let name = readable_name(name);
Self::new( Self::new(
ErrorCore::new( ErrorCore::new(
0, 0,
@ -450,6 +447,15 @@ impl TyCheckError {
) )
} }
pub fn dummy_infer_error(fn_name: &str, line: u32) -> Self {
Self::new(ErrorCore::unreachable(fn_name, line), "".into())
}
pub fn not_relation(fn_name: &str, line: u32) -> Self {
Self::new(ErrorCore::unreachable(fn_name, line), "".into())
}
pub fn reassign_error(loc: Location, caused_by: Str, name: &str) -> Self { pub fn reassign_error(loc: Location, caused_by: Str, name: &str) -> Self {
let name = readable_name(name); let name = readable_name(name);
Self::new( Self::new(

View file

@ -38,9 +38,9 @@ impl SubstContext {
} }
} }
fn substitute(&self, quant_t: Type, ty_ctx: &Context, level: usize) -> TyCheckResult<Type> { fn substitute(&self, quant_t: Type, ty_ctx: &Context, level: usize, ctx: &Context) -> TyCheckResult<Type> {
let bounds = ty_ctx.type_params_bounds(); let bounds = ty_ctx.type_params_bounds();
let tv_ctx = TyVarContext::new(level, bounds); let tv_ctx = TyVarContext::new(level, bounds, ctx);
let (inst, _) = Context::instantiate_t(quant_t, tv_ctx); let (inst, _) = Context::instantiate_t(quant_t, tv_ctx);
for param in inst.typarams() { for param in inst.typarams() {
self.substitute_tp(&param, ty_ctx)?; self.substitute_tp(&param, ty_ctx)?;
@ -355,7 +355,7 @@ impl Evaluator {
if let Ok(obj) = ty_ctx.get_local(&Token::symbol(&rhs), &ctx.name) { if let Ok(obj) = ty_ctx.get_local(&Token::symbol(&rhs), &ctx.name) {
if let ConstObj::Type(quant_t) = obj { if let ConstObj::Type(quant_t) = obj {
let subst_ctx = SubstContext::new(&lhs, ty_ctx); let subst_ctx = SubstContext::new(&lhs, ty_ctx);
let t = subst_ctx.substitute(*quant_t, ty_ctx, level)?; let t = subst_ctx.substitute(*quant_t, ty_ctx, level, ctx)?;
let t = self.eval_t_params(t, ctx, level)?; let t = self.eval_t_params(t, ctx, level)?;
return Ok(t); return Ok(t);
} else { } else {
@ -363,9 +363,13 @@ impl Evaluator {
} }
} }
} }
todo!() if let Some(outer) = &ctx.outer {
self.eval_t_params(Type::MonoProj { lhs, rhs }, outer, level)
} else {
todo!("{lhs}.{rhs} not found in {}", erg_common::fmt_iter(ctx.rec_sorted_type_ctxs(&lhs)))
}
} }
Type::Ref(l) => Ok(Type::refer(self.eval_t_params(*l, ctx, level)?)), Type::Ref(l) => Ok(Type::ref_(self.eval_t_params(*l, ctx, level)?)),
Type::RefMut(l) => Ok(Type::ref_mut(self.eval_t_params(*l, ctx, level)?)), Type::RefMut(l) => Ok(Type::ref_mut(self.eval_t_params(*l, ctx, level)?)),
Type::VarArgs(l) => Ok(Type::var_args(self.eval_t_params(*l, ctx, level)?)), Type::VarArgs(l) => Ok(Type::var_args(self.eval_t_params(*l, ctx, level)?)),
Type::Poly { name, mut params } => { Type::Poly { name, mut params } => {

View file

@ -14,6 +14,8 @@ use erg_common::{
use erg_parser::ast::{fmt_lines, DefId, Params, VarName, VarPattern}; use erg_parser::ast::{fmt_lines, DefId, Params, VarName, VarPattern};
use erg_parser::token::{Token, TokenKind}; use erg_parser::token::{Token, TokenKind};
use crate::error::readable_name;
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct Literal { pub struct Literal {
pub data: ValueObj, // for constant folding pub data: ValueObj, // for constant folding
@ -26,10 +28,17 @@ impl HasType for Literal {
fn ref_t(&self) -> &Type { fn ref_t(&self) -> &Type {
&self.t &self.t
} }
fn ref_mut_t(&mut self) -> &mut Type {
&mut self.t
}
#[inline] #[inline]
fn signature_t(&self) -> Option<&Type> { fn signature_t(&self) -> Option<&Type> {
None None
} }
#[inline]
fn signature_mut_t(&mut self) -> Option<&mut Type> {
None
}
} }
impl NestedDisplay for Literal { impl NestedDisplay for Literal {
@ -129,8 +138,8 @@ impl KwArg {
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct Args { pub struct Args {
pos_args: Vec<PosArg>, pub pos_args: Vec<PosArg>,
kw_args: Vec<KwArg>, pub kw_args: Vec<KwArg>,
paren: Option<(Token, Token)>, paren: Option<(Token, Token)>,
} }
@ -199,14 +208,6 @@ impl Args {
self.kw_args.len() self.kw_args.len()
} }
pub fn pos_args(&self) -> &[PosArg] {
&self.pos_args[..]
}
pub fn kw_args(&self) -> &[KwArg] {
&self.kw_args[..]
}
pub fn push_pos(&mut self, pos: PosArg) { pub fn push_pos(&mut self, pos: PosArg) {
self.pos_args.push(pos); self.pos_args.push(pos);
} }
@ -284,9 +285,17 @@ impl HasType for Local {
&self.t &self.t
} }
#[inline] #[inline]
fn ref_mut_t(&mut self) -> &mut Type {
&mut self.t
}
#[inline]
fn signature_t(&self) -> Option<&Type> { fn signature_t(&self) -> Option<&Type> {
None None
} }
#[inline]
fn signature_mut_t(&mut self) -> Option<&mut Type> {
None
}
} }
impl Locational for Local { impl Locational for Local {
@ -333,9 +342,17 @@ impl HasType for Attribute {
&self.t &self.t
} }
#[inline] #[inline]
fn ref_mut_t(&mut self) -> &mut Type {
&mut self.t
}
#[inline]
fn signature_t(&self) -> Option<&Type> { fn signature_t(&self) -> Option<&Type> {
None None
} }
#[inline]
fn signature_mut_t(&mut self) -> Option<&mut Type> {
None
}
} }
impl Attribute { impl Attribute {
@ -369,9 +386,17 @@ impl HasType for Subscript {
&self.t &self.t
} }
#[inline] #[inline]
fn ref_mut_t(&mut self) -> &mut Type {
&mut self.t
}
#[inline]
fn signature_t(&self) -> Option<&Type> { fn signature_t(&self) -> Option<&Type> {
None None
} }
#[inline]
fn signature_mut_t(&mut self) -> Option<&mut Type> {
None
}
} }
impl Subscript { impl Subscript {
@ -416,9 +441,21 @@ impl HasType for Accessor {
} }
} }
#[inline] #[inline]
fn ref_mut_t(&mut self) -> &mut Type {
match self {
Self::Local(n) | Self::SelfDot(n) => n.ref_mut_t(),
Self::Attr(a) => a.ref_mut_t(),
Self::Subscr(s) => s.ref_mut_t(),
}
}
#[inline]
fn signature_t(&self) -> Option<&Type> { fn signature_t(&self) -> Option<&Type> {
None None
} }
#[inline]
fn signature_mut_t(&mut self) -> Option<&mut Type> {
None
}
} }
impl Accessor { impl Accessor {
@ -440,11 +477,11 @@ impl Accessor {
pub fn var_full_name(&self) -> Option<String> { pub fn var_full_name(&self) -> Option<String> {
match self { match self {
Self::Local(local) => Some(local.inspect().to_string()), Self::Local(local) => Some(readable_name(local.inspect()).to_string()),
Self::Attr(attr) => attr Self::Attr(attr) => attr
.obj .obj
.var_full_name() .var_full_name()
.map(|n| n + "." + attr.name.inspect()), .map(|n| n + "." + readable_name(attr.name.inspect())),
Self::Subscr(_) | Self::SelfDot(_) => todo!(), Self::Subscr(_) | Self::SelfDot(_) => todo!(),
} }
} }
@ -473,9 +510,17 @@ impl HasType for Array {
&self.t &self.t
} }
#[inline] #[inline]
fn ref_mut_t(&mut self) -> &mut Type {
&mut self.t
}
#[inline]
fn signature_t(&self) -> Option<&Type> { fn signature_t(&self) -> Option<&Type> {
None None
} }
#[inline]
fn signature_mut_t(&mut self) -> Option<&mut Type> {
None
}
} }
impl NestedDisplay for Array { impl NestedDisplay for Array {
@ -500,7 +545,7 @@ impl Array {
guard: Option<Expr>, guard: Option<Expr>,
) -> Self { ) -> Self {
let elem_t = elems let elem_t = elems
.pos_args() .pos_args
.first() .first()
.map(|a| a.expr.t()) .map(|a| a.expr.t())
.unwrap_or_else(|| Type::free_var(level, Constraint::TypeOf(Type::Type))); .unwrap_or_else(|| Type::free_var(level, Constraint::TypeOf(Type::Type)));
@ -530,6 +575,9 @@ impl HasType for Dict {
fn ref_t(&self) -> &Type { fn ref_t(&self) -> &Type {
todo!() todo!()
} }
fn ref_mut_t(&mut self) -> &mut Type {
todo!()
}
fn t(&self) -> Type { fn t(&self) -> Type {
todo!() todo!()
} }
@ -537,6 +585,10 @@ impl HasType for Dict {
fn signature_t(&self) -> Option<&Type> { fn signature_t(&self) -> Option<&Type> {
None None
} }
#[inline]
fn signature_mut_t(&mut self) -> Option<&mut Type> {
None
}
} }
impl NestedDisplay for Dict { impl NestedDisplay for Dict {
@ -568,7 +620,7 @@ pub struct BinOp {
impl NestedDisplay for BinOp { impl NestedDisplay for BinOp {
fn fmt_nest(&self, f: &mut fmt::Formatter<'_>, level: usize) -> fmt::Result { fn fmt_nest(&self, f: &mut fmt::Formatter<'_>, level: usize) -> fmt::Result {
writeln!(f, "`{}`:", self.op.content)?; write!(f, "`{}`: {}:\n", self.op.content, self.sig_t)?;
self.lhs.fmt_nest(f, level + 1)?; self.lhs.fmt_nest(f, level + 1)?;
writeln!(f)?; writeln!(f)?;
self.rhs.fmt_nest(f, level + 1) self.rhs.fmt_nest(f, level + 1)
@ -580,6 +632,9 @@ impl HasType for BinOp {
fn ref_t(&self) -> &Type { fn ref_t(&self) -> &Type {
self.sig_t.return_t().unwrap() self.sig_t.return_t().unwrap()
} }
fn ref_mut_t(&mut self) -> &mut Type {
self.sig_t.mut_return_t().unwrap()
}
#[inline] #[inline]
fn lhs_t(&self) -> &Type { fn lhs_t(&self) -> &Type {
self.sig_t.lhs_t() self.sig_t.lhs_t()
@ -592,6 +647,10 @@ impl HasType for BinOp {
fn signature_t(&self) -> Option<&Type> { fn signature_t(&self) -> Option<&Type> {
Some(&self.sig_t) Some(&self.sig_t)
} }
#[inline]
fn signature_mut_t(&mut self) -> Option<&mut Type> {
Some(&mut self.sig_t)
}
} }
impl_display_from_nested!(BinOp); impl_display_from_nested!(BinOp);
@ -620,6 +679,9 @@ impl HasType for UnaryOp {
fn ref_t(&self) -> &Type { fn ref_t(&self) -> &Type {
self.sig_t.return_t().unwrap() self.sig_t.return_t().unwrap()
} }
fn ref_mut_t(&mut self) -> &mut Type {
self.sig_t.mut_return_t().unwrap()
}
#[inline] #[inline]
fn lhs_t(&self) -> &Type { fn lhs_t(&self) -> &Type {
self.expr.ref_t() self.expr.ref_t()
@ -632,6 +694,10 @@ impl HasType for UnaryOp {
fn signature_t(&self) -> Option<&Type> { fn signature_t(&self) -> Option<&Type> {
Some(&self.sig_t) Some(&self.sig_t)
} }
#[inline]
fn signature_mut_t(&mut self) -> Option<&mut Type> {
Some(&mut self.sig_t)
}
} }
impl NestedDisplay for UnaryOp { impl NestedDisplay for UnaryOp {
@ -678,6 +744,10 @@ impl HasType for Call {
self.sig_t.return_t().unwrap() self.sig_t.return_t().unwrap()
} }
#[inline] #[inline]
fn ref_mut_t(&mut self) -> &mut Type {
self.sig_t.mut_return_t().unwrap()
}
#[inline]
fn lhs_t(&self) -> &Type { fn lhs_t(&self) -> &Type {
self.sig_t.lhs_t() self.sig_t.lhs_t()
} }
@ -689,6 +759,10 @@ impl HasType for Call {
fn signature_t(&self) -> Option<&Type> { fn signature_t(&self) -> Option<&Type> {
Some(&self.sig_t) Some(&self.sig_t)
} }
#[inline]
fn signature_mut_t(&mut self) -> Option<&mut Type> {
Some(&mut self.sig_t)
}
} }
impl Locational for Call { impl Locational for Call {
@ -723,6 +797,10 @@ impl HasType for Block {
self.last().unwrap().ref_t() self.last().unwrap().ref_t()
} }
#[inline] #[inline]
fn ref_mut_t(&mut self) -> &mut Type {
self.last_mut().unwrap().ref_mut_t()
}
#[inline]
fn t(&self) -> Type { fn t(&self) -> Type {
self.last().unwrap().t() self.last().unwrap().t()
} }
@ -730,6 +808,10 @@ impl HasType for Block {
fn signature_t(&self) -> Option<&Type> { fn signature_t(&self) -> Option<&Type> {
self.last().unwrap().signature_t() self.last().unwrap().signature_t()
} }
#[inline]
fn signature_mut_t(&mut self) -> Option<&mut Type> {
self.last_mut().unwrap().signature_mut_t()
}
} }
impl NestedDisplay for Block { impl NestedDisplay for Block {
@ -810,7 +892,7 @@ pub struct Lambda {
op: Token, op: Token,
pub body: Block, pub body: Block,
pub id: usize, pub id: usize,
t: Type, pub t: Type,
} }
impl HasType for Lambda { impl HasType for Lambda {
@ -819,9 +901,17 @@ impl HasType for Lambda {
&self.t &self.t
} }
#[inline] #[inline]
fn ref_mut_t(&mut self) -> &mut Type {
&mut self.t
}
#[inline]
fn signature_t(&self) -> Option<&Type> { fn signature_t(&self) -> Option<&Type> {
None None
} }
#[inline]
fn signature_mut_t(&mut self) -> Option<&mut Type> {
None
}
} }
impl NestedDisplay for Lambda { impl NestedDisplay for Lambda {
@ -884,7 +974,7 @@ impl Signature {
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct Decl { pub struct Decl {
pub sig: Signature, pub sig: Signature,
t: Type, pub t: Type,
} }
impl NestedDisplay for Decl { impl NestedDisplay for Decl {
@ -996,6 +1086,19 @@ impl HasType for Expr {
_ => &Type::NoneType, _ => &Type::NoneType,
} }
} }
fn ref_mut_t(&mut self) -> &mut Type {
match self {
Expr::Lit(lit) => lit.ref_mut_t(),
Expr::Accessor(accessor) => accessor.ref_mut_t(),
Expr::Array(array) => array.ref_mut_t(),
Expr::Dict(dict) => dict.ref_mut_t(),
Expr::BinOp(bin) => bin.ref_mut_t(),
Expr::UnaryOp(unary) => unary.ref_mut_t(),
Expr::Call(call) => call.ref_mut_t(),
Expr::Lambda(lambda) => lambda.ref_mut_t(),
_ => todo!(),
}
}
fn signature_t(&self) -> Option<&Type> { fn signature_t(&self) -> Option<&Type> {
match self { match self {
Expr::BinOp(bin) => bin.signature_t(), Expr::BinOp(bin) => bin.signature_t(),
@ -1004,6 +1107,14 @@ impl HasType for Expr {
_ => None, _ => None,
} }
} }
fn signature_mut_t(&mut self) -> Option<&mut Type> {
match self {
Expr::BinOp(bin) => bin.signature_mut_t(),
Expr::UnaryOp(unary) => unary.signature_mut_t(),
Expr::Call(call) => call.signature_mut_t(),
_ => None,
}
}
} }
impl Expr { impl Expr {

View file

@ -10,14 +10,13 @@ use Type::*;
use erg_parser::ast::VarName; use erg_parser::ast::VarName;
use crate::context::{Context, DefaultInfo, ParamSpec}; use crate::context::{Context, DefaultInfo, ParamSpec, ConstTemplate};
use crate::varinfo::{Mutability, VarInfo, VarKind, Visibility}; use crate::varinfo::{Mutability, VarInfo, VarKind, Visibility};
use DefaultInfo::*; use DefaultInfo::*;
use Mutability::*; use Mutability::*;
use VarKind::*; use VarKind::*;
use Visibility::*; use Visibility::*;
// NOTE: TyParam::MonoQuantVarは生成時に型を指定する必要があるが、逆にそちらがあれば型境界を指定しなくてもよい
impl Context { impl Context {
fn register_decl(&mut self, name: &'static str, t: Type, vis: Visibility) { fn register_decl(&mut self, name: &'static str, t: Type, vis: Visibility) {
let name = VarName::from_static(name); let name = VarName::from_static(name);
@ -47,6 +46,14 @@ impl Context {
} }
} }
fn register_const_param_defaults(&mut self, name: &'static str, params: Vec<ConstTemplate>) {
if self.const_param_defaults.get(name).is_some() {
panic!("already registered: {name}");
} else {
self.const_param_defaults.insert(Str::ever(name), params);
}
}
fn register_type(&mut self, t: Type, ctx: Self, muty: Mutability) { fn register_type(&mut self, t: Type, ctx: Self, muty: Mutability) {
if self.types.contains_key(&t) { if self.types.contains_key(&t) {
panic!("{} has already been registered", t.name()); panic!("{} has already been registered", t.name());
@ -57,7 +64,7 @@ impl Context {
for impl_trait in ctx.super_traits.iter() { for impl_trait in ctx.super_traits.iter() {
if !impl_trait.is_monomorphic() { if !impl_trait.is_monomorphic() {
if let Some(impls) = self.poly_trait_impls.get_mut(impl_trait.name()) { if let Some(impls) = self.poly_trait_impls.get_mut(impl_trait.name()) {
impls.push(impl_trait.clone()); impls.push((t.clone(), impl_trait.clone()));
} else { } else {
self.poly_trait_impls self.poly_trait_impls
.insert(Str::rc(impl_trait.name()), vec![impl_trait.clone()]); .insert(Str::rc(impl_trait.name()), vec![impl_trait.clone()]);
@ -76,10 +83,10 @@ impl Context {
self.locals self.locals
.insert(name.clone(), VarInfo::new(Type, muty, Private, Builtin)); .insert(name.clone(), VarInfo::new(Type, muty, Private, Builtin));
for method_name in ctx.locals.keys() { for method_name in ctx.locals.keys() {
if let Some(patches) = self._method_impl_patches.get_mut(method_name) { if let Some(patches) = self.method_impl_patches.get_mut(method_name) {
patches.push(name.clone()); patches.push(name.clone());
} else { } else {
self._method_impl_patches self.method_impl_patches
.insert(method_name.clone(), vec![name.clone()]); .insert(method_name.clone(), vec![name.clone()]);
} }
} }
@ -98,147 +105,108 @@ impl Context {
} }
/// see std/prelude.er /// see std/prelude.er
/// All type boundaries are defined in each subroutine
/// `push_subtype_bound`, etc. are used for type boundary determination in user-defined APIs
// 型境界はすべて各サブルーチンで定義する // 型境界はすべて各サブルーチンで定義する
// push_subtype_boundなどはユーザー定義APIの型境界決定のために使用する // push_subtype_boundなどはユーザー定義APIの型境界決定のために使用する
fn init_builtin_traits(&mut self) { fn init_builtin_traits(&mut self) {
let named = Self::mono_trait("Named", vec![], Self::TOP_LEVEL); let named = Self::mono_trait("Named", vec![], Self::TOP_LEVEL);
// Erg does not have a trait equivalent to `PartialEq` in Rust
// This means, Erg's `Float` cannot be compared with other `Float`
// use `l - r < EPSILON` to check if two floats are almost equal
let mut eq = Self::poly_trait("Eq", vec![PS::t("R", WithDefault)], vec![], Self::TOP_LEVEL); let mut eq = Self::poly_trait("Eq", vec![PS::t("R", WithDefault)], vec![], Self::TOP_LEVEL);
// __eq__: |Self <: Eq; R <: Eq()| Self(R).(R) -> Bool // __eq__: |Self <: Eq()| Self.(Self) -> Bool
let op_t = fn1_met(poly("Self", vec![ty_tp(mono_q("R"))]), mono_q("R"), Bool); let op_t = fn1_met(mono_q("Self"), mono_q("R"), Bool);
let op_t = quant( let op_t = quant(
op_t, op_t,
set! {subtype(mono_q("Self"), mono("Eq")), subtype(mono_q("R"), poly("Eq", vec![]))}, set! {
subtype(mono_q("Self"), poly("Eq", vec![ty_tp(mono_q("R"))])),
static_instance("R", Type)
},
); );
eq.register_decl("__eq__", op_t, Public); eq.register_decl("__eq__", op_t.clone(), Public);
let mut ord = Self::poly_trait( let mut partial_ord = Self::poly_trait(
"Ord", "PartialOrd",
vec![PS::t("R", WithDefault)], vec![PS::t("R", WithDefault)],
vec![mono("Eq")], vec![poly("PartialEq", vec![ty_tp(mono_q("R"))])],
Self::TOP_LEVEL, Self::TOP_LEVEL,
); );
let op_t = fn1_met(poly("Self", vec![ty_tp(mono_q("R"))]), mono_q("R"), Bool); let op_t = fn1_met(poly("Self", vec![ty_tp(mono_q("R"))]), mono_q("R"), Bool);
let op_t = quant( let op_t = quant(
op_t, op_t,
set! {subtype(mono_q("Self"), mono("Ord")), subtype(mono_q("R"), poly("Ord", vec![]))}, set! {
subtype(mono_q("Self"), poly("PartialOrd", vec![ty_tp(mono_q("R"))])),
static_instance("R", Type)
},
);
partial_ord.register_decl("__lt__", op_t.clone(), Public);
let ord = Self::mono_trait(
"Ord",
vec![poly("Eq", vec![]), poly("PartialOrd", vec![])],
Self::TOP_LEVEL,
); );
ord.register_decl("__lt__", op_t, Public);
let mut seq = Self::poly_trait( let mut seq = Self::poly_trait(
"Seq", "Seq",
vec![PS::t("T", NonDefault)], vec![PS::t("T", NonDefault)],
vec![poly("Output", vec![ty_tp(mono_q("T"))])], vec![poly("Output", vec![ty_tp(mono_q("T"))])],
Self::TOP_LEVEL, Self::TOP_LEVEL,
); );
let self_t = poly_q("Self", vec![TyParam::t(mono_q("T"))]); let self_t = mono_q("Self");
let t = fn0_met(self_t.clone(), Nat); let t = fn0_met(self_t.clone(), Nat);
let t = quant(t, set! {subtype(self_t.clone(), mono("Seq"))}); let t = quant(t, set! {subtype(self_t.clone(), poly("Seq", vec![TyParam::erased(Type)]))});
seq.register_decl("__len__", t, Public); seq.register_decl("__len__", t, Public);
let t = Type::fn1_met(self_t.clone(), Nat, mono_q("T")); let t = Type::fn1_met(self_t.clone(), Nat, mono_q("T"));
let t = quant( let t = quant(
t, t,
set! {subtype(self_t, mono("Seq")), static_instance("T", Type)}, set! {subtype(self_t, poly("Seq", vec![ty_tp(mono_q("T"))])), static_instance("T", Type)},
); );
// Seq.get: |Self <: Seq(T)| Self.(Nat) -> T
seq.register_decl("get", t, Public); seq.register_decl("get", t, Public);
let params = vec![PS::t("T", NonDefault)]; let params = vec![PS::t("T", NonDefault)];
let input = Self::poly_trait("Input", params.clone(), vec![], Self::TOP_LEVEL); let input = Self::poly_trait("Input", params.clone(), vec![], Self::TOP_LEVEL);
let output = Self::poly_trait("Output", params, vec![], Self::TOP_LEVEL); let output = Self::poly_trait("Output", params.clone(), vec![], Self::TOP_LEVEL);
let (r, o) = (mono_q("R"), mono_q("O")); let r = mono_q("R");
let (r_bound, o_bound) = (static_instance("R", Type), static_instance("O", Type)); let r_bound = static_instance("R", Type);
let params = vec![PS::t("R", WithDefault), PS::t("O", WithDefault)]; let params = vec![PS::t("R", WithDefault)];
let ty_params = vec![mono_q_tp("R"), mono_q_tp("O")]; let ty_params = vec![ty_tp(mono_q("R"))];
let mut add = Self::poly_trait( let mut add = Self::poly_trait("Add", params.clone(), vec![
"Add", poly("Output", vec![ty_tp(mono_q("R"))]),
params.clone(), ], Self::TOP_LEVEL);
vec![
poly("Output", vec![ty_tp(mono_q("R"))]),
poly("Output", vec![ty_tp(mono_q("O"))]),
],
Self::TOP_LEVEL,
);
let self_bound = subtype( let self_bound = subtype(
poly_q("Self", ty_params.clone()), mono_q("Self"),
poly("Add", ty_params.clone()), poly("Add", ty_params.clone()),
); );
let op_t = fn1_met(poly_q("Self", ty_params.clone()), r.clone(), o.clone()); let op_t = fn1_met(poly_q("Self", ty_params.clone()), r.clone(), mono_proj(mono_q("Self"), "AddO"));
let op_t = quant(op_t, set! {r_bound.clone(), o_bound.clone(), self_bound}); let op_t = quant(op_t, set! {r_bound.clone(), self_bound});
add.register_decl("__add__", op_t, Public); add.register_decl("__add__", op_t, Public);
let mut sub = Self::poly_trait( add.register_decl("AddO", Type, Public);
"Sub", let mut sub = Self::poly_trait("Sub", params.clone(), vec![
params.clone(), poly("Output", vec![ty_tp(mono_q("R"))]),
vec![ ], Self::TOP_LEVEL);
poly("Output", vec![ty_tp(mono_q("R"))]),
poly("Output", vec![ty_tp(mono_q("O"))]),
],
Self::TOP_LEVEL,
);
let self_bound = subtype( let self_bound = subtype(
poly_q("Self", ty_params.clone()), mono_q("Self"),
poly("Sub", ty_params.clone()), poly("Sub", ty_params.clone()),
); );
let op_t = fn1_met(poly_q("Self", ty_params.clone()), r.clone(), o.clone()); let op_t = fn1_met(poly_q("Self", ty_params.clone()), r.clone(), mono_proj(mono_q("Self"), "SubO"));
let op_t = quant(op_t, set! {r_bound, o_bound, self_bound}); let op_t = quant(op_t, set! {r_bound.clone(), self_bound});
sub.register_decl("__sub__", op_t, Public); sub.register_decl("__sub__", op_t, Public);
let mut mul = Self::poly_trait( sub.register_decl("SubO", Type, Public);
"Mul", let mut mul = Self::poly_trait("Mul", params.clone(), vec![
params.clone(), poly("Output", vec![ty_tp(mono_q("R"))]),
vec![ ], Self::TOP_LEVEL);
poly("Output", vec![ty_tp(mono_q("R"))]), let op_t = fn1_met(poly("Mul", ty_params.clone()), r.clone(), mono_proj(mono_q("Self"), "MulO"));
poly("Output", vec![ty_tp(mono_q("O"))]),
],
Self::TOP_LEVEL,
);
let op_t = fn1_met(poly("Mul", ty_params.clone()), r.clone(), o.clone());
mul.register_decl("__mul__", op_t, Public); mul.register_decl("__mul__", op_t, Public);
let mut div = Self::poly_trait( mul.register_decl("MulO", Type, Public);
"Div", let mut div = Self::poly_trait("Div", params.clone(), vec![
params, poly("Output", vec![ty_tp(mono_q("R"))]),
vec![ ], Self::TOP_LEVEL);
poly("Output", vec![ty_tp(mono_q("R"))]), let op_t = fn1_met(poly("Div", ty_params.clone()), r, mono_proj(mono_q("Self"), "DivO"));
poly("Output", vec![ty_tp(mono_q("O"))]),
],
Self::TOP_LEVEL,
);
let op_t = fn1_met(poly("Div", ty_params.clone()), r, o);
div.register_decl("__div__", op_t, Public); div.register_decl("__div__", op_t, Public);
/*let sup = poly( div.register_decl("DivO", Type, Public);
"Add",
vec![
mono_q_tp("Self"),
TyParam::mono_proj(mono_q_tp("Self"), "AddO"),
],
);
let mut closed_add = Self::mono_trait("SelfAdd", vec![sup], Self::TOP_LEVEL);
closed_add.register_decl("AddO", Type, Public);
let sup = poly(
"Sub",
vec![
mono_q_tp("Self"),
TyParam::mono_proj(mono_q_tp("Self"), "SubO"),
],
);
let mut closed_sub = Self::mono_trait("SelfSub", vec![sup], Self::TOP_LEVEL);
closed_sub.register_decl("SubO", Type, Public);
let sup = poly(
"Mul",
vec![
mono_q_tp("Self"),
TyParam::mono_proj(mono_q_tp("Self"), "MulO"),
],
);
let mut closed_mul = Self::mono_trait("SelfMul", vec![sup], Self::TOP_LEVEL);
closed_mul.register_decl("MulO", Type, Public);
let sup = Type::poly(
"Div",
vec![
mono_q_tp("Self"),
TyParam::mono_proj(mono_q_tp("Self"), "DivO"),
],
);
let mut closed_div = Self::mono_trait("SelfDiv", vec![sup], Self::TOP_LEVEL);
closed_div.register_decl("DivO", Type, Public);
*/
self.register_type(mono("Named"), named, Const); self.register_type(mono("Named"), named, Const);
self.register_type(poly("Eq", vec![ty_tp(mono_q("R"))]), eq, Const); self.register_type(poly("Eq", vec![ty_tp(mono_q("R"))]), eq, Const);
self.register_type(poly("Ord", vec![ty_tp(mono_q("R"))]), ord, Const); self.register_type(poly("PartialOrd", vec![ty_tp(mono_q("R"))]), partial_ord, Const);
self.register_type(mono("Ord"), ord, Const);
self.register_type(poly("Seq", vec![ty_tp(mono_q("T"))]), seq, Const); self.register_type(poly("Seq", vec![ty_tp(mono_q("T"))]), seq, Const);
self.register_type(poly("Input", vec![ty_tp(mono_q("T"))]), input, Const); self.register_type(poly("Input", vec![ty_tp(mono_q("T"))]), input, Const);
self.register_type(poly("Output", vec![ty_tp(mono_q("T"))]), output, Const); self.register_type(poly("Output", vec![ty_tp(mono_q("T"))]), output, Const);
@ -247,6 +215,12 @@ impl Context {
self.register_type(poly("Mul", ty_params.clone()), mul, Const); self.register_type(poly("Mul", ty_params.clone()), mul, Const);
self.register_type(poly("Div", ty_params), div, Const); self.register_type(poly("Div", ty_params), div, Const);
// self.register_type(mono("Num"), num, Const); // self.register_type(mono("Num"), num, Const);
self.register_const_param_defaults("Eq", vec![ConstTemplate::Obj(ConstObj::t(mono_q("Self")))]);
self.register_const_param_defaults("PartialOrd", vec![ConstTemplate::app("Self", vec![], vec![])]);
self.register_const_param_defaults("Add", vec![ConstTemplate::Obj(ConstObj::t(mono_q("Self")))]);
self.register_const_param_defaults("Sub", vec![ConstTemplate::Obj(ConstObj::t(mono_q("Self")))]);
self.register_const_param_defaults("Mul", vec![ConstTemplate::Obj(ConstObj::t(mono_q("Self")))]);
self.register_const_param_defaults("Div", vec![ConstTemplate::Obj(ConstObj::t(mono_q("Self")))]);
} }
fn init_builtin_classes(&mut self) { fn init_builtin_classes(&mut self) {
@ -277,12 +251,12 @@ impl Context {
vec![Obj], vec![Obj],
vec![ vec![
mono("Num"), mono("Num"),
// mono("Eq"), // Float doesn't have an Eq implementation
mono("Ord"), mono("Ord"),
mono("Eq"), poly("Add", vec![ty_tp(Float)]),
mono("Add"), poly("Sub", vec![ty_tp(Float)]),
mono("Sub"), poly("Mul", vec![ty_tp(Float)]),
mono("Mul"), poly("Div", vec![ty_tp(Float)]),
mono("Div"),
mono("Mutate"), mono("Mutate"),
], ],
Self::TOP_LEVEL, Self::TOP_LEVEL,
@ -292,6 +266,10 @@ impl Context {
float.register_impl("__sub__", op_t.clone(), Const, Public); float.register_impl("__sub__", op_t.clone(), Const, Public);
float.register_impl("__mul__", op_t.clone(), Const, Public); float.register_impl("__mul__", op_t.clone(), Const, Public);
float.register_impl("__div__", op_t, Const, Public); float.register_impl("__div__", op_t, Const, Public);
float.register_const("AddO", ConstObj::t(Float));
float.register_const("SubO", ConstObj::t(Float));
float.register_const("MulO", ConstObj::t(Float));
float.register_const("DivO", ConstObj::t(Float));
float.register_impl("Real", Float, Const, Public); float.register_impl("Real", Float, Const, Public);
float.register_impl("Imag", Float, Const, Public); float.register_impl("Imag", Float, Const, Public);
let mut ratio = Self::mono_class( let mut ratio = Self::mono_class(
@ -299,12 +277,12 @@ impl Context {
vec![Obj], vec![Obj],
vec![ vec![
mono("Num"), mono("Num"),
poly("Eq", vec![ty_tp(Ratio)]),
mono("Ord"), mono("Ord"),
mono("Eq"), poly("Add", vec![ty_tp(Ratio)]),
mono("Add"), poly("Sub", vec![ty_tp(Ratio)]),
mono("Sub"), poly("Mul", vec![ty_tp(Ratio)]),
mono("Mul"), poly("Div", vec![ty_tp(Ratio)]),
mono("Div"),
mono("Mutate"), mono("Mutate"),
], ],
Self::TOP_LEVEL, Self::TOP_LEVEL,
@ -314,21 +292,25 @@ impl Context {
ratio.register_impl("__sub__", op_t.clone(), Const, Public); ratio.register_impl("__sub__", op_t.clone(), Const, Public);
ratio.register_impl("__mul__", op_t.clone(), Const, Public); ratio.register_impl("__mul__", op_t.clone(), Const, Public);
ratio.register_impl("__div__", op_t, Const, Public); ratio.register_impl("__div__", op_t, Const, Public);
ratio.register_const("AddO", ConstObj::t(Ratio));
ratio.register_const("SubO", ConstObj::t(Ratio));
ratio.register_const("MulO", ConstObj::t(Ratio));
ratio.register_const("DivO", ConstObj::t(Ratio));
ratio.register_impl("Real", Ratio, Const, Public); ratio.register_impl("Real", Ratio, Const, Public);
ratio.register_impl("Imag", Ratio, Const, Public); ratio.register_impl("Imag", Ratio, Const, Public);
let mut int = Self::mono_class( let mut int = Self::mono_class(
"Int", "Int",
vec![Obj], vec![Obj],
vec![ vec![
poly("Add", vec![ty_tp(Int), ty_tp(Int)]), mono("Ord"),
poly("Sub", vec![ty_tp(Int), ty_tp(Int)]), poly("Eq", vec![ty_tp(Int)]),
poly("Mul", vec![ty_tp(Int), ty_tp(Int)]), poly("Add", vec![ty_tp(Int)]),
poly("Div", vec![ty_tp(Int), ty_tp(Ratio)]), poly("Sub", vec![ty_tp(Int)]),
poly("Mul", vec![ty_tp(Int)]),
poly("Div", vec![ty_tp(Int)]),
mono("Num"), mono("Num"),
mono("Rational"), mono("Rational"),
mono("Integral"), mono("Integral"),
// mono("SelfOrd"),
// mono("SelfEq"),
mono("Mutate"), mono("Mutate"),
], ],
Self::TOP_LEVEL, Self::TOP_LEVEL,
@ -339,21 +321,25 @@ impl Context {
int.register_impl("__add__", op_t.clone(), Const, Public); int.register_impl("__add__", op_t.clone(), Const, Public);
int.register_impl("__sub__", op_t.clone(), Const, Public); int.register_impl("__sub__", op_t.clone(), Const, Public);
int.register_impl("__mul__", op_t, Const, Public); int.register_impl("__mul__", op_t, Const, Public);
int.register_const("AddO", ConstObj::t(Int));
int.register_const("SubO", ConstObj::t(Int));
int.register_const("MulO", ConstObj::t(Int));
int.register_const("DivO", ConstObj::t(Ratio));
int.register_impl("Real", Int, Const, Public); int.register_impl("Real", Int, Const, Public);
int.register_impl("Imag", Int, Const, Public); int.register_impl("Imag", Int, Const, Public);
let mut nat = Self::mono_class( let mut nat = Self::mono_class(
"Nat", "Nat",
vec![Int, Obj], vec![Int, Obj],
vec![ vec![
poly("Add", vec![ty_tp(Nat), ty_tp(Nat)]), mono("Ord"),
poly("Sub", vec![ty_tp(Nat), ty_tp(Int)]), poly("Eq", vec![ty_tp(Nat)]),
poly("Mul", vec![ty_tp(Nat), ty_tp(Nat)]), poly("Add", vec![ty_tp(Nat)]),
poly("Div", vec![ty_tp(Nat), ty_tp(Ratio)]), poly("Sub", vec![ty_tp(Nat)]),
poly("Mul", vec![ty_tp(Nat)]),
poly("Div", vec![ty_tp(Nat)]),
mono("Num"), mono("Num"),
mono("Rational"), mono("Rational"),
mono("Integral"), mono("Integral"),
// mono("SelfOrd"),
// mono("SelfEq"),
mono("Mutate"), mono("Mutate"),
], ],
Self::TOP_LEVEL, Self::TOP_LEVEL,
@ -374,6 +360,10 @@ impl Context {
Immutable, Immutable,
Public, Public,
); );
nat.register_const("AddO", ConstObj::t(Nat));
nat.register_const("SubO", ConstObj::t(Int));
nat.register_const("MulO", ConstObj::t(Nat));
nat.register_const("DivO", ConstObj::t(Ratio));
nat.register_impl("Real", Nat, Const, Public); nat.register_impl("Real", Nat, Const, Public);
nat.register_impl("Imag", Nat, Const, Public); nat.register_impl("Imag", Nat, Const, Public);
let mut bool_ = Self::mono_class( let mut bool_ = Self::mono_class(
@ -383,8 +373,8 @@ impl Context {
mono("Num"), mono("Num"),
mono("Rational"), mono("Rational"),
mono("Integral"), mono("Integral"),
// mono("SelfOrd"), poly("Eq", vec![ty_tp(Bool)]),
// mono("SelfEq"), mono("Ord"),
// mono("SelfAdd"), // mono("SelfAdd"),
// mono("SelfSub"), // mono("SelfSub"),
// mono("SelfMul"), // mono("SelfMul"),
@ -399,10 +389,12 @@ impl Context {
"Str", "Str",
vec![Obj], vec![Obj],
vec![ vec![
mono("Eq"), poly("Eq", vec![ty_tp(Str)]),
mono("Ord"),
mono("Mutate"), mono("Mutate"),
poly("Seq", vec![ty_tp(Str)]), poly("Seq", vec![ty_tp(Str)]),
poly("Add", vec![ty_tp(Str), ty_tp(Str)]), poly("Add", vec![ty_tp(Str)]),
poly("Mul", vec![ty_tp(Nat)])
], ],
Self::TOP_LEVEL, Self::TOP_LEVEL,
); );
@ -418,12 +410,14 @@ impl Context {
Immutable, Immutable,
Public, Public,
); );
str_.register_const("AddO", ConstObj::t(Str));
str_.register_const("MulO", ConstObj::t(Str));
let mut array = Self::poly_class( let mut array = Self::poly_class(
"Array", "Array",
vec![PS::t_nd("T"), PS::named_nd("N", Nat)], vec![PS::t_nd("T"), PS::named_nd("N", Nat)],
vec![Obj], vec![Obj],
vec![ vec![
mono("Eq"), poly("Eq", vec![ty_tp(Type::poly("Array", vec![ty_tp(mono_q("T")), mono_q_tp("N")]))]),
mono("Mutate"), mono("Mutate"),
poly("Seq", vec![ty_tp(mono_q("T"))]), poly("Seq", vec![ty_tp(mono_q("T"))]),
poly("Output", vec![ty_tp(mono_q("T"))]), poly("Output", vec![ty_tp(mono_q("T"))]),
@ -453,7 +447,10 @@ impl Context {
let mut type_ = Self::mono_class( let mut type_ = Self::mono_class(
"Type", "Type",
vec![Obj], vec![Obj],
vec![mono("Eq"), mono("Named")], vec![
poly("Eq", vec![ty_tp(Type)]),
mono("Named")
],
Self::TOP_LEVEL, Self::TOP_LEVEL,
); );
type_.register_impl( type_.register_impl(
@ -465,16 +462,18 @@ impl Context {
let module = Self::mono_class( let module = Self::mono_class(
"Module", "Module",
vec![Obj], vec![Obj],
vec![mono("Eq"), mono("Named")], vec![
poly("Eq", vec![ty_tp(Module)]),
mono("Named")
],
Self::TOP_LEVEL, Self::TOP_LEVEL,
); );
let array_mut_t = Type::poly("Array!", vec![TyParam::t(mono_q("T")), mono_q_tp("N")]); let array_mut_t = Type::poly("Array!", vec![ty_tp(mono_q("T")), mono_q_tp("N")]);
let mut array_mut = Self::poly_class( let mut array_mut = Self::poly_class(
"Array!", "Array!",
vec![PS::t_nd("T"), PS::named_nd("N", NatMut)], vec![PS::t_nd("T"), PS::named_nd("N", NatMut)],
vec![Obj], vec![poly("Range", vec![ty_tp(mono_q("T")), mono_q_tp("N")]), Obj],
vec![ vec![
mono("Eq"),
mono("Mutate"), mono("Mutate"),
poly("Seq", vec![ty_tp(mono_q("T"))]), poly("Seq", vec![ty_tp(mono_q("T"))]),
], ],
@ -484,7 +483,7 @@ impl Context {
Type::ref_mut(array_mut_t.clone()), Type::ref_mut(array_mut_t.clone()),
Some(Type::ref_mut(poly( Some(Type::ref_mut(poly(
"Array!", "Array!",
vec![TyParam::t(mono_q("T")), mono_q_tp("N") + value(1)], vec![ty_tp(mono_q("T")), mono_q_tp("N") + value(1)],
))), ))),
vec![param_t("elem", mono_q("T"))], vec![param_t("elem", mono_q("T"))],
vec![], vec![],
@ -501,7 +500,7 @@ impl Context {
vec![PS::t_nd("T")], vec![PS::t_nd("T")],
vec![Obj], vec![Obj],
vec![ vec![
mono("Eq"), poly("Eq", vec![ty_tp(Type::poly("Range", vec![ty_tp(mono_q("T"))]))]),
mono("Mutate"), mono("Mutate"),
poly("Seq", vec![ty_tp(mono_q("T"))]), poly("Seq", vec![ty_tp(mono_q("T"))]),
poly("Output", vec![ty_tp(mono_q("T"))]), poly("Output", vec![ty_tp(mono_q("T"))]),
@ -577,7 +576,7 @@ impl Context {
fn init_builtin_procs(&mut self) { fn init_builtin_procs(&mut self) {
let t_print = nd_proc( let t_print = nd_proc(
vec![param_t("objs", Type::var_args(Type::refer(Obj)))], vec![param_t("objs", Type::var_args(Type::ref_(Obj)))],
NoneType, NoneType,
); );
let t_input = nd_proc(vec![param_t("msg", Str)], Str); let t_input = nd_proc(vec![param_t("msg", Str)], Str);
@ -616,37 +615,41 @@ impl Context {
/* binary */ /* binary */
let l = mono_q("L"); let l = mono_q("L");
let r = mono_q("R"); let r = mono_q("R");
let o = mono_q("O"); let params = vec![ty_tp(mono_q("R"))];
let params = vec![mono_q_tp("R"), mono_q_tp("O")]; let op_t = Type::func2(l.clone(), r.clone(), mono_proj(mono_q("L"), "AddO"));
let op_t = Type::func2(l.clone(), r.clone(), o.clone());
let op_t = quant( let op_t = quant(
op_t, op_t,
set! { set! {
static_instance("R", Type), static_instance("R", Type),
static_instance("O", Type),
subtype(l.clone(), poly("Add", params.clone())) subtype(l.clone(), poly("Add", params.clone()))
}, },
); );
self.register_impl("__add__", op_t, Const, Private); self.register_impl("__add__", op_t, Const, Private);
let op_t = Type::func2(l.clone(), r.clone(), o.clone()); let op_t = Type::func2(l.clone(), r.clone(), mono_proj(mono_q("L"), "SubO"));
let op_t = quant( let op_t = quant(
op_t, op_t,
set! { set! {
static_instance("R", Type), static_instance("R", Type),
static_instance("O", Type),
subtype(l.clone(), poly("Sub", params.clone())) subtype(l.clone(), poly("Sub", params.clone()))
}, },
); );
self.register_impl("__sub__", op_t, Const, Private); self.register_impl("__sub__", op_t, Const, Private);
let op_t = Type::func2(l.clone(), r.clone(), o.clone()); let op_t = Type::func2(l.clone(), r.clone(), mono_proj(mono_q("L"), "MulO"));
let op_t = quant(op_t, set! {subtype(l.clone(), poly("Mul", params.clone()))}); let op_t = quant(op_t, set! {
static_instance("R", Type),
subtype(l.clone(), poly("Mul", params.clone()))
});
self.register_impl("__mul__", op_t, Const, Private); self.register_impl("__mul__", op_t, Const, Private);
let op_t = Type::func2(l.clone(), r, o); let op_t = Type::func2(l.clone(), r.clone(), mono_proj(mono_q("L"), "DivO"));
let op_t = quant(op_t, set! {subtype(l, poly("Mul", params))}); let op_t = quant(op_t, set! {
static_instance("R", Type),
subtype(l, poly("Mul", params.clone()))
});
self.register_impl("__div__", op_t, Const, Private); self.register_impl("__div__", op_t, Const, Private);
let m = mono_q("M"); let m = mono_q("M");
let op_t = Type::func2(m.clone(), m.clone(), m.clone()); let op_t = Type::func2(m.clone(), m.clone(), m.clone());
let op_t = quant(op_t, set! {subtype(m, poly("Mul", vec![]))}); let op_t = quant(op_t, set! {subtype(m, poly("Mul", vec![]))});
// TODO: add bound: M == MulO
self.register_impl("__pow__", op_t, Const, Private); self.register_impl("__pow__", op_t, Const, Private);
let d = mono_q("D"); let d = mono_q("D");
let op_t = Type::func2(d.clone(), d.clone(), d.clone()); let op_t = Type::func2(d.clone(), d.clone(), d.clone());
@ -659,7 +662,7 @@ impl Context {
self.register_impl("__ne__", op_t, Const, Private); self.register_impl("__ne__", op_t, Const, Private);
let o = mono_q("O"); let o = mono_q("O");
let op_t = Type::func2(o.clone(), o.clone(), Bool); let op_t = Type::func2(o.clone(), o.clone(), Bool);
let op_t = quant(op_t, set! {subtype(o, poly("Ord", vec![]))}); let op_t = quant(op_t, set! {subtype(o, mono("Ord"))});
self.register_impl("__lt__", op_t.clone(), Const, Private); self.register_impl("__lt__", op_t.clone(), Const, Private);
self.register_impl("__le__", op_t.clone(), Const, Private); self.register_impl("__le__", op_t.clone(), Const, Private);
self.register_impl("__gt__", op_t.clone(), Const, Private); self.register_impl("__gt__", op_t.clone(), Const, Private);
@ -675,7 +678,7 @@ impl Context {
self.register_decl("__neg__", op_t, Private); self.register_decl("__neg__", op_t, Private);
let t = mono_q("T"); let t = mono_q("T");
let op_t = Type::func2(t.clone(), t.clone(), Type::range(t.clone())); let op_t = Type::func2(t.clone(), t.clone(), Type::range(t.clone()));
let op_t = quant(op_t, set! {subtype(t, mono("Ord"))}); let op_t = quant(op_t, set! {subtype(t.clone(), mono("Ord"))});
self.register_decl("__rng__", op_t.clone(), Private); self.register_decl("__rng__", op_t.clone(), Private);
self.register_decl("__lorng__", op_t.clone(), Private); self.register_decl("__lorng__", op_t.clone(), Private);
self.register_decl("__rorng__", op_t.clone(), Private); self.register_decl("__rorng__", op_t.clone(), Private);
@ -704,17 +707,11 @@ impl Context {
vec![ vec![
poly( poly(
"Add", "Add",
vec![ vec![TyParam::from(&o..=&p)],
TyParam::from(&o..=&p),
TyParam::from(m.clone() + o.clone()..=n.clone() + p.clone()),
],
), ),
poly( poly(
"Sub", "Sub",
vec![ vec![TyParam::from(&o..=&p)],
TyParam::from(&o..=&p),
TyParam::from(m.clone() - p.clone()..=n.clone() - o.clone()),
],
), ),
], ],
Self::TOP_LEVEL, Self::TOP_LEVEL,
@ -728,9 +725,11 @@ impl Context {
let op_t = fn1_met( let op_t = fn1_met(
Type::from(&m..=&n), Type::from(&m..=&n),
Type::from(&o..=&p), Type::from(&o..=&p),
Type::from(m - p..=n - o), Type::from(m.clone() - p.clone()..=n.clone() - o.clone()),
); );
interval.register_impl("__sub__", op_t, Const, Public); interval.register_impl("__sub__", op_t, Const, Public);
interval.register_const("AddO", ConstObj::t(Type::from(m.clone() + o.clone()..=n.clone() + p.clone())));
interval.register_const("SubO", ConstObj::t(Type::from(m - p..=n - o)));
self.register_patch("Interval", interval, Const); self.register_patch("Interval", interval, Const);
// eq.register_impl("__ne__", op_t, Const, Public); // eq.register_impl("__ne__", op_t, Const, Public);
// ord.register_impl("__le__", op_t.clone(), Const, Public); // ord.register_impl("__le__", op_t.clone(), Const, Public);

View file

@ -12,7 +12,7 @@ use erg_parser::ast;
use erg_parser::ast::AST; use erg_parser::ast::AST;
use crate::context::{Context, ContextKind, RegistrationMode}; use crate::context::{Context, ContextKind, RegistrationMode};
use crate::error::{LowerError, LowerErrors, LowerResult, LowerWarnings}; use crate::error::{LowerError, LowerErrors, LowerResult, LowerWarnings, readable_name};
use crate::hir; use crate::hir;
use crate::hir::HIR; use crate::hir::HIR;
use crate::varinfo::Visibility; use crate::varinfo::Visibility;
@ -36,7 +36,7 @@ impl ASTLowerer {
Some(Context::init_builtins()), Some(Context::init_builtins()),
vec![], vec![],
vec![], vec![],
0, Context::TOP_LEVEL,
), ),
errs: LowerErrors::empty(), errs: LowerErrors::empty(),
warns: LowerWarnings::empty(), warns: LowerWarnings::empty(),
@ -173,8 +173,8 @@ impl ASTLowerer {
let obj = self.lower_expr(*call.obj, false)?; let obj = self.lower_expr(*call.obj, false)?;
let t = self.ctx.get_call_t( let t = self.ctx.get_call_t(
&obj, &obj,
hir_args.pos_args(), &hir_args.pos_args,
hir_args.kw_args(), &hir_args.kw_args,
&self.ctx.name, &self.ctx.name,
)?; )?;
Ok(hir::Call::new(obj, hir_args, t)) Ok(hir::Call::new(obj, hir_args, t))
@ -296,7 +296,7 @@ impl ASTLowerer {
.outer .outer
.as_mut() .as_mut()
.unwrap() .unwrap()
.import_mod(name, &call.args.pos_args().first().unwrap().expr)?; .import_mod(name, &call.args.pos_args.first().unwrap().expr)?;
} }
} else { } else {
todo!() todo!()
@ -395,6 +395,7 @@ impl ASTLowerer {
} }
} }
let hir = HIR::new(ast.name, module); let hir = HIR::new(ast.name, module);
let hir = self.ctx.deref_toplevel(hir)?;
log!( log!(
"[DEBUG] {}() has completed, found errors: {}", "[DEBUG] {}() has completed, found errors: {}",
fn_name!(), fn_name!(),

View file

@ -143,15 +143,15 @@ impl OwnershipChecker {
let (nd_ownerships, d_ownerships): (Vec<_>, Vec<_>) = non_defaults let (nd_ownerships, d_ownerships): (Vec<_>, Vec<_>) = non_defaults
.iter() .iter()
.enumerate() .enumerate()
.partition(|(i, _)| *i == call.args.pos_args().len()); .partition(|(i, _)| *i == call.args.pos_args.len());
for (parg, (_, ownership)) in for (parg, (_, ownership)) in
call.args.pos_args().iter().zip(nd_ownerships.into_iter()) call.args.pos_args.iter().zip(nd_ownerships.into_iter())
{ {
self.check_expr(&parg.expr, *ownership); self.check_expr(&parg.expr, *ownership);
} }
for (kwarg, (_, ownership)) in call for (kwarg, (_, ownership)) in call
.args .args
.kw_args() .kw_args
.iter() .iter()
.zip(d_ownerships.into_iter().chain(defaults.iter().enumerate())) .zip(d_ownerships.into_iter().chain(defaults.iter().enumerate()))
{ {
@ -159,10 +159,10 @@ impl OwnershipChecker {
} }
} }
ArgsOwnership::VarArgs(ownership) => { ArgsOwnership::VarArgs(ownership) => {
for parg in call.args.pos_args().iter() { for parg in call.args.pos_args.iter() {
self.check_expr(&parg.expr, ownership); self.check_expr(&parg.expr, ownership);
} }
for kwarg in call.args.kw_args().iter() { for kwarg in call.args.kw_args.iter() {
self.check_expr(&kwarg.expr, ownership); self.check_expr(&kwarg.expr, ownership);
} }
} }
@ -178,12 +178,12 @@ impl OwnershipChecker {
self.check_expr(&unary.expr, ownership); self.check_expr(&unary.expr, ownership);
} }
Expr::Array(arr) => { Expr::Array(arr) => {
for a in arr.elems.pos_args().iter() { for a in arr.elems.pos_args.iter() {
self.check_expr(&a.expr, ownership); self.check_expr(&a.expr, ownership);
} }
} }
Expr::Dict(dict) => { Expr::Dict(dict) => {
for a in dict.attrs.kw_args().iter() { for a in dict.attrs.kw_args.iter() {
// self.check_expr(&a.key); // self.check_expr(&a.key);
self.check_expr(&a.expr, ownership); self.check_expr(&a.expr, ownership);
} }

View file

@ -142,9 +142,17 @@ impl HasType for VarInfo {
&self.t &self.t
} }
#[inline] #[inline]
fn ref_mut_t(&mut self) -> &mut Type {
&mut self.t
}
#[inline]
fn signature_t(&self) -> Option<&Type> { fn signature_t(&self) -> Option<&Type> {
None None
} }
#[inline]
fn signature_mut_t(&mut self) -> Option<&mut Type> {
None
}
} }
impl VarInfo { impl VarInfo {

View file

@ -1,6 +1,6 @@
[package] [package]
name = "erg_parser" name = "erg_parser"
version = "0.2.2" version = "0.2.4"
description = "The Erg parser" description = "The Erg parser"
authors = ["mtshiba <sbym1346@gmail.com>"] authors = ["mtshiba <sbym1346@gmail.com>"]
license = "MIT OR Apache-2.0" license = "MIT OR Apache-2.0"
@ -14,7 +14,7 @@ debug = [ "erg_common/debug" ]
japanese = [ "erg_common/japanese" ] japanese = [ "erg_common/japanese" ]
[dependencies] [dependencies]
erg_common = { version = "0.2.2", path = "../erg_common" } erg_common = { version = "0.2.4", path = "../erg_common" }
[lib] [lib]
path = "lib.rs" path = "lib.rs"

View file

@ -42,6 +42,10 @@ impl Runnable for LexerRunner {
#[inline] #[inline]
fn clear(&mut self) {} fn clear(&mut self) {}
fn exec(&mut self) -> Result<(), Self::Errs> {
todo!()
}
fn eval(&mut self, src: Str) -> Result<String, LexerRunnerErrors> { fn eval(&mut self, src: Str) -> Result<String, LexerRunnerErrors> {
let lexer = Lexer::from_str(src); let lexer = Lexer::from_str(src);
if cfg!(feature = "debug") { if cfg!(feature = "debug") {

View file

@ -294,6 +294,10 @@ impl Runnable for ParserRunner {
#[inline] #[inline]
fn clear(&mut self) {} fn clear(&mut self) {}
fn exec(&mut self) -> Result<(), Self::Errs> {
todo!()
}
fn eval(&mut self, src: Str) -> Result<String, ParserRunnerErrors> { fn eval(&mut self, src: Str) -> Result<String, ParserRunnerErrors> {
let ast = self.parse_from_str(src)?; let ast = self.parse_from_str(src)?;
Ok(format!("{ast}")) Ok(format!("{ast}"))

View file

@ -1,6 +1,6 @@
# プロシージャ # プロシージャ
プロシージャは可変オブジェクトを取り扱う際に必要となるが、可変オブジェクトを引数に持てばプロシージャであるとは限らない プロシージャは可変オブジェクトを取り扱う際に必要となりますが、可変オブジェクトを引数に持てばプロシージャであるとは限りません
```erg ```erg
peek_str s: Str! = log s peek_str s: Str! = log s

View file

@ -2,8 +2,8 @@
## id! ## id!
オブジェクトのユニークな識別番号を返す。 オブジェクトのユニークな識別番号を返します。
純粋なErgの意味論の中では同一の構造を持つオブジェクトの間に差異を見出す事はできないが、実際のところ、オブジェクトはメモリ上の位置が異なる`id!`はこの位置を表す数値を返す。 純粋なErgの意味論の中では同一の構造を持つオブジェクトの間に差異を見出す事はできませんが、実際のところ、オブジェクトはメモリ上の位置が異なります`id!`はこの位置を表す数値を返します。
```erg ```erg
``` ```

View file

@ -1,6 +1,6 @@
# タプル # タプル
タプルは配列と似ていますが、違う型のオブジェクトを保持することができます。 タプルは配列と似ていますが、違う型のオブジェクトを保持できます。
このようなコレクションを非等質なコレクションと呼びます。対して等質なコレクションには配列、セットなどがあります。 このようなコレクションを非等質なコレクションと呼びます。対して等質なコレクションには配列、セットなどがあります。
```erg ```erg
@ -25,7 +25,7 @@ t = 1, True, "a"
i, b, s = t i, b, s = t
``` ```
タプルは違う型のオブジェクトを保持することができますが、そのかわり配列のようなイテレーションができなくなります。 タプルは違う型のオブジェクトを保持できますが、そのかわり配列のようなイテレーションができなくなります。
```erg ```erg
t: ({1}, {2}, {3}) = (1, 2, 3) t: ({1}, {2}, {3}) = (1, 2, 3)

View file

@ -15,10 +15,10 @@ john["name"] # Error: john is not subscribable
`.name`, `.age`の部分を属性、`"John"`, `21`の部分を属性値と呼びます。 `.name`, `.age`の部分を属性、`"John"`, `21`の部分を属性値と呼びます。
JavaScriptのオブジェクトリテラルとの相違点は、文字列でアクセスできない点です。すなわち、属性は単なる文字列ではありません。 JavaScriptのオブジェクトリテラルとの相違点は、文字列でアクセスできない点です。すなわち、属性は単なる文字列ではありません。
これは、値へのアクセスをコンパイル時に決定するためと、辞書とレコードが別物であるためといった理由があります。つまり、`{"name": "John"}`はDict,`{name = "John"}`はレコードである これは、値へのアクセスをコンパイル時に決定するためと、辞書とレコードが別物であるためといった理由があります。つまり、`{"name": "John"}`はDict,`{name = "John"}`はレコードで
では、辞書とレコードはどう使い分ければいいのか。 では、辞書とレコードはどう使い分ければいいのでしょうか。
一般的にはレコードの使用を推奨す。レコードには、コンパイル時に要素が存在するかチェックされる、 __可視性(visibility)__ を指定できるなどのメリットがあ 一般的にはレコードの使用を推奨します。レコードには、コンパイル時に要素が存在するかチェックされる、 __可視性(visibility)__ を指定できるなどのメリットがあります
可視性の指定は、Java言語などでみられるpublic/privateの指定に相当す。詳しくは[可視性](./15_visibility.md)を参照。 可視性の指定は、Java言語などでみられるpublic/privateの指定に相当します。詳しくは[可視性](./15_visibility.md)を参照してください
```erg ```erg
a = {x = 1; .y = x + 1} a = {x = 1; .y = x + 1}
@ -27,9 +27,9 @@ a.x # AttributeError: x is private
assert a.y == 2 assert a.y == 2
``` ```
上の例はJavaScriptに習熟している人間からすると奇妙かもしれないが、単に`x`と宣言すると外部からアクセスできない。`.`をつけると`.`でアクセスできるというわけである 上の例はJavaScriptに習熟している人間からすると奇妙かもしれませんが、単に`x`と宣言すると外部からアクセスできず、`.`をつけると`.`でアクセスできるというわけです
属性に対する明示的な型指定もでき 属性に対する明示的な型指定もできます
```erg ```erg
anonymous = { anonymous = {
@ -39,7 +39,7 @@ anonymous = {
anonymous.name.set! "John" anonymous.name.set! "John"
``` ```
レコードはメソッドも持て レコードはメソッドも持てます
```erg ```erg
o = { o = {
@ -52,8 +52,8 @@ o.inc!()
assert o.i == 1 assert o.i == 1
``` ```
レコードに関して特筆すべき文法があ。レコードの属性値が全てクラス(構造型ではダメ)のとき、そのレコード自体が、自身の属性を要求属性とする型としてふるまうのである レコードに関して特筆すべき文法があります。レコードの属性値が全てクラス(構造型ではダメです)のとき、そのレコード自体が、自身の属性を要求属性とする型としてふるまいます
このような型をレコード型と呼ぶ。詳しくは[レコード]の項を参照してほしい。 このような型をレコード型と呼びます。詳しくは[レコード]の項を参照してください。
```erg ```erg
# レコード # レコード
@ -72,7 +72,7 @@ print! Named.name # Str
## レコードの分解 ## レコードの分解
レコードは以下のようにして分解することができる レコードは以下のようにして分解できます。
```erg ```erg
record = {x = 1; y = 2} record = {x = 1; y = 2}
@ -88,8 +88,8 @@ match point:
{x = x; y = y; z = z} -> "({x}, {y}, {z})" {x = x; y = y; z = z} -> "({x}, {y}, {z})"
``` ```
また、レコードは属性と同名の変数があるとき、例えば`x = x`または`x = .x``x`に、`.x = .x`または`.x = x``.x`に省略することができる また、レコードは属性と同名の変数があるとき、例えば`x = x`または`x = .x``x`に、`.x = .x`または`.x = x``.x`に省略できます。
ただし属性が一つのときはセットと区別するために`;`を付ける必要があ ただし属性が一つのときはセットと区別するために`;`を付ける必要があります
```erg ```erg
x = 1 x = 1
@ -106,7 +106,7 @@ tuple = {x}
assert tuple.1 == 1 assert tuple.1 == 1
``` ```
この構文を利用して、レコードを分解して変数に代入することができる この構文を利用して、レコードを分解して変数に代入できます。
```erg ```erg
# same as `{x = x; y = y} = xy` # same as `{x = x; y = y} = xy`
@ -121,7 +121,7 @@ assert b == 2
## 空レコード ## 空レコード
空のレコードは`{=}`で表される。空のレコードはUnitと同じく自身のクラスそのものでもある 空のレコードは`{=}`で表されます。空のレコードはUnitと同じく、自身のクラスそのものでもあります
```erg ```erg
empty_record = {=} empty_record = {=}
@ -132,10 +132,10 @@ empty_record: Structural {=}
{x = 3; y = 5}: Structural {=} {x = 3; y = 5}: Structural {=}
``` ```
空のレコードは空のDict`{:}`や空のセット`{}`とは異なる。特に`{}`とは意味が正反対なので注意が必要である(Pythonでは`{}`は空の辞書となっているが、Ergでは`!{:}`である)。 空のレコードは空のDict`{:}`や空のセット`{}`とは異なります。特に`{}`とは意味が正反対なので注意が必要です(Pythonでは`{}`は空の辞書となっているが、Ergでは`!{:}`です)。
列挙型としての`{}`は何も要素に含まない空虚な型である。`Never`型は、これをクラス化したものである 列挙型としての`{}`は何も要素に含まない空虚な型です。`Never`型は、これをクラス化したものです
逆に、レコードクラスの`{=}`は要求インスタンス属性がないので、全てのオブジェクトがこれの要素になる。`Object`は、これのエイリアスである 逆に、レコードクラスの`{=}`は要求インスタンス属性がないので、全てのオブジェクトがこれの要素になります。`Object`は、これのエイリアスです
`Object`(のパッチ)は`.__sizeof__`などの極めて基本的な提供メソッドを持 `Object`(のパッチ)は`.__sizeof__`などの極めて基本的な提供メソッドを持ちます
```erg ```erg
AnyPatch = Patch Structural {=} AnyPatch = Patch Structural {=}
@ -145,13 +145,13 @@ AnyPatch = Patch Structural {=}
Never = Class {} Never = Class {}
``` ```
注意として、`{}`, `Never`型と構造的に等価な型・クラスは他に存在できず、ユーザーが`{}`, `Class {}`を右辺に指定して型を定義するとエラーとな 注意として、`{}`, `Never`型と構造的に等価な型・クラスは他に存在できず、ユーザーが`{}`, `Class {}`を右辺に指定して型を定義するとエラーとなります
これにより、例えば`1..10 or -10..-1`とするところを`1..10 and -10..-1`としてしまうようなミスを防ぐことができる これにより、例えば`1..10 or -10..-1`とするところを`1..10 and -10..-1`としてしまうようなミスを防げます
また、合成の結果`Object`となるような型(`Int and Str`など)を定義すると単に`Object`とするように警告が出 また、合成の結果`Object`となるような型(`Int and Str`など)を定義すると単に`Object`とするように警告が出ます
## インスタントブロック ## インスタントブロック
Ergにはもう一つインスタントブロックという構文があるが、これは単に最後に評価した値を返すだけである。属性の保持はできない Ergにはもう一つインスタントブロックという構文がありますが、これは単に最後に評価した値を返すだけです。属性の保持はできません
```erg ```erg
x = x =
@ -166,8 +166,8 @@ y =
## データクラス ## データクラス
素のレコード(レコードリテラルで生成されたレコード)は、これ単体でメソッドを実装しようとすると、直接インスタンスに定義する必要があ 素のレコード(レコードリテラルで生成されたレコード)は、これ単体でメソッドを実装しようとすると、直接インスタンスに定義する必要があります
これは効率が悪く、さらに属性の数が増えていくとエラー表示などが見にくくなり使いにくい。 これは効率が悪く、さらに属性の数が増えていくとエラー表示などが見にくくなり使いにくいです
```erg ```erg
john = { john = {
@ -180,8 +180,8 @@ john + 1
# TypeError: + is not implemented for {name = Str; age = Int; .greet! = Ref(Self).() => None; inc_age! = Ref!(Self).() => None}, Int # TypeError: + is not implemented for {name = Str; age = Int; .greet! = Ref(Self).() => None; inc_age! = Ref!(Self).() => None}, Int
``` ```
そこで、このような場合はレコードクラスを継承するとよい。このようなクラスをデータクラスと呼 そこで、このような場合はレコードクラスを継承します。このようなクラスをデータクラスと呼びます
これについては[クラス](./type/04_class.md)の項で詳しく説明す これについては[クラス](./type/04_class.md)の項で詳しく説明します。
```erg ```erg
Person = Inherit {name = Str; age = Nat} Person = Inherit {name = Str; age = Nat}

View file

@ -18,7 +18,7 @@ assert {1, 2} and {2, 3} == {2}
assert {1, 2} not {2} == {1} assert {1, 2} not {2} == {1}
``` ```
セットは等質なコレクションである。別のクラスのオブジェクトを共存させるためには等質化させなくてはならない セットは等質なコレクションです。別のクラスのオブジェクトを共存させるためには、等質化させなくてはなりません
```erg ```erg
s: {Int or Str} = {"a", 1, "b", -1} s: {Int or Str} = {"a", 1, "b", -1}
@ -26,15 +26,15 @@ s: {Int or Str} = {"a", 1, "b", -1}
## 型としてのセット ## 型としてのセット
セットは型としても扱える。このような型は __列挙型(Enum type)__ と呼ばれる セットは型としても扱えます。このような型は __列挙型(Enum type)__ と呼ばれます
```erg ```erg
i: {1, 2, 3} = 1 i: {1, 2, 3} = 1
assert i in {1, 2, 3} assert i in {1, 2, 3}
``` ```
セットの要素がそのまま型の要素にな セットの要素がそのまま型の要素になります
セット自身は違うことに注意してほしい セット自身は違うことに注意が必要です
```erg ```erg
mut_set = {1, 2, 3}.into {Int; !3} mut_set = {1, 2, 3}.into {Int; !3}

View file

@ -1,13 +1,13 @@
# 所有権システム # 所有権システム
ErgはPythonをホスト言語にした言語であるため、メモリ管理の方法はPythonの処理系に依存してい ErgはPythonをホスト言語にした言語であるため、メモリ管理の方法はPythonの処理系に依存しています
しかし意味論的にはErgのメモリ管理はPythonのそれとは別物である。顕著な違いは、所有権システムと循環参照の禁止に現れている しかし意味論的にはErgのメモリ管理はPythonのそれとは別物です。顕著な違いは、所有権システムと循環参照の禁止に現れています
## 所有権 ## 所有権
ErgはRustから影響を受けた所有権システムを持ってい ErgはRustから影響を受けた所有権システムを持っています
Rustの所有権システムは一般的に難解だと言われているが、Ergのそれは直感的になるよう簡略化されている Rustの所有権システムは一般的に難解だと言われていますが、Ergのそれは直感的になるよう簡略化されています
Ergでは __可変オブジェクト__ に所有権がついており、所有権を失った後はそのオブジェクトを参照できない Ergでは __可変オブジェクト__ に所有権がついており、所有権を失った後はそのオブジェクトを参照できません
```erg ```erg
v = [1, 2, 3].into [Int; !3] v = [1, 2, 3].into [Int; !3]
@ -22,17 +22,17 @@ print! v # error: v was moved
print! w # [1, 2, 3, 4] print! w # [1, 2, 3, 4]
``` ```
所有権の移動はオブジェクトをサブルーチンに渡したときなどに発生す 所有権の移動はオブジェクトをサブルーチンに渡したときなどに発生します。
渡した後も所有権をまだ持っていたい場合は、複製(cloning)、凍結(freeze)、または借用(borrowing)をする必要があ 渡した後も所有権をまだ持っていたい場合は、複製(cloning)、凍結(freeze)、または借用(borrowing)をする必要があります
ただし後述するように借用はできる場面が限られてい ただし後述するように借用はできる場面が限られています
## 複製 ## 複製
オブジェクトを複製してその所有権を移す。実引数に`.clone`メソッドを適用することで行 オブジェクトを複製してその所有権を移します。実引数に`.clone`メソッドを適用することで行います
複製したオブジェクトは複製元のオブジェクトと全く同一になるが、互いに独立しているので、変更の影響は受けない 複製したオブジェクトは複製元のオブジェクトと全く同一になりますが、互いに独立しているので、変更の影響は受けません
複製はPythonのディープコピーに相当し、同一のオブジェクトをまるごと作り直すので、凍結・借用と比べて一般に計算コスト、メモリコストが高 複製はPythonのディープコピーに相当し、同一のオブジェクトをまるごと作り直すので、凍結・借用と比べて一般に計算コスト、メモリコストが高くなります
オブジェクトを複製する必要があるようなサブルーチンは、「引数を消費する」サブルーチンとい オブジェクトを複製する必要があるようなサブルーチンは、「引数を消費する」サブルーチンといいます
```erg ```erg
capitalize s: Str! = capitalize s: Str! =
@ -46,10 +46,10 @@ log s2, s1 # !"HELLO hello"
## 凍結 ## 凍結
不変オブジェクトは複数の場所から参照できることを利用して、可変オブジェクトを不変オブジェクトに変換してしまう 不変オブジェクトは複数の場所から参照できることを利用して、可変オブジェクトを不変オブジェクトに変換します
これを凍結という。凍結は可変配列からイテレータを作るときなどで使われる これを凍結といいます。凍結は可変配列からイテレータを作るときなどで使われます
可変配列からは直接イテレータを作ることができないので、不変配列に変換するのである 可変配列からは直接イテレータを作ることができないので、不変配列に変換します。
配列を壊したくない場合は、[`.freeze_map`メソッド](./type/mut.md)等を使 配列を壊したくない場合は、[`.freeze_map`メソッド](./type/mut.md)等を使います
```erg ```erg
# イテレータが出す値の合計を計算する # イテレータが出す値の合計を計算する
@ -66,8 +66,8 @@ y # この後もyは触れられる
## 借用 ## 借用
借用は複製や凍結よりも低コストである 借用は複製や凍結よりも低コストで
以下のような単純な場合では、借用を行え 以下のような単純な場合では、借用を行えます
```erg ```erg
peek_str ref(s: Str!) = peek_str ref(s: Str!) =
@ -77,8 +77,8 @@ s = !"hello"
peek_str s peek_str s
``` ```
借用した値は元のオブジェクトに対する __参照__ と呼ばれ 借用した値は元のオブジェクトに対する __参照__ と呼ばれます
参照をまた別のサブルーチンに渡す「又貸し」はできるが、借りているだけなので消費することはできない 参照をまた別のサブルーチンに渡す「又貸し」はできますが、借りているだけなので消費することはできません
```erg ```erg
steal_str ref(s: Str!) = steal_str ref(s: Str!) =
@ -96,14 +96,14 @@ steal_str ref(s: Str!) =
x x
``` ```
Ergの参照はRustより制約が強い。参照は言語上第一級のオブジェクトであるが、明示的に生成することはできず、`ref`/`ref!`によって実引数の渡し方として指定できるのみである Ergの参照はRustより制約が強いです。参照は言語上第一級のオブジェクトでが、明示的に生成することはできず、`ref`/`ref!`によって実引数の渡し方として指定できるのみで
これは、参照を配列に詰めたり参照を属性とするクラスを作ったりはできないということを意味す これは、参照を配列に詰めたり参照を属性とするクラスを作ったりはできないということを意味します。
とはいえ、このような制約はそもそも参照のない言語では当たり前の仕様であり、そこまで不便となることはない とはいえ、このような制約はそもそも参照のない言語では当たり前の仕様であり、そこまで不便となることはありません
## 循環参照 ## 循環参照
Ergでは意図せずメモリリークを起こせないように設計されており、メモリーチェッカーが循環参照を検知するとエラーを出す。ほとんどの場合、このエラーは弱参照`Weak`で解消できる。しかしこれでは巡回グラフなどの循環構造を持つオブジェクトを生成できないため、unsafe操作として循環参照を生成できるAPIを実装予定である Ergでは意図せずメモリリークを起こせないように設計されており、メモリーチェッカーが循環参照を検知するとエラーを出します。ほとんどの場合、このエラーは弱参照`Weak`で解消できます。しかし、これでは巡回グラフなどの循環構造を持つオブジェクトを生成できないため、unsafe操作として循環参照を生成できるAPIを実装予定で
<p align='center'> <p align='center'>
<a href='./17_mutability.md'>Previous</a> | <a href='./19_visibility.md'>Next</a> <a href='./17_mutability.md'>Previous</a> | <a href='./19_visibility.md'>Next</a>

View file

@ -1,6 +1,6 @@
# 命名規則 # 命名規則
変数を定数式として使いたい場合は大文字で始まらなくてはならない。二文字以降は小文字でもよい 変数を定数式として使いたい場合は、必ず大文字で始めます。二文字以降は小文字でもよいです
```erg ```erg
i: Option Type = Int i: Option Type = Int
@ -9,8 +9,8 @@ match i:
None -> log "None" None -> log "None"
``` ```
副作用のあるオブジェクトは`!`で終わらなくてはならない。プロシージャとプロシージャルメソッド、そして可変型である 副作用のあるオブジェクトは、必ず`!`で終わります。プロシージャとプロシージャルメソッド、そして可変型です
ただし、`Proc`型自体は可変型ではない ただし、`Proc`型自体は可変型ではありません
```erg ```erg
# Callable == Func or Proc # Callable == Func or Proc
@ -20,7 +20,7 @@ match c:
f -> log "func" f -> log "func"
``` ```
属性を外部に公開したい場合は、`.`始めにつけて定義す`.`を初めにつけなかった場合非公開となる。混乱を避けるため同一のスコープ内で共存はできない 属性を外部に公開したい場合は、初めに`.`をつけて定義します。`.`を初めにつけなかった場合は非公開になります。混乱を避けるため同一のスコープ内で共存はできません
```erg ```erg
o = {x = 1; .x = 2} # SyntaxError: private and public variables with the same name cannot coexist o = {x = 1; .x = 2} # SyntaxError: private and public variables with the same name cannot coexist
@ -28,17 +28,17 @@ o = {x = 1; .x = 2} # SyntaxError: private and public variables with the same na
## リテラル識別子(Literal Identifiers) ## リテラル識別子(Literal Identifiers)
以上の規則は、文字列をシングルクォート('')で囲むと回避でき。すなわち、プロシージャルオブジェクトも`!`をつけずに代入することができる。ただしこの場合、値が定数式でも定数とはみなされない 以上の規則は、文字列をシングルクォート('')で囲むと回避できます。すなわち、プロシージャルオブジェクトも`!`をつけずに代入することができます。ただしこの場合、値が定数式でも定数とはみなされません
このようにシングルクォートで囲まれた文字列による識別子をリテラル識別子とい このようにシングルクォートで囲まれた文字列による識別子をリテラル識別子といいます
これは、Pythonなど他言語のAPI(FFI)を呼び出す際に使 これは、Pythonなど他言語のAPI(FFI)を呼び出す際に使います
```erg ```erg
bar! = pyimport("foo").'bar' bar! = pyimport("foo").'bar'
``` ```
Ergでも有効な識別子の場合は、''で囲む必要はない Ergでも有効な識別子の場合は、''で囲む必要はありません
さらに、リテラル識別子中では記号も空白も入れることができるため、通常は識別子として使えない文字列を識別子として使うことができ さらに、リテラル識別子中では記号も空白も入れることができるため、通常は識別子として使えない文字列を識別子として使うことができます
```erg ```erg
'∂/∂t' y '∂/∂t' y

View file

@ -1,6 +1,6 @@
# 無名関数(anonymous function) # 無名関数(anonymous function)
無名関数は、関数オブジェクトを名付けずその場で生成するための文法である 無名関数は、関数オブジェクトを名付けずその場で生成するための文法で
```erg ```erg
# `->`は無名関数演算子 # `->`は無名関数演算子
@ -10,22 +10,22 @@ f = (x, y) -> x + y
g = (x, y: Int): Int -> x + y g = (x, y: Int): Int -> x + y
``` ```
引数が1つの場合は`()`を省略でき 引数が1つの場合は`()`を省略できます
```erg ```erg
assert [1, 2, 3].map_collect(i -> i + 1) == [2, 3, 4] assert [1, 2, 3].map_collect(i -> i + 1) == [2, 3, 4]
assert ((i, j) -> [i, j])(1, 2) == [1, 2] assert ((i, j) -> [i, j])(1, 2) == [1, 2]
``` ```
下の場合`0..9, (i -> ...)`であって`(0..9, i) -> ...`ではない 下の場合`0..9, (i -> ...)`であって`(0..9, i) -> ...`ではありません
`->`は左辺に一つだけ引数をとる。複数の引数は一つのタプルとして受け取る `->`は左辺に一つだけ引数をとります。複数の引数は一つのタプルとして受け取ります
```erg ```erg
for 0..9, i: Int -> for 0..9, i: Int ->
... ...
``` ```
無名関数では、空白による構文解釈の差異が存在す 無名関数では、空白による構文解釈の差異が存在します。
```erg ```erg
# この場合は`T(() -> Int)`と解釈される # この場合は`T(() -> Int)`と解釈される
@ -34,16 +34,17 @@ i: T () -> Int
k: U() -> Int k: U() -> Int
``` ```
無名関数は引数なしでも使える。`=>`は無名プロシージャ演算子 無名関数は引数なしでも使えます
```erg ```erg
# `=>`は無名プロシージャ演算子
p! = () => print! "`p!` was called" p! = () => print! "`p!` was called"
# `() ->`, `() =>`には`do`, `do!`という糖衣構文がある # `() ->`, `() =>`には`do`, `do!`という糖衣構文がある
# p! = do! print! "`p!` was called" # p! = do! print! "`p!` was called"
p!() # `p!` was called p!() # `p!` was called
``` ```
引数なし関数は遅延初期化に使え 引数なし関数は遅延初期化に使えます
```erg ```erg
time = import "time" time = import "time"
@ -55,8 +56,8 @@ now = if! True:
do date.new("1970", "1", "1", "00", "00") do date.new("1970", "1", "1", "00", "00")
``` ```
型付け、パターンマッチもできる。このため、`match`関数はほとんど無名関数の力で実現されている 型付け、パターンマッチもできます。このため、`match`関数はほとんど無名関数の力で実現されています
`match`関数の引数に与える無名関数は上から順番にトライされる。ので、上の方は特殊なケースを、下に行くほど一般的なケースを記述する必要があ。順番を間違えると(可能な限り)コンパイラがWarningを出す。 `match`関数の引数に与える無名関数は上から順番にトライされます。なので、上の方は特殊なケースを、下に行くほど一般的なケースを記述する必要があります。順番を間違えると(可能な限り)コンパイラがWarningを出します。
```erg ```erg
n = (Complex or Ratio or Int).sample!() n = (Complex or Ratio or Int).sample!()
@ -68,7 +69,7 @@ i = match n:
_ -> panic "cannot convert to Int" # 以上のいずれにも該当しない場合。matchは全パターンを網羅していなくてはならない _ -> panic "cannot convert to Int" # 以上のいずれにも該当しない場合。matchは全パターンを網羅していなくてはならない
``` ```
エラーハンドリングも`?``match`を使用して行うのが一般的である エラーハンドリングも`?``match`を使用して行うのが一般的で
```erg ```erg
res: ParseResult Int res: ParseResult Int

View file

@ -16,7 +16,7 @@ some_proc!: (T, U) => V
## Func Method ## Func Method
メソッド型は、外部からは`Self`で指定できない メソッド型は、外部からは`Self`で指定できません
```erg ```erg
.some_method(self, x: T, y: U) => () .some_method(self, x: T, y: U) => ()
@ -26,7 +26,7 @@ some_proc!: (T, U) => V
## Proc Method (dependent) ## Proc Method (dependent)
以下で、型`T!``N: Nat`という型引数を取るとす。外部から指定する場合は型変数を使用す 以下で、型`T!``N: Nat`という型引数を取るとします。外部から指定する場合は型変数を使用します。
```erg ```erg
T!: Nat -> Type T!: Nat -> Type
@ -34,10 +34,10 @@ T!: Nat -> Type
T!(N).some_method!: (Ref! T!(N ~> N+X), X: Nat) => () T!(N).some_method!: (Ref! T!(N ~> N+X), X: Nat) => ()
``` ```
注意として、`.some_method`の型は`|N, X: Nat| Ref!(T(N ~> N+X)).({X}) => ()`とな 注意として、`.some_method`の型は`|N, X: Nat| Ref!(T(N ~> N+X)).({X}) => ()`となります
`ref!`がついていない、すなわち適用後所有権が奪われるメソッドでは、型引数の遷移(`~>`)を使用できない `ref!`がついていない、すなわち適用後所有権が奪われるメソッドでは、型引数の遷移(`~>`)を使用できません
所有権が奪われる場合は以下のようにな 所有権が奪われる場合は以下のようになります
```erg ```erg
# Nを使わないなら_で省略可 # Nを使わないなら_で省略可
@ -47,8 +47,8 @@ T!(N).some_method!: (Ref! T!(N ~> N+X), X: Nat) => ()
## Operator ## Operator
``で囲むことで通常の関数と同じように定義でき ``で囲むことで通常の関数と同じように定義できます
`and``or`などの中置アルファベット演算子は囲むことで中置演算子として定義でき `and``or`などの中置アルファベット演算子は囲むことで中置演算子として定義できます
```erg ```erg
and(x, y, z) = x and y and z and(x, y, z) = x and y and z

View file

@ -1,6 +1,6 @@
# クロージャ # クロージャ
Ergのサブルーチンには、外部変数を捕捉する「クロージャ」という機能があ Ergのサブルーチンには、外部変数を捕捉する「クロージャ」という機能があります
```erg ```erg
outer = 1 outer = 1
@ -8,7 +8,7 @@ f x = outer + x
assert f(1) == 2 assert f(1) == 2
``` ```
不変オブジェクトと同じく、可変オブジェクトも捕捉でき 不変オブジェクトと同じく、可変オブジェクトも捕捉できます
```erg ```erg
sum = !0 sum = !0
@ -22,8 +22,8 @@ p!(1)
assert sum == 46 assert sum == 46
``` ```
しかし、関数は可変オブジェクトを捕捉できないので注意が必要である しかし、関数は可変オブジェクトを捕捉できないので注意が必要で
仮に可変オブジェクトが関数内で参照できると、以下のようなコードが書けてしま 仮に可変オブジェクトが関数内で参照できると、以下のようなコードが書けてしまいます
```erg ```erg
# !!! このコードは実際にはエラーになる !!! # !!! このコードは実際にはエラーになる !!!
@ -34,10 +34,10 @@ i.add! 1
assert f 1 == 2 assert f 1 == 2
``` ```
関数は同じ引数に対して同じ値を返すべきだが、その前提が破れてしまっている 関数は同じ引数に対して同じ値を返すべきですが、その前提が破れてしまっています
`i`は呼び出し時に初めて評価されることに注意してほしい。 `i`は呼び出し時に初めて評価されることに注意してください。
関数定義時点での可変オブジェクトの内容がほしい場合は`.clone` 関数定義時点での可変オブジェクトの内容がほしい場合は`.clone`を呼び出します。
```erg ```erg
i = !0 i = !0
@ -58,7 +58,7 @@ for! 1..10, i =>
assert sum == 45 assert sum == 45
``` ```
上と同等のプログラムは、Pythonでは以下のように記述でき 上と同等のプログラムは、Pythonでは以下のように記述できます
```python ```python
# Python # Python
@ -68,8 +68,8 @@ for i in range(1, 10):
assert sum == 45 assert sum == 45
``` ```
しかしErgではもっとシンプルな書き方を推奨す しかしErgではもっとシンプルな書き方を推奨します。
サブルーチンと可変オブジェクトを使って状態を持ち回す代わりに、関数を使用する状態を局所化するスタイルである。これは関数型プログラミングと呼ばれる サブルーチンと可変オブジェクトを使って状態を持ち回す代わりに、関数を使用する状態を局所化するスタイルを使います。これは関数型プログラミングと呼ばれます
```erg ```erg
# Functional style # Functional style
@ -77,11 +77,11 @@ sum = (1..10).sum()
assert sum == 45 assert sum == 45
``` ```
上のコードは先程と全く同じ結果となるが、こちらのほうが遥かにシンプルであることが見て取れる 上のコードは先程と全く同じ結果になりますが、こちらのほうが遥かにシンプルであることが見て取れます
`fold`関数を使用すれば、合計以外にも多様な操作を行うことができ `fold`関数を使用すれば、合計以外にも多様な操作を行うことができます
`fold`はイテレータのメソッドで、各イテレーションごとに引数`f`を実行す `fold`はイテレータのメソッドで、各イテレーションごとに引数`f`を実行します。
結果を蓄積するカウンタの初期値は`init`で指定し、`acc`に蓄積されてい 結果を蓄積するカウンタの初期値は`init`で指定し、`acc`に蓄積されていきます
```erg ```erg
# start with 0, result will # start with 0, result will
@ -89,7 +89,7 @@ sum = (1..10).fold(init: 0, f: (acc, i) -> acc + i)
assert sum == 45 assert sum == 45
``` ```
Ergは不変オブジェクトによるプログラミングで自然と簡潔な記述となるように設計されている 不変オブジェクトによるプログラミングで自然と簡潔な記述となるように、Ergは設計されています
<p align='center'> <p align='center'>
<a href='./22_subroutine.md'>Previous</a> | <a href='./24_module.md'>Next</a> <a href='./22_subroutine.md'>Previous</a> | <a href='./24_module.md'>Next</a>

View file

@ -1,19 +1,19 @@
# Object(対象体) # Object(対象体)
変数に代入できる全てのデータ。`Object`クラスの持つ属性は以下の通り。 変数に代入できる全てのデータです`Object`クラスの持つ属性は以下の通りです
* `.__repr__`: オブジェクトの(リッチでない)文字列表現を返す * `.__repr__`: オブジェクトの(リッチでない)文字列表現を返しま
* `.__sizeof__`: オブジェクトのサイズ(ヒープ確保分含む)を返す * `.__sizeof__`: オブジェクトのサイズ(ヒープ確保分含む)を返しま
* `.__dir__`: オブジェクトの属性を一覧にして返す * `.__dir__`: オブジェクトの属性を一覧にして返しま
* `.__hash__`: オブジェクトのハッシュ値を返す * `.__hash__`: オブジェクトのハッシュ値を返しま
* `.__getattribute__`: オブジェクトの属性を取得して返す * `.__getattribute__`: オブジェクトの属性を取得して返しま
* `.clone`: オブジェクトのクローン(メモリ上に独立な実体を持つ)を生成して返す * `.clone`: オブジェクトのクローン(メモリ上に独立な実体を持つ)を生成して返しま
* `.copy`: オブジェクトのコピー(メモリ上で同じものをさす)を返す * `.copy`: オブジェクトのコピー(メモリ上で同じものをさす)を返しま
## Record(レコード) ## Record(レコード)
レコードリテラル(`{attr = value; ...}`)で生成されるオブジェクト。 レコードリテラル(`{attr = value; ...}`)で生成されるオブジェクトです
このオブジェクトは`.clone``.__sizeof__`などの基本的なメソッドを持 このオブジェクトは`.clone``.__sizeof__`などの基本的なメソッドを持ちます
```erg ```erg
obj = {.x = 1} obj = {.x = 1}
@ -25,7 +25,7 @@ assert obj2.x == 1 and obj2.y == 2
## Attribute(属性) ## Attribute(属性)
オブジェクトと関連付けられたオブジェクト。特に自身(`self`)を暗黙の第一引数にとるサブルーチン属性はメソッド(method)と呼ばれ オブジェクトと関連付けられたオブジェクトです。特に自身(`self`)を暗黙の第一引数にとるサブルーチン属性はメソッド(method)と呼ばれます
```erg ```erg
# private_attrには`.`がないことに注意 # private_attrには`.`がないことに注意
@ -37,45 +37,45 @@ assert record.method() == 3
## Element(要素) ## Element(要素)
特定の型に属するオブジェクト(e.g. `1``Int`型の要素)。全てのオブジェクトは、少なくとも`{=}`型の要素である 特定の型に属するオブジェクト(e.g. `1``Int`型の要素)です。全てのオブジェクトは、少なくとも`{=}`型の要素で
クラスの要素の場合特にインスタンス(Instance)と呼ぶこともあ クラスの要素の場合特にインスタンス(Instance)と呼ぶこともあります
## Subroutine(サブルーチン) ## Subroutine(サブルーチン)
関数またはプロシージャのインスタンスであるオブジェクトを示す(メソッドも含む)。サブルーチンを表すクラスは`Subroutine`ある 関数またはプロシージャのインスタンスであるオブジェクトを示す(メソッドも含む)。サブルーチンを表すクラスは`Subroutine`
より一般に`.__call__`を実装するオブジェクトは`Callable`(呼び出し可能オブジェクト)と呼ばれ より一般に`.__call__`を実装するオブジェクトは`Callable`(呼び出し可能オブジェクト)と呼ばれます
## Callable(呼び出し可能オブジェクト) ## Callable(呼び出し可能オブジェクト)
`.__call__`を実装するオブジェクト。`Subroutine`のスーパークラス。 `.__call__`を実装するオブジェクトです`Subroutine`のスーパークラスでもあります
## Type(型) ## Type(型)
要求属性を定義し、オブジェクトを共通化するオブジェクト。 要求属性を定義し、オブジェクトを共通化するオブジェクトです
大きく分けて多相型(Polymorphic Type)と単相型(Monomorphic Type)の2つがあ。典型的な単相型は`Int`, `Str`などで、多相型には`Option Int`, `[Int; 3]`などがあ 大きく分けて多相型(Polymorphic Type)と単相型(Monomorphic Type)の2つがあります。典型的な単相型は`Int`, `Str`などで、多相型には`Option Int`, `[Int; 3]`などがあります
さらにオブジェクトの状態変更をするメソッドを定義した型は可変型(Mutable type)と呼ばれ、可変な属性に`!`をつける必要があ(e.g. 動的配列: `[T; !_]`)。 さらにオブジェクトの状態変更をするメソッドを定義した型は可変型(Mutable type)と呼ばれ、可変な属性に`!`をつける必要があります(e.g. 動的配列: `[T; !_]`)。
## Class(クラス) ## Class(クラス)
`.__new__`, `.__init__`メソッドなどを持つ型。クラスベースのオブジェクト指向を実現す `.__new__`, `.__init__`メソッドなどを持つ型です。クラスベースのオブジェクト指向を実現します。
## Function(関数、写像) ## Function(関数、写像)
外部変数(静的変数除く)のread権限はあるが、外部変数のread/write権限がないサブルーチン。つまり、外部に副作用を及ぼせない 外部変数(静的変数除く)のread権限はありますが、外部変数のread/write権限がないサブルーチンです。つまり、外部に副作用を及ぼせません
Ergの関数(Function)は副作用を許さないのでPythonのそれとは定義が異なる Ergの関数(Function)は副作用を許さないので、Pythonのそれとは定義が異なります
## Procedure(手続) ## Procedure(手続)
外部変数のread権限および`self`、静的変数のread/write権限があり、全てのサブルーチンの使用が許可されている。外部に副作用を及ぼせる 外部変数のread権限および`self`、静的変数のread/write権限があり、全てのサブルーチンの使用が許可されています。外部に副作用を及ぼせます
## Method(メソッド) ## Method(メソッド)
第一引数に`self`を暗黙的にとるサブルーチン。単なる関数/プロシージャとは別の型となってい 第一引数に`self`を暗黙的にとるサブルーチンです。単なる関数/プロシージャとは別の型となっています
## Entity(エンティティ) ## Entity(エンティティ)
サブルーチンおよび型ではないオブジェクト。 サブルーチンおよび型ではないオブジェクトです
単相型エンティティ(`1`, `"a"`など)は値オブジェクト、多相型エンティティ(`[1, 2, 3], {"a": 1}`)はコンテナオブジェクトとも呼ばれ 単相型エンティティ(`1`, `"a"`など)は値オブジェクト、多相型エンティティ(`[1, 2, 3], {"a": 1}`)はコンテナオブジェクトとも呼ばれます
<p align='center'> <p align='center'>
<a href='./24_module.md'>Previous</a> | <a href='./26_pattern_matching.md'>Next</a> <a href='./24_module.md'>Previous</a> | <a href='./26_pattern_matching.md'>Next</a>

View file

@ -11,6 +11,7 @@ i = 1
i: Int = 1 i: Int = 1
# with anonymous type # with anonymous type
i: {1, 2, 3} = 2 i: {1, 2, 3} = 2
# function # function
fn x = x + 1 fn x = x + 1
# equals # equals
@ -18,6 +19,7 @@ fn x: Add(Int) = x + 1
# (anonymous) function # (anonymous) function
fn = x -> x + 1 fn = x -> x + 1
fn: Int -> Int = x -> x + 1 fn: Int -> Int = x -> x + 1
# higher-order type # higher-order type
a: [Int; 4] = [0, 1, 2, 3] a: [Int; 4] = [0, 1, 2, 3]
# or # or
@ -27,14 +29,16 @@ a: Array Int, 4 = [0, 1, 2, 3]
### リテラルパターン ### リテラルパターン
```erg ```erg
# if `i` cannot be determined to be 1 at compile time, TypeError occurs. # もし`i`がコンパイル時に1と判断できない場合は、TypeErrorが発生する。
# short hand of `_: {1} = i` # `_: {1} = i`を省略したもの
1 = i 1 = i
# simple pattern matching # simple pattern matching
match x: match x:
1 -> "1" 1 -> "1"
2 -> "2" 2 -> "2"
_ -> "other" _ -> "other"
# fibonacci function # fibonacci function
fib 0 = 0 fib 0 = 0
fib 1 = 1 fib 1 = 1
@ -61,8 +65,8 @@ name = match num:
### 篩パターン ### 篩パターン
```erg ```erg
# この2つは同じ
Array(T, N: {N | N >= 3}) Array(T, N: {N | N >= 3})
# ==
Array(T, N | N >= 3) Array(T, N | N >= 3)
f M, N | M >= 0, N >= 1 = ... f M, N | M >= 0, N >= 1 = ...
@ -80,7 +84,7 @@ right(_, r) = r
### 可変長パターン ### 可変長パターン
後述するタプル/配列/レコードパターンと組み合わせて使 後述するタプル/配列/レコードパターンと組み合わせて使います
```erg ```erg
[i, ...j] = [1, 2, 3, 4] [i, ...j] = [1, 2, 3, 4]

View file

@ -2,23 +2,33 @@
`[expr | (name <- iterable)+ (predicate)*]`で配列、 `[expr | (name <- iterable)+ (predicate)*]`で配列、
`{expr | (name <- iterable)+ (predicate)*}`でセット、 `{expr | (name <- iterable)+ (predicate)*}`でセット、
`{key: value | (name <- iterable)+ (predicate)*}`でDictが作れ `{key: value | (name <- iterable)+ (predicate)*}`でDictが作れます
`|`で区切られた節のうち最初の部分をレイアウト節(配置節)といい、2番目の部分をバインド節(束縛節)、3番目の部分をガード節(条件節)という。 `|`で区切られた節のうち最初の部分をレイアウト節(配置節)といい、2番目の部分をバインド節(束縛節)、3番目の部分をガード節(条件節)という。
ガード節は省略可能であるがバインド節は省略できず、バインド節より先にガード節を置くことはできない ガード節は省略可能でがバインド節は省略できず、バインド節より先にガード節を置くことはできません
e.g. 内包表記の例
```erg ```erg
# レイアウト節はi
# バインド節はi <- [0, 1, 2]
assert [i | i <- [0, 1, 2]] == [0, 1, 2] assert [i | i <- [0, 1, 2]] == [0, 1, 2]
# レイアウト節はi / 2
# バインド節はi <- 0..2
assert [i / 2 | i <- 0..2] == [0.0, 0.5, 1.0] assert [i / 2 | i <- 0..2] == [0.0, 0.5, 1.0]
# レイアウト節は(i, j)
# バインド節はi <- 0..2, j <- 0..2
# ガード節は(i + j) % 2 == 0
assert [(i, j) | i <- 0..2; j <- 0..2; (i + j) % 2 == 0] == [(0, 0), (0, 2), (1, 1), (2, 0), (2, 2)] assert [(i, j) | i <- 0..2; j <- 0..2; (i + j) % 2 == 0] == [(0, 0), (0, 2), (1, 1), (2, 0), (2, 2)]
assert {i % 2 | i <- 0..9} == {0, 1} assert {i % 2 | i <- 0..9} == {0, 1}
assert {k: v | k <- ["a", "b"]; v <- [1, 2]} == {"a": 1, "b": 2} assert {k: v | k <- ["a", "b"]; v <- [1, 2]} == {"a": 1, "b": 2}
``` ```
Ergの内包表記はHaskellに影響を受けているが、若干の違いがあ Ergの内包表記はHaskellに影響を受けているが、若干の違いがあります
Haskellのリスト内包表記の場合、変数の順番は結果に違いをもたらすが、Ergでは関係がない Haskellのリスト内包表記の場合、変数の順番は結果に違いをもたらしますが、Ergでは関係がありません
```haskell ```haskell
-- Haskell -- Haskell
@ -31,7 +41,7 @@ Haskellのリスト内包表記の場合、変数の順番は結果に違いを
assert [(i, j) | i <- 1..<3; j <- 3..<5] == [(i, j) | j <- 3..<5; i <- 1..<3] assert [(i, j) | i <- 1..<3; j <- 3..<5] == [(i, j) | j <- 3..<5; i <- 1..<3]
``` ```
れはPythonと同じである の仕様はPythonのものと同じです
```python ```python
# Python # Python
@ -40,8 +50,8 @@ assert [(i, j) for i in range(1, 3) for j in range(3, 5)] == [(i, j) for j in ra
## 篩型 ## 篩型
内包表記と似たものに、篩型がある。篩型は`{Name: Type | Predicate}`という形式で作られる型(列挙型)である 内包表記と似たものに、篩型があります。篩型は`{Name: Type | Predicate}`という形式で作られる型(列挙型)です
篩型の場合、Nameは1つまででレイアウトは指定できず(ただしタプル型などにすれば複数の値は扱える)、Predicateはコンパイル時計算できるもの、つまり定数式でなくてはならない 篩型の場合、Nameは1つまででレイアウトは指定できず(ただしタプル型などにすれば複数の値は扱えます)、Predicateはコンパイル時計算できるもの、つまり定数式のみが指定できます
```erg ```erg
Nat = {I: Int | I >= 0} Nat = {I: Int | I >= 0}

View file

@ -1,6 +1,6 @@
# Spread assignment (展開代入) # Spread assignment (展開代入)
分解代入において、変数の前に`...`を置くと残りの要素を全てその変数に展開できる。これを展開代入と呼ぶ 分解代入において、変数の前に`...`を置くと残りの要素を全てその変数に展開できます。これを展開代入と呼びます
```erg ```erg
[x, ...y] = [1, 2, 3] [x, ...y] = [1, 2, 3]
@ -13,23 +13,23 @@ assert y == (2, 3)
## Extract assignment (抽出代入) ## Extract assignment (抽出代入)
`...`のあとに何も書かない場合、残りの要素は無視して代入される。このタイプの展開代入を特に抽出代入と呼ぶ `...`のあとに何も書かない場合、残りの要素は無視して代入されます。このタイプの展開代入を特に抽出代入と呼びます
抽出代入は、モジュールやレコード内にある特定の属性をローカルに持ってくる際に便利な構文である 抽出代入は、モジュールやレコード内にある特定の属性をローカルに持ってくる際に便利な構文で
```erg ```erg
{sin; cos; tan; ..} = import "math" {sin; cos; tan; ..} = import "math"
``` ```
このようにすると、以降はローカルで`sin, cos, tan`が使用でき このようにすると、以降はローカルで`sin, cos, tan`が使用できます
レコードでも同じようにでき レコードでも同じようにできます
```erg ```erg
record = {x = 1; y = 2} record = {x = 1; y = 2}
{x; y; ...} = record {x; y; ...} = record
``` ```
全て展開したい場合は`{*} = record`する。OCamlなどでいう`open`である 全て展開したい場合は`{*} = record`します。OCamlなどでいう`open`です
```erg ```erg
record = {x = 1; y = 2} record = {x = 1; y = 2}

View file

@ -1,11 +1,11 @@
# エラーハンドリングシステム # エラーハンドリングシステム
主にResult型を使用す 主にResult型を使用します。
ErgではError型オブジェクトを捨てる(トップレベルで対応しない)とエラーが発生す ErgではError型オブジェクトを捨てる(トップレベルで対応しない)とエラーが発生します。
## 例外、Pythonとの相互運用 ## 例外、Pythonとの相互運用
Ergは例外機構(Exception)を持たない。Pythonの関数をインポートする際は Ergは例外機構(Exception)を持ちません。Pythonの関数をインポートする際は
* 戻り値を`T or Error`型とする * 戻り値を`T or Error`型とする
* `T or Panic`型(実行時エラーを出す可能性がある)とする * `T or Panic`型(実行時エラーを出す可能性がある)とする
@ -15,8 +15,8 @@ Ergは例外機構(Exception)を持たない。Pythonの関数をインポート
## 例外とResult型 ## 例外とResult型
`Result`型はエラーかもしれない値を表現す`Result`によるエラーハンドリングはいくつかの点で例外機構よりも優れてい `Result`型はエラーかもしれない値を表現します。`Result`によるエラーハンドリングはいくつかの点で例外機構よりも優れています
まず第一に、サブルーチンがエラーを出すかもしれないと型定義から分かり、実際に使用するときも一目瞭然なのである まず第一に、サブルーチンがエラーを出すかもしれないと型定義から分かり、実際に使用するときも一目瞭然です
```python ```python
# Python # Python
@ -28,7 +28,7 @@ except e:
print(e) print(e)
``` ```
上の例では、例外がどの関数から送出されたものなのか、このコードだけでは分からない。関数定義まで遡っても、その関数が例外を出すかは判別しにくい 上の例では、例外がどの関数から送出されたものなのか、このコードだけでは分かりません。関数定義まで遡っても、その関数が例外を出すかを判別するのは難しいです
```erg ```erg
# Erg # Erg
@ -41,14 +41,14 @@ try!:
print! e print! e
``` ```
翻って、こちらの例では`foo!``qux!`がエラーを出しうるとわか 翻って、こちらの例では`foo!``qux!`がエラーを出しうるとわかります
正確には`y``Result`型である可能性があるが、中の値を使用するためにはいずれ対処しなくてはならない 正確には`y``Result`型である可能性がありますが、中の値を使用するためにはいずれ対処しなくてはなりません
`Result`型を使用するメリットはそれだけではない。`Result`型はスレッドセーフでもある。これは、エラー情報を並列実行中に(容易に)受け渡しできるということを意味す `Result`型を使用するメリットはそれだけではありません。`Result`型はスレッドセーフでもあります。これは、エラー情報を並列実行中に(容易に)受け渡しできるということを意味します。
## Context ## Context
`Error`/`Result`型単体では副作用が発生しないので、例外と違い送出場所などの情報(Context、文脈)を持てないが、`.context`メソッドを使えば`Error`オブジェクトに情報を付加でき`.context`メソッドは`Error`オブジェクト自身を消費して新しい`Error`オブジェクトを作るタイプのメソッドである。チェイン可能であり、複数のコンテクストを保持できる `Error`/`Result`型単体では副作用が発生しないので、例外と違い送出場所などの情報(Context、文脈)を持てませんが、`.context`メソッドを使えば`Error`オブジェクトに情報を付加できます`.context`メソッドは`Error`オブジェクト自身を消費して新しい`Error`オブジェクトを作るタイプのメソッドです。チェイン可能であり、複数のコンテクストを保持できます
```erg ```erg
f() = f() =
@ -62,14 +62,14 @@ f()
# hint: and more hints ... # hint: and more hints ...
``` ```
なお、`.msg``.kind`などの`Error`の属性は副次的なものではないのでcontextではなく、最初に生成されたときのまま上書きできない なお、`.msg``.kind`などの`Error`の属性は副次的なものではないのでcontextではなく、最初に生成されたときのまま上書きできません
## スタックトレース ## スタックトレース
`Result`型はその利便性から他言語でも多く取り入れられていが、例外機構と比較してエラーの発生元がわかりにくくなるというデメリットがあ `Result`型はその利便性から他言語でも多く取り入れられていますが、例外機構と比較してエラーの発生元がわかりにくくなるというデメリットがあります
そこで、Ergでは`Error`オブジェクトに`.stack`という属性を持たせており、擬似的に例外機構のようなスタックトレースを再現してい そこで、Ergでは`Error`オブジェクトに`.stack`という属性を持たせており、擬似的に例外機構のようなスタックトレースを再現しています
`.stack`は呼び出し元オブジェクトの配列である。Errorオブジェクトは`return`(`?`によるものも含む)されるたびにその呼出元サブルーチンを`.stack`に積んでい `.stack`は呼び出し元オブジェクトの配列で。Errorオブジェクトは`return`(`?`によるものも含む)されるたびにその呼出元サブルーチンを`.stack`に積んでいきます
そして`return`ができないコンテクストで`?`されるなり`.unwrap`されるなりすると、トレースバックを表示しながらパニックす そして`return`ができないコンテクストで`?`されるなり`.unwrap`されるなりすると、トレースバックを表示しながらパニックします。
```erg ```erg
f x = f x =
@ -95,10 +95,10 @@ i = g(1)?
## パニック ## パニック
Ergには回復不能なエラーへの対処として __パニッキング__ という機構も存在す Ergには回復不能なエラーへの対処として __パニッキング__ という機構も存在します。
回復不能なエラーとは、例えばソフト/ハードウェアの不具合など外的要因によるエラーや、それ以上コードを実行し続けても意味がないほど致命的なエラー、あるいはプログラム作成者の想定だにしないエラーなどである。これが発生した場合、プログラマの努力によって正常系に復帰させることができないため、その場でプログラムを終了させる。これを「パニックさせる」という 回復不能なエラーとは、例えばソフト/ハードウェアの不具合など外的要因によるエラーや、それ以上コードを実行し続けても意味がないほど致命的なエラー、あるいはプログラム作成者の想定だにしないエラーなどで。これが発生した場合、プログラマの努力によって正常系に復帰させることができないため、その場でプログラムを終了させます。これを「パニックさせる」といいます
パニックは`panic`関数で行 パニックは`panic`関数で行います
```erg ```erg
panic "something went wrong!" panic "something went wrong!"

View file

@ -1,24 +1,27 @@
# パイプライン演算子 # パイプライン演算子
パイプライン演算子は、次のように使 パイプライン演算子は、次のように使います
```erg ```erg
assert f(g(x)) == (x |> g |> f) assert f(g(x)) == (x |> g |> f)
assert f(g(x, y)) == ((x, y) |> g |> f) assert f(g(x, y)) == ((x, y) |> g |> f)
``` ```
つまり、`Callable(object)`という順序を`object |> Callable`と変えられるのである つまり、`Callable(object)`という順序を`object |> Callable`に変えられます
パイプライン演算子はメソッドに対しても使え。メソッドの場合、`object.method(args)``object |>.method(args)`と変わ パイプライン演算子はメソッドに対しても使えます。メソッドの場合、`object.method(args)``object |>.method(args)`と変わります
単に`|>`が増えただけにも見えるが、結合強度が低めなので`()`の量を減らせる場合があ 単に`|>`が増えただけにも見えるが、結合強度が低めなので`()`の量を減らせる場合があります
```erg ```erg
rand = -1.0..1.0 |>.sample!() rand = -1.0..1.0 |>.sample!()
log rand # 0.2597... log rand # 0.2597...
1+1*2 |>.times do log("a", end: "") # aaa 1+1*2 |>.times do log("a", end: "") # aaa
# without `|>`, the following will be `evens = (1..100).iter().filter(i -> i % 2 == 0).collect(Array)`
evens = 1..100 |>.iter |>.filter i -> i % 2 == 0 |>.collect Array evens = 1..100 |>.iter |>.filter i -> i % 2 == 0 |>.collect Array
# or # パイプライン演算子を使わずに実装する場合、
_evens = 1..100 \ _evens = (1..100).iter().filter(i -> i % 2 == 0).collect(Array)
# または
__evens = 1..100 \
.iter() \ .iter() \
.filter i -> i % 2 == 0 \ .filter i -> i % 2 == 0 \
.collect Array .collect Array

View file

@ -57,7 +57,7 @@ Iterable T = Trait {
} }
``` ```
また、クラス定義時に部分型指定を行うと、クラスが指定した型のサブタイプか静的に検査することができます。 また、クラス定義時に部分型指定を行うと、クラスが指定した型のサブタイプか静的に検査できます。
```erg ```erg
# クラスCはShowのサブタイプ # クラスCはShowのサブタイプ
@ -87,7 +87,7 @@ C.shoe self = ... # TypoのせいでShowが実装できていない(単なる固
## 属性定義 ## 属性定義
トレイトやクラスには、モジュール内でのみ属性を定義することができます。 トレイトやクラスには、モジュール内でのみ属性を定義できます。
```erg ```erg
C = Class() C = Class()

View file

@ -10,7 +10,7 @@ Norm = Trait {.x = Int; .y = Int; .norm = Self.() -> Int}
トレイトは属性とメソッドを区別しません。 トレイトは属性とメソッドを区別しません。
トレイトは宣言ができるのみで実装を持てないことに注意してください(実装は後に述べるパッチという機能で実現します)。 トレイトは宣言ができるのみで実装を持てないことに注意してください(実装は後に述べるパッチという機能で実現します)。
トレイトは部分型指定でクラスに実装されているかチェックすることができます。 トレイトは部分型指定でクラスに実装されているかチェックできます。
```erg ```erg
Point2D <: Norm Point2D <: Norm

View file

@ -257,7 +257,7 @@ assert x1 == x2
## 包含関係 ## 包含関係
クラスは、要件型のサブタイプです。要件型のメソッド(パッチメソッド含む)を使用することができます。 クラスは、要件型のサブタイプです。要件型のメソッド(パッチメソッド含む)を使用できます。
```erg ```erg
T = Trait ... T = Trait ...

View file

@ -3,7 +3,7 @@
> __Warning__: この項の情報は古く、一部に間違いを含みます。 > __Warning__: この項の情報は古く、一部に間違いを含みます。
Ergではデフォルトですべての型が不変型、すなわち内部状態を更新できないようになっています。 Ergではデフォルトですべての型が不変型、すなわち内部状態を更新できないようになっています。
しかし可変な型ももちろん定義することができます。可変型は`!`を付けて宣言します。 しかし可変な型ももちろん定義できます。可変型は`!`を付けて宣言します。
```erg ```erg
Person! = Class({name = Str; age = Nat!}) Person! = Class({name = Str; age = Nat!})

View file

@ -44,7 +44,7 @@ print! nil().head() # TypeError
``` ```
巷でよく説明されるGADTsの例は、以上のように中身が空か否か型で判定できるリストです。 巷でよく説明されるGADTsの例は、以上のように中身が空か否か型で判定できるリストです。
Ergではさらに精密化して、長さを持つリストを定義することができます。 Ergではさらに精密化して、長さを持つリストを定義できます。
```erg ```erg
List: (Type, Nat) -> Type List: (Type, Nat) -> Type

View file

@ -47,7 +47,7 @@ Ergにはもう一つ変性がある。それは非変性(non-variance)である
## 変性指定された全称型 ## 変性指定された全称型
全称型の型変数は、その上限・下限を指定することができます。 全称型の型変数は、その上限・下限を指定できます。
```erg ```erg
|A <: T| K(A) |A <: T| K(A)

View file

@ -2,7 +2,7 @@
ここでは、Rustでよく使われるnewtypeパターンのErg版を紹介します。 ここでは、Rustでよく使われるnewtypeパターンのErg版を紹介します。
Ergはでは以下のように型のエイリアスを定義することができますが、これはあくまで同じ型を指します。 Ergはでは以下のように型のエイリアスを定義できますが、これはあくまで同じ型を指します。
```erg ```erg
UserId = Int UserId = Int

View file

@ -1,10 +1,11 @@
use std::fs::remove_file;
use std::io::{Read, Write}; use std::io::{Read, Write};
use std::net::TcpStream; use std::net::TcpStream;
use std::thread::sleep; use std::thread::sleep;
use std::time::Duration; use std::time::Duration;
use erg_common::config::{ErgConfig, Input, BUILD_INFO, SEMVER}; use erg_common::config::{ErgConfig, Input, BUILD_INFO, SEMVER};
use erg_common::python_util::exec_py; use erg_common::python_util::{exec_py, exec_pyc};
use erg_common::str::Str; use erg_common::str::Str;
use erg_common::traits::Runnable; use erg_common::traits::Runnable;
@ -16,7 +17,7 @@ use erg_compiler::Compiler;
pub struct DummyVM { pub struct DummyVM {
cfg: ErgConfig, cfg: ErgConfig,
compiler: Compiler, compiler: Compiler,
stream: TcpStream, stream: Option<TcpStream>,
} }
impl Runnable for DummyVM { impl Runnable for DummyVM {
@ -24,23 +25,25 @@ impl Runnable for DummyVM {
type Errs = CompileErrors; type Errs = CompileErrors;
fn new(cfg: ErgConfig) -> Self { fn new(cfg: ErgConfig) -> Self {
println!("Starting the REPL server..."); let stream = if cfg.input.is_repl() {
let code = include_str!("scripts/repl_server.py"); println!("Starting the REPL server...");
exec_py(code); let code = include_str!("scripts/repl_server.py");
println!("Connecting to the REPL server..."); exec_py(code);
let repl_server_ip = "127.0.0.1"; println!("Connecting to the REPL server...");
let repl_server_port = 8736; let repl_server_ip = "127.0.0.1";
let addr = format!("{repl_server_ip}:{repl_server_port}"); let repl_server_port = 8736;
let stream = loop { let addr = format!("{repl_server_ip}:{repl_server_port}");
match TcpStream::connect(&addr) { loop {
Ok(stream) => break stream, match TcpStream::connect(&addr) {
Err(_) => { Ok(stream) => break Some(stream),
println!("Retrying to connect to the REPL server..."); Err(_) => {
sleep(Duration::from_millis(500)); println!("Retrying to connect to the REPL server...");
continue; sleep(Duration::from_millis(500));
continue;
}
} }
} }
}; } else { None };
Self { Self {
compiler: Compiler::new(cfg.copy()), compiler: Compiler::new(cfg.copy()),
cfg, cfg,
@ -59,17 +62,19 @@ impl Runnable for DummyVM {
} }
fn finish(&mut self) { fn finish(&mut self) {
self.stream.write_all("exit".as_bytes()).unwrap(); if let Some(stream) = &mut self.stream {
let mut buf = [0; 1024]; stream.write_all("exit".as_bytes()).unwrap();
match self.stream.read(&mut buf) { let mut buf = [0; 1024];
Result::Ok(n) => { match stream.read(&mut buf) {
let s = std::str::from_utf8(&buf[..n]).unwrap(); Result::Ok(n) => {
if s.contains("closed") { let s = std::str::from_utf8(&buf[..n]).unwrap();
println!("The REPL server is closed."); if s.contains("closed") {
println!("The REPL server is closed.");
}
}
Result::Err(e) => {
panic!("{}", format!("Read error: {e}"));
} }
}
Result::Err(e) => {
panic!("{}", format!("Read error: {e}"));
} }
} }
} }
@ -78,13 +83,22 @@ impl Runnable for DummyVM {
self.compiler.clear(); self.compiler.clear();
} }
fn exec(&mut self) -> Result<(), Self::Errs> {
let src = self.input().read();
self.compiler
.compile_and_dump_as_pyc(src, "o.pyc", "exec")?;
exec_pyc("o.pyc");
remove_file("o.pyc").unwrap();
Ok(())
}
fn eval(&mut self, src: Str) -> Result<String, CompileErrors> { fn eval(&mut self, src: Str) -> Result<String, CompileErrors> {
self.compiler self.compiler
.compile_and_dump_as_pyc(src, "o.pyc", "eval")?; .compile_and_dump_as_pyc(src, "o.pyc", "eval")?;
let mut res = match self.stream.write("load".as_bytes()) { let mut res = match self.stream.as_mut().unwrap().write("load".as_bytes()) {
Result::Ok(_) => { Result::Ok(_) => {
let mut buf = [0; 1024]; let mut buf = [0; 1024];
match self.stream.read(&mut buf) { match self.stream.as_mut().unwrap().read(&mut buf) {
Result::Ok(n) => { Result::Ok(n) => {
let s = std::str::from_utf8(&buf[..n]).unwrap(); let s = std::str::from_utf8(&buf[..n]).unwrap();
s.to_string() s.to_string()