Merge branch 'main' into dict

This commit is contained in:
Shunsuke Shibayama 2022-10-10 13:57:08 +09:00
commit c784ba261e
53 changed files with 1336 additions and 818 deletions

View file

@ -12,6 +12,14 @@ cmp = "run -- --mode compile"
ex = "run -- --mode exec" ex = "run -- --mode exec"
read = "run -- --mode read" read = "run -- --mode read"
dlex = "run --features debug -- --mode lex"
dprs = "run --features debug -- --mode parse"
dlwr = "run --features debug -- --mode lower"
dchk = "run --features debug -- --mode check"
dcmp = "run --features debug -- --mode compile"
dex = "run --features debug -- --mode exec"
dread = "run --features debug -- --mode read"
rd = "run --features debug" rd = "run --features debug"
rd_ja = "run --features debug --features japanese" rd_ja = "run --features debug --features japanese"
rd_zh_cn = "run --features debug --features simplified_chinese" rd_zh_cn = "run --features debug --features simplified_chinese"

View file

@ -1,29 +0,0 @@
---
name: Bug report
about: Create a report to help us improve
title: ''
labels: bug
assignees: ''
---
**Describe the bug**
A clear and concise description of what the bug is.
**Reproducible code**
Or steps to reproduce the behavior:
**Expected behavior**
A clear and concise description of what you expected to happen.
**Result**
**Screenshots (optional)**
If applicable, add screenshots to help explain your problem.
**OS**
e.g. Windows 11 (WSL2)
If it is an obvious environment-independent bug (e.g. type inference bug), it is not necessary
**Additional context**
Add any other context about the problem here.

58
.github/ISSUE_TEMPLATE/bug_report.yaml vendored Normal file
View file

@ -0,0 +1,58 @@
name: 🐛 Bug report
description: Create a report to help us improve
labels:
- bug
body:
- type: textarea
attributes:
label: Describe the bug?
validations:
required: true
- type: textarea
attributes:
label: Reproducible code
validations:
required: false
- type: textarea
attributes:
label: Expected result
validations:
required: false
- type: textarea
attributes:
label: Actual result
validations:
required: false
- type: textarea
attributes:
label: Additional context
validations:
required: false
- type: input
attributes:
label: Erg version
validations:
required: true
- type: input
attributes:
label: Python version
validations:
required: false
- type: dropdown
attributes:
label: os
options:
- Windows 10
- Windows 11
- MacOS 12 (Monterey)
- MacOS 11 (Big Sur)
- Ubuntu
- Linux(other distro)
- Other (write in `Additional context`)

25
Cargo.lock generated
View file

@ -2,20 +2,9 @@
# It is not intended for manual editing. # It is not intended for manual editing.
version = 3 version = 3
[[package]]
name = "atty"
version = "0.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
dependencies = [
"hermit-abi",
"libc",
"winapi",
]
[[package]] [[package]]
name = "erg" name = "erg"
version = "0.5.7" version = "0.5.9-nightly.0"
dependencies = [ dependencies = [
"erg_common", "erg_common",
"erg_compiler", "erg_compiler",
@ -25,14 +14,16 @@ dependencies = [
[[package]] [[package]]
name = "erg_common" name = "erg_common"
version = "0.5.7" version = "0.5.9-nightly.0"
dependencies = [ dependencies = [
"atty", "hermit-abi",
"libc",
"winapi",
] ]
[[package]] [[package]]
name = "erg_compiler" name = "erg_compiler"
version = "0.5.7" version = "0.5.9-nightly.0"
dependencies = [ dependencies = [
"erg_common", "erg_common",
"erg_parser", "erg_parser",
@ -41,14 +32,14 @@ dependencies = [
[[package]] [[package]]
name = "erg_parser" name = "erg_parser"
version = "0.5.7" version = "0.5.9-nightly.0"
dependencies = [ dependencies = [
"erg_common", "erg_common",
] ]
[[package]] [[package]]
name = "erg_type" name = "erg_type"
version = "0.5.7" version = "0.5.9-nightly.0"
dependencies = [ dependencies = [
"erg_common", "erg_common",
"erg_parser", "erg_parser",

View file

@ -1,6 +1,6 @@
[package] [package]
name = "erg" name = "erg"
version = "0.5.7" version = "0.5.9-nightly.0"
description = "The Erg programming language" description = "The Erg programming language"
authors = ["erg-lang team <moderation.erglang@gmail.com>"] authors = ["erg-lang team <moderation.erglang@gmail.com>"]
license = "MIT OR Apache-2.0" license = "MIT OR Apache-2.0"
@ -18,6 +18,14 @@ members = [
"compiler/erg_type", "compiler/erg_type",
] ]
[workspace.package]
version = "0.5.9-nightly.0"
authors = ["erg-lang team <moderation.erglang@gmail.com>"]
license = "MIT OR Apache-2.0"
edition = "2021"
repository = "https://github.com/erg-lang/erg"
homepage = "https://erg-lang.org/"
[features] [features]
# when "debug" feature is turned on, that of the following crates will also be turned on. # when "debug" feature is turned on, that of the following crates will also be turned on.
debug = [ debug = [
@ -47,10 +55,10 @@ traditional_chinese = [
pre-commit = [] pre-commit = []
[dependencies] [dependencies]
erg_common = { version = "0.5.7", path = "./compiler/erg_common" } erg_common = { version = "0.5.9-nightly.0", path = "./compiler/erg_common" }
erg_parser = { version = "0.5.7", path = "./compiler/erg_parser" } erg_parser = { version = "0.5.9-nightly.0", path = "./compiler/erg_parser" }
erg_compiler = { version = "0.5.7", path = "./compiler/erg_compiler" } erg_compiler = { version = "0.5.9-nightly.0", path = "./compiler/erg_compiler" }
erg_type = { version = "0.5.7", path = "./compiler/erg_type" } erg_type = { version = "0.5.9-nightly.0", path = "./compiler/erg_type" }
# [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>This is the main source code repository for [Erg](https://erg-lang.github.io/). This contains the compiler and documentation. <br>This is the main source code repository for [Erg](https://erg-lang.org/). This contains the compiler and documentation.
<p align='center'> <p align='center'>
<a href="https://github.com/erg-lang/erg/releases"><img alt="Build status" src="https://img.shields.io/github/v/release/erg-lang/erg.svg"></a> <a href="https://github.com/erg-lang/erg/releases"><img alt="Build status" src="https://img.shields.io/github/v/release/erg-lang/erg.svg"></a>

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://mtshiba.github.io/TheErgBook)のメインリポジトリです。コンパイラとドキュメントが置かれています。 <br>こちらは[Erg](https://erg-lang.org/)のメインリポジトリです。コンパイラとドキュメントが置かれています。
<p align='center'> <p align='center'>
<a href="https://github.com/erg-lang/erg/releases"><img alt="Build status" src="https://img.shields.io/github/v/release/erg-lang/erg.svg"></a> <a href="https://github.com/erg-lang/erg/releases"><img alt="Build status" src="https://img.shields.io/github/v/release/erg-lang/erg.svg"></a>
@ -12,8 +12,8 @@
<br> <br>
</p> </p>
[![badge](https://img.shields.io/endpoint.svg?url=https%3A%2F%2Fgezf7g7pd5.execute-api.ap-northeast-1.amazonaws.com%2Fdefault%2Fsource_up_to_date%3Fowner%3Derg-lang%26repos%3Derg%26ref%3Dmain%26path%3DREADME.md%26commit_hash%3Df2118ff45d9e46ca8fa44242363223be43b046dd) [![badge](https://img.shields.io/endpoint.svg?url=https%3A%2F%2Fgezf7g7pd5.execute-api.ap-northeast-1.amazonaws.com%2Fdefault%2Fsource_up_to_date%3Fowner%3Derg-lang%26repos%3Derg%26ref%3Dmain%26path%3DREADME.md%26commit_hash%3D1a66848fd63479093d0d7995712571e3fdc6bd92)
](https://gezf7g7pd5.execute-api.ap-northeast-1.amazonaws.com/default/source_up_to_date?owner=erg-lang&repos=erg&ref=main&path=README.md&commit_hash=f2118ff45d9e46ca8fa44242363223be43b046dd) ](https://gezf7g7pd5.execute-api.ap-northeast-1.amazonaws.com/default/source_up_to_date?owner=erg-lang&repos=erg&ref=main&path=README.md&commit_hash=1a66848fd63479093d0d7995712571e3fdc6bd92)
## Ergはこんな人におすすめです&#58; ## Ergはこんな人におすすめです&#58;

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/)的主要源代码库。它包含编译器和文档。 <br>这是[Erg](https://erg-lang.org/)的主要源代码库。它包含编译器和文档。
<p align='center'> <p align='center'>
<a href="https://github.com/erg-lang/erg/releases"><img alt="Build status" src="https://img.shields.io/github/v/release/erg-lang/erg.svg"></a> <a href="https://github.com/erg-lang/erg/releases"><img alt="Build status" src="https://img.shields.io/github/v/release/erg-lang/erg.svg"></a>
@ -12,8 +12,8 @@
<br> <br>
</p> </p>
[![badge](https://img.shields.io/endpoint.svg?url=https%3A%2F%2Fgezf7g7pd5.execute-api.ap-northeast-1.amazonaws.com%2Fdefault%2Fsource_up_to_date%3Fowner%3Derg-lang%26repos%3Derg%26ref%3Dmain%26path%3DREADME.md%26commit_hash%3Df2118ff45d9e46ca8fa44242363223be43b046dd) [![badge](https://img.shields.io/endpoint.svg?url=https%3A%2F%2Fgezf7g7pd5.execute-api.ap-northeast-1.amazonaws.com%2Fdefault%2Fsource_up_to_date%3Fowner%3Derg-lang%26repos%3Derg%26ref%3Dmain%26path%3DREADME.md%26commit_hash%3D1a66848fd63479093d0d7995712571e3fdc6bd92)
](https://gezf7g7pd5.execute-api.ap-northeast-1.amazonaws.com/default/source_up_to_date?owner=erg-lang&repos=erg&ref=main&path=README.md&commit_hash=f2118ff45d9e46ca8fa44242363223be43b046dd) ](https://gezf7g7pd5.execute-api.ap-northeast-1.amazonaws.com/default/source_up_to_date?owner=erg-lang&repos=erg&ref=main&path=README.md&commit_hash=1a66848fd63479093d0d7995712571e3fdc6bd92)
## Erg可以推荐给以下人员&colon; ## Erg可以推荐给以下人员&colon;

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/)的主要源代碼庫。它包含編譯器和文檔。 <br>這是[Erg](https://erg-lang.org/)的主要源代碼庫。它包含編譯器和文檔。
<p align='center'> <p align='center'>
<a href="https://github.com/erg-lang/erg/releases"><img alt="Build status" src="https://img.shields.io/github/v/release/erg-lang/erg.svg"></a> <a href="https://github.com/erg-lang/erg/releases"><img alt="Build status" src="https://img.shields.io/github/v/release/erg-lang/erg.svg"></a>
@ -12,8 +12,8 @@
<br> <br>
</p> </p>
[![badge](https://img.shields.io/endpoint.svg?url=https%3A%2F%2Fgezf7g7pd5.execute-api.ap-northeast-1.amazonaws.com%2Fdefault%2Fsource_up_to_date%3Fowner%3Derg-lang%26repos%3Derg%26ref%3Dmain%26path%3DREADME.md%26commit_hash%3Df2118ff45d9e46ca8fa44242363223be43b046dd) [![badge](https://img.shields.io/endpoint.svg?url=https%3A%2F%2Fgezf7g7pd5.execute-api.ap-northeast-1.amazonaws.com%2Fdefault%2Fsource_up_to_date%3Fowner%3Derg-lang%26repos%3Derg%26ref%3Dmain%26path%3DREADME.md%26commit_hash%3D1a66848fd63479093d0d7995712571e3fdc6bd92)
](https://gezf7g7pd5.execute-api.ap-northeast-1.amazonaws.com/default/source_up_to_date?owner=erg-lang&repos=erg&ref=main&path=README.md&commit_hash=f2118ff45d9e46ca8fa44242363223be43b046dd) ](https://gezf7g7pd5.execute-api.ap-northeast-1.amazonaws.com/default/source_up_to_date?owner=erg-lang&repos=erg&ref=main&path=README.md&commit_hash=1a66848fd63479093d0d7995712571e3fdc6bd92)
## Erg可以推薦給以下人員&colon; ## Erg可以推薦給以下人員&colon;

View file

@ -14,36 +14,35 @@ cargo license --json | \
---- ----
## `atty` ## `crossterm`
* Source code is available at [https://github.com/softprops/atty](https://github.com/softprops/atty) * Source code is available at [https://github.com/crossterm-rs/crossterm](https://github.com/crossterm-rs/crossterm)
* license: MIT * license: MIT
### `atty`'s license text ### `crossterm`'s license text
MIT from from [https://raw.githubusercontent.com/softprops/atty/0.2.14/LICENSE](https://raw.githubusercontent.com/softprops/atty/0.2.14/LICENSE):
```text ```text
Copyright (c) 2015-2019 Doug Tangren MIT License
Permission is hereby granted, free of charge, to any person obtaining Copyright (c) 2019 Timon
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be Permission is hereby granted, free of charge, to any person obtaining a copy
included in all copies or substantial portions of the Software. of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, The above copyright notice and this permission notice shall be included in all
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF copies or substantial portions of the Software.
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
``` ```
## `hermit-abi` ## `hermit-abi`

View file

@ -1,13 +1,13 @@
[package] [package]
name = "erg_common" name = "erg_common"
version = "0.5.7"
description = "A common components library of Erg" description = "A common components library of Erg"
authors = ["erg-lang team <moderation.erglang@gmail.com>"] documentation = "http://docs.rs/erg_common"
license = "MIT OR Apache-2.0" version.workspace = true
edition = "2021" authors.workspace = true
repository = "https://github.com/erg-lang/erg/tree/main/src/erg_common" license.workspace = true
documentation = "https://docs.rs/erg_common" edition.workspace = true
homepage = "https://erg-lang.github.io/" repository.workspace = true
homepage.workspace = true
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
@ -17,8 +17,13 @@ japanese = []
simplified_chinese = [] simplified_chinese = []
traditional_chinese = [] traditional_chinese = []
[dependencies] [target.'cfg(unix)'.dependencies]
atty = "0.2.14" libc = { version = "0.2", default-features = false }
[target.'cfg(target_os = "hermit")'.dependencies]
hermit-abi = "0.1.6"
[target.'cfg(windows)'.dependencies.winapi]
version = "0.3"
features = ["consoleapi"]
[lib] [lib]
path = "lib.rs" path = "lib.rs"

View file

@ -211,48 +211,70 @@ impl ErgConfig {
let mut cfg = Self::default(); let mut cfg = Self::default();
// ループ内でnextするのでforにしないこと // ループ内でnextするのでforにしないこと
while let Some(arg) = args.next() { while let Some(arg) = args.next() {
let next_arg = args.next();
match &arg[..] { match &arg[..] {
"-c" if next_arg.is_some() => { "-c" | "--code" => {
cfg.input = Input::Str(next_arg.unwrap()); cfg.input = Input::Str(args.next().expect("the value of `-c` is not passed"));
} }
"--dump-as-pyc" => { "--dump-as-pyc" => {
cfg.dump_as_pyc = true; cfg.dump_as_pyc = true;
} }
"-?" | "-h" | "--help" => { "-?" | "-h" | "--help" => {
// TODO:
println!("{}", command_message()); println!("{}", command_message());
if let "--mode" = args.next().as_ref().map(|s| &s[..]).unwrap_or("") {
println!("{}", mode_message());
}
process::exit(0); process::exit(0);
} }
"-m" if next_arg.is_some() => { "-m" | "--module" => {
cfg.module = Box::leak(next_arg.unwrap().into_boxed_str()); let module = args
.next()
.expect("the value of `-m` is not passed")
.into_boxed_str();
cfg.module = Box::leak(module);
} }
"--mode" if next_arg.is_some() => { "--mode" => {
let mode = next_arg.unwrap(); let mode = args.next().expect("the value of `--mode` is not passed");
if let "-?" | "-h" | "--help" = &mode[..] { if let "-?" | "-h" | "--help" = &mode[..] {
println!("{}", mode_message()); println!("{}", mode_message());
process::exit(0); process::exit(0);
} }
cfg.mode = Box::leak(mode.into_boxed_str()); cfg.mode = Box::leak(mode.into_boxed_str());
} }
"--ps1" if next_arg.is_some() => { "--ps1" => {
cfg.ps1 = Box::leak(next_arg.unwrap().into_boxed_str()); let ps1 = args
.next()
.expect("the value of `--ps1` is not passed")
.into_boxed_str();
cfg.ps1 = Box::leak(ps1);
} }
"--ps2" if next_arg.is_some() => { "--ps2" => {
cfg.ps2 = Box::leak(next_arg.unwrap().into_boxed_str()); let ps2 = args
.next()
.expect("the value of `--ps2` is not passed")
.into_boxed_str();
cfg.ps2 = Box::leak(ps2);
} }
"-o" | "--opt-level" | "--optimization-level" if next_arg.is_some() => { "-o" | "--opt-level" | "--optimization-level" => {
cfg.opt_level = next_arg.unwrap().parse::<u8>().unwrap(); cfg.opt_level = args
.next()
.expect("the value of `-o` is not passed")
.parse::<u8>()
.expect("the value of `-o` is not a number");
} }
"-p" | "--py-ver" | "--python-version" if next_arg.is_some() => { "-p" | "--py-ver" | "--python-version" => {
if let Ok(ver) = next_arg.unwrap().parse::<u32>() { let py_ver = args
cfg.python_ver = Some(ver) .next()
} .expect("the value of `-p` is not passed")
.parse::<u32>()
.expect("the value of `-p` is not a number");
cfg.python_ver = Some(py_ver);
} }
"--py-server-timeout" if next_arg.is_some() => { "--py-server-timeout" => {
if let Ok(time) = next_arg.unwrap().parse::<u64>() { cfg.py_server_timeout = args
cfg.py_server_timeout = time; .next()
} .expect("the value of `--py-server-timeout` is not passed")
.parse::<u64>()
.expect("the value of `--py-server-timeout` is not a number");
} }
"--quiet-startup" => { "--quiet-startup" => {
cfg.quiet_startup = true; cfg.quiet_startup = true;
@ -260,10 +282,12 @@ impl ErgConfig {
"-t" | "--show-type" => { "-t" | "--show-type" => {
cfg.show_type = true; cfg.show_type = true;
} }
"--verbose" if next_arg.is_some() => { "--verbose" => {
if let Ok(vr) = next_arg.unwrap().parse::<u8>() { cfg.verbose = args
cfg.verbose = vr; .next()
} .expect("the value of `--verbose` is not passed")
.parse::<u8>()
.expect("the value of `--verbose` is not a number");
} }
"-V" | "--version" => { "-V" | "--version" => {
println!("Erg {}", env!("CARGO_PKG_VERSION")); println!("Erg {}", env!("CARGO_PKG_VERSION"));
@ -282,7 +306,8 @@ impl ErgConfig {
} }
} }
if cfg.input == Input::REPL { if cfg.input == Input::REPL {
let is_stdin_piped = atty::isnt(atty::Stream::Stdin); use crate::tty::IsTty;
let is_stdin_piped = !stdin().is_tty();
let input = if is_stdin_piped { let input = if is_stdin_piped {
let mut buffer = String::new(); let mut buffer = String::new();
stdin().read_to_string(&mut buffer).unwrap(); stdin().read_to_string(&mut buffer).unwrap();

View file

@ -20,7 +20,7 @@ OPTIONS
--python-version/-p (uint 32 number) Pythonバージョンを指定 --python-version/-p (uint 32 number) Pythonバージョンを指定
--py-server-timeout (uint 64 number) PythonのREPLサーバーのタイムアウト時間を指定 --py-server-timeout (uint 64 number) PythonのREPLサーバーのタイムアウト時間を指定
--dump-as-pyc .pycファイルにダンプ --dump-as-pyc .pycファイルにダンプ
--mode lex|parse|compile|exec --mode lex|parse|compile|exec (--mode --helpを参照)
SUBCOMMAND SUBCOMMAND
-c cmd : -c cmd :
@ -43,7 +43,7 @@ OPTIONS
--python-version/-p (uint 32 number) Python --python-version/-p (uint 32 number) Python
--py-server-timeout (uint 64 number) Python REPL --py-server-timeout (uint 64 number) Python REPL
--dump-as-pyc .pyc --dump-as-pyc .pyc
--mode lex|parse|compile|exec --mode lex|parse|compile|exec (`--mode --help`)
SUBCOMMAND SUBCOMMAND
-c cmd : -c cmd :
@ -66,7 +66,7 @@ OPTIONS
--python-version/-p (uint 32 number) Python --python-version/-p (uint 32 number) Python
--py-server-timeout (uint 64 number) Python REPL --py-server-timeout (uint 64 number) Python REPL
--dump-as-pyc .pyc --dump-as-pyc .pyc
--mode lex|parse|compile|exec --mode lex|parse|compile|exec (`--mode --help`)
SUBCOMMAND SUBCOMMAND
-c cmd : -c cmd :
@ -89,7 +89,7 @@ OPTIONS
--python-version/-p (uint 32 number) Python version --python-version/-p (uint 32 number) Python version
--py-server-timeout (uint 64 number) timeout for the Python REPL server --py-server-timeout (uint 64 number) timeout for the Python REPL server
--dump-as-pyc dump as .pyc file --dump-as-pyc dump as .pyc file
--mode lex|parse|compile|exec execution mode --mode lex|parse|compile|exec execution mode (See `--mode --help` for details)
SUBCOMMAND SUBCOMMAND
-c cmd : program passed in as string -c cmd : program passed in as string

View file

@ -21,6 +21,7 @@ pub mod stdin;
pub mod str; pub mod str;
pub mod traits; pub mod traits;
pub mod tsort; pub mod tsort;
pub mod tty;
pub mod vis; pub mod vis;
use crate::set::Set; use crate::set::Set;

View file

@ -0,0 +1,63 @@
//! Copied and modified from the [crossterm](https://github.com/crossterm-rs/crossterm).
//! Making it a little more convenient and safe to query whether
//! something is a terminal teletype or not.
//! This module defines the IsTty trait and the is_tty method to
//! return true if the item represents a terminal.
#[cfg(unix)]
use std::os::unix::io::AsRawFd;
#[cfg(windows)]
use std::os::windows::io::AsRawHandle;
#[cfg(windows)]
use winapi::um::consoleapi::GetConsoleMode;
/// Adds the `is_tty` method to types that might represent a terminal
///
/// ```rust
/// use std::io::stdout;
/// use erg_common::tty::IsTty;
///
/// let is_tty: bool = stdout().is_tty();
/// ```
pub trait IsTty {
/// Returns true when an instance is a terminal teletype, otherwise false.
fn is_tty(&self) -> bool;
}
/// On UNIX, the `isatty()` function returns true if a file
/// descriptor is a terminal.
#[cfg(unix)]
impl<S: AsRawFd> IsTty for S {
fn is_tty(&self) -> bool {
let fd = self.as_raw_fd();
unsafe { libc::isatty(fd) == 1 }
}
}
#[cfg(target_os = "hermit")]
impl<S: AsRawFd> IsTty for S {
fn is_tty(&self) -> bool {
let fd = self.as_raw_fd();
hermit_abi::isatty(fd)
}
}
/// returns true if this is a tty
#[cfg(any(target_arch = "wasm32", target_env = "sgx"))]
impl<S: AsRawFd> IsTty for S {
fn is_tty(&self) -> bool {
false
}
}
/// On windows, `GetConsoleMode` will return true if we are in a terminal.
/// Otherwise false.
#[cfg(windows)]
impl<S: AsRawHandle> IsTty for S {
fn is_tty(&self) -> bool {
let mut mode = 0;
let ok = unsafe { GetConsoleMode(self.as_raw_handle() as *mut _, &mut mode) };
ok == 1
}
}

View file

@ -1,25 +1,34 @@
[package] [package]
name = "erg_compiler" name = "erg_compiler"
version = "0.5.7"
description = "Centimetre: the Erg compiler" description = "Centimetre: the Erg compiler"
authors = ["erg-lang team <moderation.erglang@gmail.com>"] documentation = "http://docs.rs/erg_compiler"
license = "MIT OR Apache-2.0" build = "build.rs"
edition = "2021" version.workspace = true
repository = "https://github.com/erg-lang/erg/tree/main/src/compiler/erg_compiler" authors.workspace = true
documentation = "https://docs.rs/erg_compiler" license.workspace = true
homepage = "https://erg-lang.github.io/" edition.workspace = true
repository.workspace = true
homepage.workspace = true
[features] [features]
# when "debug" feature is turned on, that of parser will also be turned on. # when "debug" feature is turned on, that of parser will also be turned on.
debug = [ "erg_common/debug", "erg_parser/debug", "erg_type/debug" ] debug = ["erg_common/debug", "erg_parser/debug", "erg_type/debug"]
japanese = [ "erg_common/japanese", "erg_parser/japanese", "erg_type/japanese" ] japanese = ["erg_common/japanese", "erg_parser/japanese", "erg_type/japanese"]
simplified_chinese = [ "erg_common/simplified_chinese", "erg_parser/simplified_chinese", "erg_type/simplified_chinese" ] simplified_chinese = [
traditional_chinese = [ "erg_common/traditional_chinese", "erg_parser/traditional_chinese", "erg_type/traditional_chinese" ] "erg_common/simplified_chinese",
"erg_parser/simplified_chinese",
"erg_type/simplified_chinese",
]
traditional_chinese = [
"erg_common/traditional_chinese",
"erg_parser/traditional_chinese",
"erg_type/traditional_chinese",
]
[dependencies] [dependencies]
erg_common = { version = "0.5.7", path = "../erg_common" } erg_common = { version = "0.5.9-nightly.0", path = "../erg_common" }
erg_parser = { version = "0.5.7", path = "../erg_parser" } erg_parser = { version = "0.5.9-nightly.0", path = "../erg_parser" }
erg_type = { version = "0.5.7", path = "../erg_type" } erg_type = { version = "0.5.9-nightly.0", path = "../erg_type" }
[lib] [lib]
path = "lib.rs" path = "lib.rs"

View file

@ -0,0 +1,33 @@
#![allow(deprecated)]
use std::env;
use std::fs;
use std::path;
fn main() -> std::io::Result<()> {
// Create a ".erg" directory
let erg_path = env::home_dir()
.expect("failed to get the location of the home dir")
.to_str()
.expect("invalid encoding of the home dir name")
.to_string()
+ "/.erg";
if !path::Path::new(&erg_path).exists() {
fs::create_dir(&erg_path)?;
fs::create_dir(format!("{erg_path}/std"))?;
}
println!("cargo:rustc-env=ERG_PATH={erg_path}");
println!("cargo:rustc-env=ERG_STD_PATH={erg_path}/std");
// create a std library in ".erg"
for res in fs::read_dir("std")? {
let entry = res?;
let path = entry.path();
let filename = path
.file_name()
.expect("this is not a file")
.to_str()
.unwrap();
fs::copy(&path, format!("{erg_path}/std/{filename}"))?;
}
Ok(())
}

View file

@ -29,7 +29,7 @@ use erg_type::value::ValueObj;
use erg_type::{HasType, Type, TypeCode, TypePair}; use erg_type::{HasType, Type, TypeCode, TypePair};
use crate::compile::{AccessKind, Name, StoreLoadKind}; use crate::compile::{AccessKind, Name, StoreLoadKind};
use crate::context::eval::eval_lit; use crate::context::eval::type_from_token_kind;
use crate::error::CompileError; use crate::error::CompileError;
use crate::hir::{ use crate::hir::{
Accessor, Args, Array, AttrDef, Attribute, BinOp, Block, Call, ClassDef, Def, DefBody, Expr, Accessor, Args, Array, AttrDef, Attribute, BinOp, Block, Call, ClassDef, Def, DefBody, Expr,
@ -867,7 +867,7 @@ impl CodeGenerator {
self.write_instr(MAKE_FUNCTION); self.write_instr(MAKE_FUNCTION);
self.write_arg(0); self.write_arg(0);
self.emit_load_const(def.sig.ident().inspect().clone()); self.emit_load_const(def.sig.ident().inspect().clone());
self.emit_load_name_instr(Identifier::private(Str::ever("#ABCMeta"))); self.emit_load_name_instr(Identifier::private("#ABCMeta"));
self.emit_load_const(vec![ValueObj::from("metaclass")]); self.emit_load_const(vec![ValueObj::from("metaclass")]);
let subclasses_len = 1; let subclasses_len = 1;
self.write_instr(Opcode::CALL_FUNCTION_KW); self.write_instr(Opcode::CALL_FUNCTION_KW);
@ -917,7 +917,7 @@ impl CodeGenerator {
self.emit_empty_func( self.emit_empty_func(
Some(sig.ident().inspect()), Some(sig.ident().inspect()),
def.sig.into_ident(), def.sig.into_ident(),
Some(Identifier::private(Str::ever("#abstractmethod"))), Some(Identifier::private("#abstractmethod")),
); );
} }
self.emit_load_const(ValueObj::None); self.emit_load_const(ValueObj::None);
@ -1129,7 +1129,7 @@ impl CodeGenerator {
CompileError::feature_error( CompileError::feature_error(
self.cfg.input.clone(), self.cfg.input.clone(),
unary.op.loc(), unary.op.loc(),
"", &unary.op.inspect().clone(),
AtomicStr::from(unary.op.content), AtomicStr::from(unary.op.content),
) )
.write_to_stderr(); .write_to_stderr();
@ -1150,6 +1150,9 @@ impl CodeGenerator {
self.emit_load_name_instr(Identifier::public("range")); self.emit_load_name_instr(Identifier::public("range"));
} }
TokenKind::LeftOpen | TokenKind::Closed | TokenKind::Open => todo!(), TokenKind::LeftOpen | TokenKind::Closed | TokenKind::Open => todo!(),
TokenKind::InOp => {
self.emit_load_name_instr(Identifier::private("#in_operator"));
}
_ => {} _ => {}
} }
let type_pair = TypePair::new(bin.lhs_t(), bin.rhs_t()); let type_pair = TypePair::new(bin.lhs_t(), bin.rhs_t());
@ -1170,14 +1173,16 @@ impl CodeGenerator {
| TokenKind::NotEq | TokenKind::NotEq
| TokenKind::Gre | TokenKind::Gre
| TokenKind::GreEq => COMPARE_OP, | TokenKind::GreEq => COMPARE_OP,
TokenKind::LeftOpen | TokenKind::RightOpen | TokenKind::Closed | TokenKind::Open => { TokenKind::LeftOpen
CALL_FUNCTION | TokenKind::RightOpen
} // ERG_BINARY_RANGE, | TokenKind::Closed
| TokenKind::Open
| TokenKind::InOp => CALL_FUNCTION, // ERG_BINARY_RANGE,
_ => { _ => {
CompileError::feature_error( CompileError::feature_error(
self.cfg.input.clone(), self.cfg.input.clone(),
bin.op.loc(), bin.op.loc(),
"", &bin.op.inspect().clone(),
AtomicStr::from(bin.op.content), AtomicStr::from(bin.op.content),
) )
.write_to_stderr(); .write_to_stderr();
@ -1191,14 +1196,22 @@ impl CodeGenerator {
TokenKind::NotEq => 3, TokenKind::NotEq => 3,
TokenKind::Gre => 4, TokenKind::Gre => 4,
TokenKind::GreEq => 5, TokenKind::GreEq => 5,
TokenKind::LeftOpen | TokenKind::RightOpen | TokenKind::Closed | TokenKind::Open => 2, TokenKind::LeftOpen
| TokenKind::RightOpen
| TokenKind::Closed
| TokenKind::Open
| TokenKind::InOp => 2,
_ => type_pair as u8, _ => type_pair as u8,
}; };
self.write_instr(instr); self.write_instr(instr);
self.write_arg(arg); self.write_arg(arg);
self.stack_dec(); self.stack_dec();
match &bin.op.kind { match &bin.op.kind {
TokenKind::LeftOpen | TokenKind::RightOpen | TokenKind::Open | TokenKind::Closed => { TokenKind::LeftOpen
| TokenKind::RightOpen
| TokenKind::Open
| TokenKind::Closed
| TokenKind::InOp => {
self.stack_dec(); self.stack_dec();
} }
_ => {} _ => {}
@ -1339,7 +1352,11 @@ impl CodeGenerator {
self.emit_store_instr(ident, AccessKind::Name); self.emit_store_instr(ident, AccessKind::Name);
} }
ParamPattern::Lit(lit) => { ParamPattern::Lit(lit) => {
self.emit_load_const(eval_lit(&lit)); let value = {
let t = type_from_token_kind(lit.token.kind);
ValueObj::from_str(t, lit.token.content).unwrap()
};
self.emit_load_const(value);
self.write_instr(Opcode::COMPARE_OP); self.write_instr(Opcode::COMPARE_OP);
self.write_arg(2); // == self.write_arg(2); // ==
self.stack_dec(); self.stack_dec();
@ -1597,7 +1614,7 @@ impl CodeGenerator {
log!(info "entered {} ({rec})", fn_name!()); log!(info "entered {} ({rec})", fn_name!());
let attrs_len = rec.attrs.len(); let attrs_len = rec.attrs.len();
// making record type // making record type
let ident = Identifier::private(Str::ever("#NamedTuple")); let ident = Identifier::private("#NamedTuple");
self.emit_load_name_instr(ident); self.emit_load_name_instr(ident);
// record name, let it be anonymous // record name, let it be anonymous
self.emit_load_const("Record"); self.emit_load_const("Record");
@ -1615,10 +1632,10 @@ impl CodeGenerator {
self.write_arg(2); self.write_arg(2);
// (1 (subroutine) + argc + kwsc) input objects -> 1 return object // (1 (subroutine) + argc + kwsc) input objects -> 1 return object
self.stack_dec_n((1 + 2 + 0) - 1); self.stack_dec_n((1 + 2 + 0) - 1);
let ident = Identifier::private(Str::ever("#rec")); let ident = Identifier::private("#rec");
self.emit_store_instr(ident, Name); self.emit_store_instr(ident, Name);
// making record instance // making record instance
let ident = Identifier::private(Str::ever("#rec")); let ident = Identifier::private("#rec");
self.emit_load_name_instr(ident); self.emit_load_name_instr(ident);
for field in rec.attrs.into_iter() { for field in rec.attrs.into_iter() {
self.emit_frameless_block(field.body.block, vec![]); self.emit_frameless_block(field.body.block, vec![]);
@ -1687,6 +1704,15 @@ impl CodeGenerator {
self.stack_dec_n(len - 1); self.stack_dec_n(len - 1);
} }
} }
Array::WithLength(arr) => {
self.emit_expr(*arr.elem);
self.write_instr(BUILD_LIST);
self.write_arg(1u8);
self.emit_expr(*arr.len);
self.write_instr(BINARY_MULTIPLY);
self.write_arg(0);
self.stack_dec();
}
other => todo!("{other}"), other => todo!("{other}"),
}, },
// TODO: tuple comprehension // TODO: tuple comprehension
@ -1720,7 +1746,11 @@ impl CodeGenerator {
self.stack_dec_n(len - 1); self.stack_dec_n(len - 1);
} }
} }
crate::hir::Set::WithLength(_) => todo!(), crate::hir::Set::WithLength(st) => {
self.emit_expr(*st.elem);
self.write_instr(BUILD_SET);
self.write_arg(1u8);
}
}, },
Expr::Record(rec) => self.emit_record(rec), Expr::Record(rec) => self.emit_record(rec),
Expr::Code(code) => { Expr::Code(code) => {
@ -1739,7 +1769,7 @@ impl CodeGenerator {
} }
// Dict, // Dict,
other => { other => {
CompileError::feature_error(self.cfg.input.clone(), other.loc(), "???", "".into()) CompileError::feature_error(self.cfg.input.clone(), other.loc(), "Dict", "".into())
.write_to_stderr(); .write_to_stderr();
self.crash("cannot compile this expression at this time"); self.crash("cannot compile this expression at this time");
} }
@ -1894,7 +1924,7 @@ impl CodeGenerator {
attrs.push(Expr::AttrDef(attr_def)); attrs.push(Expr::AttrDef(attr_def));
} }
let none = Token::new(TokenKind::NoneLit, "None", line, 0); let none = Token::new(TokenKind::NoneLit, "None", line, 0);
attrs.push(Expr::Lit(Literal::from(none))); attrs.push(Expr::Lit(Literal::try_from(none).unwrap()));
} }
other => todo!("{other}"), other => todo!("{other}"),
} }
@ -2007,15 +2037,40 @@ impl CodeGenerator {
fn load_prelude(&mut self) { fn load_prelude(&mut self) {
self.load_record_type(); self.load_record_type();
self.load_prelude_py();
self.record_type_loaded = true; self.record_type_loaded = true;
} }
fn load_prelude_py(&mut self) {
self.emit_global_import_items(
Identifier::public("sys"),
vec![(
Identifier::public("path"),
Some(Identifier::private("#path")),
)],
);
self.emit_load_name_instr(Identifier::private("#path"));
self.emit_load_method_instr("Array!", None, Identifier::public("push!"));
self.emit_load_const(env!("ERG_STD_PATH"));
self.write_instr(CALL_METHOD);
self.write_arg(1u8);
self.stack_dec();
self.emit_pop_top();
self.emit_global_import_items(
Identifier::public("_erg_std_prelude"),
vec![(
Identifier::public("in_operator"),
Some(Identifier::private("#in_operator")),
)],
);
}
fn load_record_type(&mut self) { fn load_record_type(&mut self) {
self.emit_global_import_items( self.emit_global_import_items(
Identifier::public("collections"), Identifier::public("collections"),
vec![( vec![(
Identifier::public("namedtuple"), Identifier::public("namedtuple"),
Some(Identifier::private(Str::ever("#NamedTuple"))), Some(Identifier::private("#NamedTuple")),
)], )],
); );
} }
@ -2026,11 +2081,11 @@ impl CodeGenerator {
vec![ vec![
( (
Identifier::public("ABCMeta"), Identifier::public("ABCMeta"),
Some(Identifier::private(Str::ever("#ABCMeta"))), Some(Identifier::private("#ABCMeta")),
), ),
( (
Identifier::public("abstractmethod"), Identifier::public("abstractmethod"),
Some(Identifier::private(Str::ever("#abstractmethod"))), Some(Identifier::private("#abstractmethod")),
), ),
], ],
); );
@ -2041,7 +2096,7 @@ impl CodeGenerator {
Identifier::public("types"), Identifier::public("types"),
vec![( vec![(
Identifier::public("ModuleType"), Identifier::public("ModuleType"),
Some(Identifier::private(Str::ever("#ModuleType"))), Some(Identifier::private("#ModuleType")),
)], )],
); );
} }

View file

@ -681,25 +681,26 @@ impl Context {
pub(crate) fn cyclic_supertype_of(&self, lhs: &FreeTyVar, rhs: &Type) -> bool { pub(crate) fn cyclic_supertype_of(&self, lhs: &FreeTyVar, rhs: &Type) -> bool {
let subst_ctx = SubstContext::new(rhs, self, Location::Unknown); let subst_ctx = SubstContext::new(rhs, self, Location::Unknown);
if let Some(super_traits) = self.get_nominal_type_ctx(rhs).map(|ctx| &ctx.super_traits) { if let Some(super_traits) = self.get_nominal_type_ctx(rhs).map(|ctx| &ctx.super_traits) {
for sup_trait in super_traits { for super_trait in super_traits {
let sup_trait = if sup_trait.has_qvar() { let sup_trait = if super_trait.has_qvar() {
subst_ctx.substitute(sup_trait.clone()).unwrap() subst_ctx.substitute(super_trait.clone()).unwrap()
} else { } else {
sup_trait.clone() super_trait.clone()
}; };
if self.sup_conforms(lhs, rhs, &sup_trait) { if self.sup_conforms(lhs, rhs, &sup_trait) {
return true; return true;
} }
} }
} }
if let Some(sup_classes) = self.get_nominal_type_ctx(rhs).map(|ctx| &ctx.super_classes) { if let Some(super_classes) = self.get_super_classes(rhs) {
for sup_class in sup_classes { for super_class in super_classes {
let sup_class = if sup_class.has_qvar() { let sup_class = if super_class.has_qvar() {
subst_ctx.substitute(sup_class.clone()).unwrap() subst_ctx.substitute(super_class).unwrap()
} else { } else {
sup_class.clone() super_class
}; };
if self.cyclic_supertype_of(lhs, &sup_class) { if self.cyclic_supertype_of(lhs, &sup_class) {
log!(err "引っかかった: {lhs}, {sup_class}");
return true; return true;
} }
} }
@ -849,6 +850,9 @@ impl Context {
/// returns union of two types (A or B) /// returns union of two types (A or B)
pub(crate) fn union(&self, lhs: &Type, rhs: &Type) -> Type { pub(crate) fn union(&self, lhs: &Type, rhs: &Type) -> Type {
if lhs == rhs {
return lhs.clone();
}
// `?T or ?U` will not be unified // `?T or ?U` will not be unified
// `Set!(?T, 3) or Set(?T, 3)` wii be unified to Set(?T, 3) // `Set!(?T, 3) or Set(?T, 3)` wii be unified to Set(?T, 3)
if !lhs.is_unbound_var() && !rhs.is_unbound_var() { if !lhs.is_unbound_var() && !rhs.is_unbound_var() {
@ -888,6 +892,9 @@ impl Context {
/// returns intersection of two types (A and B) /// returns intersection of two types (A and B)
pub(crate) fn intersection(&self, lhs: &Type, rhs: &Type) -> Type { pub(crate) fn intersection(&self, lhs: &Type, rhs: &Type) -> Type {
if lhs == rhs {
return lhs.clone();
}
// ?T and ?U will not be unified // ?T and ?U will not be unified
if !lhs.is_unbound_var() && !rhs.is_unbound_var() { if !lhs.is_unbound_var() && !rhs.is_unbound_var() {
match (self.supertype_of(lhs, rhs), self.subtype_of(lhs, rhs)) { match (self.supertype_of(lhs, rhs), self.subtype_of(lhs, rhs)) {

View file

@ -100,12 +100,6 @@ fn op_to_name(op: OpKind) -> &'static str {
} }
} }
#[inline]
pub(crate) fn eval_lit(lit: &Literal) -> ValueObj {
let t = type_from_token_kind(lit.token.kind);
ValueObj::from_str(t, lit.token.content.clone())
}
/// Instantiate the polymorphic type from the quantified state. /// Instantiate the polymorphic type from the quantified state.
/// ///
/// e.g. /// e.g.
@ -577,13 +571,26 @@ impl Context {
Ok(ValueObj::Subr(subr)) Ok(ValueObj::Subr(subr))
} }
pub(crate) fn eval_lit(&self, lit: &Literal) -> EvalResult<ValueObj> {
let t = type_from_token_kind(lit.token.kind);
ValueObj::from_str(t, lit.token.content.clone()).ok_or_else(|| {
EvalError::invalid_literal(
self.cfg.input.clone(),
line!() as usize,
lit.token.loc(),
self.caused_by(),
)
.into()
})
}
pub(crate) fn eval_const_expr( pub(crate) fn eval_const_expr(
&self, &self,
expr: &Expr, expr: &Expr,
__name__: Option<&Str>, __name__: Option<&Str>,
) -> EvalResult<ValueObj> { ) -> EvalResult<ValueObj> {
match expr { match expr {
Expr::Lit(lit) => Ok(eval_lit(lit)), Expr::Lit(lit) => self.eval_lit(lit),
Expr::Accessor(acc) => self.eval_const_acc(acc), Expr::Accessor(acc) => self.eval_const_acc(acc),
Expr::BinOp(bin) => self.eval_const_bin(bin), Expr::BinOp(bin) => self.eval_const_bin(bin),
Expr::UnaryOp(unary) => self.eval_const_unary(unary), Expr::UnaryOp(unary) => self.eval_const_unary(unary),
@ -603,7 +610,7 @@ impl Context {
__name__: Option<&Str>, __name__: Option<&Str>,
) -> EvalResult<ValueObj> { ) -> EvalResult<ValueObj> {
match expr { match expr {
Expr::Lit(lit) => Ok(eval_lit(lit)), Expr::Lit(lit) => self.eval_lit(lit),
Expr::Accessor(acc) => self.eval_const_acc(acc), Expr::Accessor(acc) => self.eval_const_acc(acc),
Expr::BinOp(bin) => self.eval_const_bin(bin), Expr::BinOp(bin) => self.eval_const_bin(bin),
Expr::UnaryOp(unary) => self.eval_const_unary(unary), Expr::UnaryOp(unary) => self.eval_const_unary(unary),

View file

@ -109,9 +109,14 @@ impl Context {
panic!("{} has already been registered as const", t.name()); panic!("{} has already been registered as const", t.name());
} else { } else {
let name = VarName::from_str(t.name()); let name = VarName::from_str(t.name());
let meta_t = match ctx.kind {
ContextKind::Class => Type::ClassType,
ContextKind::Trait => Type::TraitType,
_ => Type::Type,
};
self.locals.insert( self.locals.insert(
name.clone(), name.clone(),
VarInfo::new(Type, muty, Private, Builtin, None), VarInfo::new(meta_t, muty, Private, Builtin, None),
); );
self.consts self.consts
.insert(name.clone(), ValueObj::builtin_t(t.clone())); .insert(name.clone(), ValueObj::builtin_t(t.clone()));
@ -156,9 +161,14 @@ impl Context {
root_ctx.methods_list.push((ClassDefType::Simple(t), ctx)); root_ctx.methods_list.push((ClassDefType::Simple(t), ctx));
} else { } else {
let name = VarName::from_str(t.name()); let name = VarName::from_str(t.name());
let meta_t = match ctx.kind {
ContextKind::Class => Type::ClassType,
ContextKind::Trait => Type::TraitType,
_ => Type::Type,
};
self.locals.insert( self.locals.insert(
name.clone(), name.clone(),
VarInfo::new(Type, muty, Private, Builtin, None), VarInfo::new(meta_t, muty, Private, Builtin, None),
); );
self.consts self.consts
.insert(name.clone(), ValueObj::builtin_t(t.clone())); .insert(name.clone(), ValueObj::builtin_t(t.clone()));
@ -203,7 +213,7 @@ impl Context {
let name = VarName::from_static(name); let name = VarName::from_static(name);
self.locals.insert( self.locals.insert(
name.clone(), name.clone(),
VarInfo::new(Type, muty, Private, Builtin, None), VarInfo::new(Patch, muty, Private, Builtin, None),
); );
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) {
@ -454,7 +464,7 @@ impl Context {
/* Obj */ /* Obj */
let mut obj = Self::builtin_mono_class("Obj", 2); let mut obj = Self::builtin_mono_class("Obj", 2);
let t = fn0_met(mono_q("Self"), mono_q("Self")); let t = fn0_met(mono_q("Self"), mono_q("Self"));
let t = quant(t, set! {subtypeof(mono_q("Self"), builtin_mono("Obj"))}); let t = quant(t, set! {subtypeof(mono_q("Self"), Obj)});
obj.register_builtin_impl("clone", t, Const, Public); obj.register_builtin_impl("clone", t, Const, Public);
obj.register_builtin_impl("__module__", Str, Const, Public); obj.register_builtin_impl("__module__", Str, Const, Public);
obj.register_builtin_impl("__sizeof__", fn0_met(Obj, Nat), Const, Public); obj.register_builtin_impl("__sizeof__", fn0_met(Obj, Nat), Const, Public);
@ -469,10 +479,11 @@ impl Context {
); );
let mut obj_in = Self::builtin_methods("In", 2); let mut obj_in = Self::builtin_methods("In", 2);
obj_in.register_builtin_impl("__in__", fn1_met(Obj, Type, Bool), Const, Public); obj_in.register_builtin_impl("__in__", fn1_met(Obj, Type, Bool), Const, Public);
obj.register_trait(Obj, builtin_poly("Eq", vec![ty_tp(Type)]), obj_in); obj.register_trait(Obj, builtin_poly("In", vec![ty_tp(Type)]), obj_in);
let mut obj_mutizable = Self::builtin_methods("Mutizable", 1); let mut obj_mutizable = Self::builtin_methods("Mutizable", 1);
obj_mutizable.register_builtin_const("MutType!", ValueObj::builtin_t(builtin_mono("Obj!"))); obj_mutizable.register_builtin_const("MutType!", ValueObj::builtin_t(builtin_mono("Obj!")));
obj.register_trait(Obj, builtin_mono("Mutizable"), obj_mutizable); obj.register_trait(Obj, builtin_mono("Mutizable"), obj_mutizable);
// Obj does not implement Eq
/* Float */ /* Float */
let mut float = Self::builtin_mono_class("Float", 2); let mut float = Self::builtin_mono_class("Float", 2);
@ -760,6 +771,24 @@ impl Context {
let mut str_show = Self::builtin_methods("Show", 1); let mut str_show = Self::builtin_methods("Show", 1);
str_show.register_builtin_impl("to_str", fn0_met(Str, Str), Immutable, Public); str_show.register_builtin_impl("to_str", fn0_met(Str, Str), Immutable, Public);
str_.register_trait(Str, builtin_mono("Show"), str_show); str_.register_trait(Str, builtin_mono("Show"), str_show);
/* NoneType */
let mut nonetype = Self::builtin_mono_class("NoneType", 10);
nonetype.register_superclass(Obj, &obj);
let mut nonetype_eq = Self::builtin_methods("Eq", 2);
nonetype_eq.register_builtin_impl(
"__eq__",
fn1_met(NoneType, NoneType, Bool),
Const,
Public,
);
nonetype.register_trait(
NoneType,
builtin_poly("Eq", vec![ty_tp(NoneType)]),
nonetype_eq,
);
let mut nonetype_show = Self::builtin_methods("Show", 1);
nonetype_show.register_builtin_impl("to_str", fn0_met(NoneType, Str), Immutable, Public);
nonetype.register_trait(NoneType, builtin_mono("Show"), nonetype_show);
/* Type */ /* Type */
let mut type_ = Self::builtin_mono_class("Type", 2); let mut type_ = Self::builtin_mono_class("Type", 2);
type_.register_superclass(Obj, &obj); type_.register_superclass(Obj, &obj);
@ -783,6 +812,21 @@ impl Context {
builtin_poly("Eq", vec![ty_tp(ClassType)]), builtin_poly("Eq", vec![ty_tp(ClassType)]),
class_eq, class_eq,
); );
let mut trait_type = Self::builtin_mono_class("TraitType", 2);
trait_type.register_superclass(Type, &type_);
trait_type.register_marker_trait(builtin_mono("Named"));
let mut trait_eq = Self::builtin_methods("Eq", 2);
trait_eq.register_builtin_impl(
"__eq__",
fn1_met(TraitType, TraitType, Bool),
Const,
Public,
);
trait_type.register_trait(
TraitType,
builtin_poly("Eq", vec![ty_tp(TraitType)]),
trait_eq,
);
let g_module_t = builtin_mono("GenericModule"); let g_module_t = builtin_mono("GenericModule");
let mut generic_module = Self::builtin_mono_class("GenericModule", 2); let mut generic_module = Self::builtin_mono_class("GenericModule", 2);
generic_module.register_superclass(Obj, &obj); generic_module.register_superclass(Obj, &obj);
@ -849,7 +893,15 @@ impl Context {
Immutable, Immutable,
Public, Public,
); );
array_.register_trait(array_t, builtin_mono("Show"), array_show); array_.register_trait(array_t.clone(), builtin_mono("Show"), array_show);
let array_type_t = builtin_poly("ArrayType", vec![mono_q_tp("T"), mono_q_tp("N")]);
let mut array_type = Self::builtin_poly_class(
"ArrayType",
vec![PS::named_nd("T", Type), PS::named_nd("N", Nat)],
2,
);
array_type.register_superclass(array_t.clone(), &array_);
array_type.register_superclass(Type, &type_);
/* Set */ /* Set */
let mut set_ = let mut set_ =
Self::builtin_poly_class("Set", vec![PS::t_nd("T"), PS::named_nd("N", Nat)], 10); Self::builtin_poly_class("Set", vec![PS::t_nd("T"), PS::named_nd("N", Nat)], 10);
@ -892,6 +944,14 @@ impl Context {
let mut set_show = Self::builtin_methods("Show", 1); let mut set_show = Self::builtin_methods("Show", 1);
set_show.register_builtin_impl("to_str", fn0_met(set_t.clone(), Str), Immutable, Public); set_show.register_builtin_impl("to_str", fn0_met(set_t.clone(), Str), Immutable, Public);
set_.register_trait(set_t.clone(), builtin_mono("Show"), set_show); set_.register_trait(set_t.clone(), builtin_mono("Show"), set_show);
let set_type_t = builtin_poly("SetType", vec![mono_q_tp("T"), mono_q_tp("N")]);
let mut set_type = Self::builtin_poly_class(
"SetType",
vec![PS::named_nd("T", Type), PS::named_nd("N", Nat)],
2,
);
set_type.register_superclass(set_t.clone(), &set_);
set_type.register_superclass(Type, &type_);
/* Bytes */ /* Bytes */
let mut bytes = Self::builtin_mono_class("Bytes", 2); let mut bytes = Self::builtin_mono_class("Bytes", 2);
bytes.register_superclass(Obj, &obj); bytes.register_superclass(Obj, &obj);
@ -1117,243 +1177,16 @@ impl Context {
), ),
tuple5_eq, tuple5_eq,
); );
let mut tuple6 = Self::builtin_poly_class(
"Tuple6",
vec![
PS::t_nd("A"),
PS::t_nd("B"),
PS::t_nd("C"),
PS::t_nd("D"),
PS::t_nd("E"),
PS::t_nd("F"),
],
2,
);
tuple6.register_superclass(builtin_mono("Tuple"), &tuple_);
let mut tuple6_eq = Self::builtin_methods("Eq", 2);
tuple6_eq.register_builtin_impl(
"__eq__",
fn1_met(
builtin_poly(
"Tuple6",
vec![
ty_tp(mono_q("A")),
ty_tp(mono_q("B")),
ty_tp(mono_q("C")),
ty_tp(mono_q("D")),
ty_tp(mono_q("E")),
ty_tp(mono_q("F")),
],
),
builtin_poly(
"Tuple6",
vec![
ty_tp(mono_q("A")),
ty_tp(mono_q("B")),
ty_tp(mono_q("C")),
ty_tp(mono_q("D")),
ty_tp(mono_q("E")),
ty_tp(mono_q("F")),
],
),
Bool,
),
Const,
Public,
);
tuple6.register_trait(
builtin_poly(
"Tuple6",
vec![
ty_tp(mono_q("A")),
ty_tp(mono_q("B")),
ty_tp(mono_q("C")),
ty_tp(mono_q("D")),
ty_tp(mono_q("E")),
ty_tp(mono_q("F")),
],
),
builtin_poly(
"Eq",
vec![ty_tp(builtin_poly(
"Tuple6",
vec![
ty_tp(mono_q("A")),
ty_tp(mono_q("B")),
ty_tp(mono_q("C")),
ty_tp(mono_q("D")),
ty_tp(mono_q("E")),
ty_tp(mono_q("F")),
],
))],
),
tuple6_eq,
);
let mut tuple7 = Self::builtin_poly_class(
"Tuple7",
vec![
PS::t_nd("A"),
PS::t_nd("B"),
PS::t_nd("C"),
PS::t_nd("D"),
PS::t_nd("E"),
PS::t_nd("F"),
PS::t_nd("G"),
],
2,
);
tuple7.register_superclass(builtin_mono("Tuple"), &tuple_);
let mut tuple7_eq = Self::builtin_methods("Eq", 2);
tuple7_eq.register_builtin_impl(
"__eq__",
fn1_met(
builtin_poly(
"Tuple7",
vec![
ty_tp(mono_q("A")),
ty_tp(mono_q("B")),
ty_tp(mono_q("C")),
ty_tp(mono_q("D")),
ty_tp(mono_q("E")),
ty_tp(mono_q("F")),
ty_tp(mono_q("G")),
],
),
builtin_poly(
"Tuple7",
vec![
ty_tp(mono_q("A")),
ty_tp(mono_q("B")),
ty_tp(mono_q("C")),
ty_tp(mono_q("D")),
ty_tp(mono_q("E")),
ty_tp(mono_q("F")),
ty_tp(mono_q("G")),
],
),
Bool,
),
Const,
Public,
);
tuple7.register_trait(
builtin_poly(
"Tuple7",
vec![
ty_tp(mono_q("A")),
ty_tp(mono_q("B")),
ty_tp(mono_q("C")),
ty_tp(mono_q("D")),
ty_tp(mono_q("E")),
ty_tp(mono_q("F")),
ty_tp(mono_q("G")),
],
),
builtin_poly(
"Eq",
vec![ty_tp(builtin_poly(
"Tuple7",
vec![
ty_tp(mono_q("A")),
ty_tp(mono_q("B")),
ty_tp(mono_q("C")),
ty_tp(mono_q("D")),
ty_tp(mono_q("E")),
ty_tp(mono_q("F")),
ty_tp(mono_q("G")),
],
))],
),
tuple7_eq,
);
let mut tuple8 = Self::builtin_poly_class(
"Tuple8",
vec![
PS::t_nd("A"),
PS::t_nd("B"),
PS::t_nd("C"),
PS::t_nd("D"),
PS::t_nd("E"),
PS::t_nd("F"),
PS::t_nd("G"),
PS::t_nd("H"),
],
2,
);
tuple8.register_superclass(builtin_mono("Tuple"), &tuple_);
let mut tuple8_eq = Self::builtin_methods("Eq", 2);
tuple8_eq.register_builtin_impl(
"__eq__",
fn1_met(
builtin_poly(
"Tuple8",
vec![
ty_tp(mono_q("A")),
ty_tp(mono_q("B")),
ty_tp(mono_q("C")),
ty_tp(mono_q("D")),
ty_tp(mono_q("E")),
ty_tp(mono_q("F")),
ty_tp(mono_q("G")),
ty_tp(mono_q("H")),
],
),
builtin_poly(
"Tuple8",
vec![
ty_tp(mono_q("A")),
ty_tp(mono_q("B")),
ty_tp(mono_q("C")),
ty_tp(mono_q("D")),
ty_tp(mono_q("E")),
ty_tp(mono_q("F")),
ty_tp(mono_q("G")),
ty_tp(mono_q("H")),
],
),
Bool,
),
Const,
Public,
);
tuple8.register_trait(
builtin_poly(
"Tuple8",
vec![
ty_tp(mono_q("A")),
ty_tp(mono_q("B")),
ty_tp(mono_q("C")),
ty_tp(mono_q("D")),
ty_tp(mono_q("E")),
ty_tp(mono_q("F")),
ty_tp(mono_q("G")),
ty_tp(mono_q("H")),
],
),
builtin_poly(
"Eq",
vec![ty_tp(builtin_poly(
"Tuple8",
vec![
ty_tp(mono_q("A")),
ty_tp(mono_q("B")),
ty_tp(mono_q("C")),
ty_tp(mono_q("D")),
ty_tp(mono_q("E")),
ty_tp(mono_q("F")),
ty_tp(mono_q("G")),
ty_tp(mono_q("H")),
],
))],
),
tuple8_eq,
);
/* record */ /* record */
let mut record = Self::builtin_mono_class("Record", 2); let mut record = Self::builtin_mono_class("Record", 2);
record.register_superclass(Obj, &obj); record.register_superclass(Obj, &obj);
let mut record_type = Self::builtin_mono_class("RecordType", 2); let mut record_type = Self::builtin_mono_class("RecordType", 2);
record_type.register_superclass(builtin_mono("Record"), &record); record_type.register_superclass(builtin_mono("Record"), &record);
record_type.register_superclass(builtin_mono("Type"), &type_); record_type.register_superclass(Type, &type_);
/* Or (true or type) */
let or_t = builtin_poly("Or", vec![ty_tp(mono_q("L")), ty_tp(mono_q("R"))]);
let mut or = Self::builtin_poly_class("Or", vec![PS::t_nd("L"), PS::t_nd("R")], 2);
or.register_superclass(Obj, &obj);
/* Float_mut */ /* Float_mut */
let mut float_mut = Self::builtin_mono_class("Float!", 2); let mut float_mut = Self::builtin_mono_class("Float!", 2);
float_mut.register_superclass(Float, &float); float_mut.register_superclass(Float, &float);
@ -1378,15 +1211,7 @@ impl Context {
ratio_mut.register_superclass(Ratio, &ratio); ratio_mut.register_superclass(Ratio, &ratio);
let mut ratio_mut_mutable = Self::builtin_methods("Mutable", 2); let mut ratio_mut_mutable = Self::builtin_methods("Mutable", 2);
ratio_mut_mutable.register_builtin_const("ImmutType", ValueObj::builtin_t(Ratio)); ratio_mut_mutable.register_builtin_const("ImmutType", ValueObj::builtin_t(Ratio));
let f_t = kw( let f_t = kw("f", func(vec![kw("old", Ratio)], None, vec![], Ratio));
"f",
func(
vec![kw("old", builtin_mono("Ratio"))],
None,
vec![],
builtin_mono("Ratio"),
),
);
let t = pr_met( let t = pr_met(
ref_mut(builtin_mono("Ratio!"), None), ref_mut(builtin_mono("Ratio!"), None),
vec![f_t], vec![f_t],
@ -1462,7 +1287,7 @@ impl Context {
); );
/* Str_mut */ /* Str_mut */
let mut str_mut = Self::builtin_mono_class("Str!", 2); let mut str_mut = Self::builtin_mono_class("Str!", 2);
str_mut.register_superclass(Str, &str_); str_mut.register_superclass(Str, &nonetype);
let mut str_mut_mutable = Self::builtin_methods("Mutable", 2); let mut str_mut_mutable = Self::builtin_methods("Mutable", 2);
str_mut_mutable.register_builtin_const("ImmutType", ValueObj::builtin_t(Str)); str_mut_mutable.register_builtin_const("ImmutType", ValueObj::builtin_t(Str));
let f_t = kw("f", func(vec![kw("old", Str)], None, vec![], Str)); let f_t = kw("f", func(vec![kw("old", Str)], None, vec![], Str));
@ -1500,7 +1325,6 @@ impl Context {
file_mut_readable, file_mut_readable,
); );
/* Array_mut */ /* Array_mut */
let array_t = builtin_poly("Array", vec![ty_tp(mono_q("T")), mono_q_tp("N")]);
let array_mut_t = builtin_poly("Array!", vec![ty_tp(mono_q("T")), mono_q_tp("N")]); let array_mut_t = builtin_poly("Array!", vec![ty_tp(mono_q("T")), mono_q_tp("N")]);
let mut array_mut_ = Self::builtin_poly_class( let mut array_mut_ = Self::builtin_poly_class(
"Array!", "Array!",
@ -1617,7 +1441,8 @@ impl Context {
/* Range */ /* Range */
let range_t = builtin_poly("Range", vec![TyParam::t(mono_q("T"))]); let range_t = builtin_poly("Range", vec![TyParam::t(mono_q("T"))]);
let mut range = Self::builtin_poly_class("Range", vec![PS::t_nd("T")], 2); let mut range = Self::builtin_poly_class("Range", vec![PS::t_nd("T")], 2);
range.register_superclass(Obj, &obj); // range.register_superclass(Obj, &obj);
range.register_superclass(Type, &type_);
range.register_marker_trait(builtin_poly("Output", vec![ty_tp(mono_q("T"))])); range.register_marker_trait(builtin_poly("Output", vec![ty_tp(mono_q("T"))]));
let mut range_eq = Self::builtin_methods("Eq", 2); let mut range_eq = Self::builtin_methods("Eq", 2);
range_eq.register_builtin_impl( range_eq.register_builtin_impl(
@ -1653,12 +1478,16 @@ impl Context {
self.register_builtin_type(Ratio, ratio, Const); self.register_builtin_type(Ratio, ratio, Const);
self.register_builtin_type(Bool, bool_, Const); self.register_builtin_type(Bool, bool_, Const);
self.register_builtin_type(Str, str_, Const); self.register_builtin_type(Str, str_, Const);
self.register_builtin_type(NoneType, nonetype, Const);
self.register_builtin_type(Type, type_, Const); self.register_builtin_type(Type, type_, Const);
self.register_builtin_type(ClassType, class_type, Const); self.register_builtin_type(ClassType, class_type, Const);
self.register_builtin_type(TraitType, trait_type, Const);
self.register_builtin_type(g_module_t, generic_module, Const); self.register_builtin_type(g_module_t, generic_module, Const);
self.register_builtin_type(module_t, module, Const); self.register_builtin_type(module_t, module, Const);
self.register_builtin_type(array_t, array_, Const); self.register_builtin_type(array_t, array_, Const);
self.register_builtin_type(array_type_t, array_type, Const);
self.register_builtin_type(set_t, set_, Const); self.register_builtin_type(set_t, set_, Const);
self.register_builtin_type(set_type_t, set_type, Const);
self.register_builtin_type(builtin_mono("Bytes"), bytes, Const); self.register_builtin_type(builtin_mono("Bytes"), bytes, Const);
self.register_builtin_type(tuple(vec![mono_q("A")]), tuple1, Const); self.register_builtin_type(tuple(vec![mono_q("A")]), tuple1, Const);
self.register_builtin_type(tuple(vec![mono_q("A"), mono_q("B")]), tuple2, Const); self.register_builtin_type(tuple(vec![mono_q("A"), mono_q("B")]), tuple2, Const);
@ -1683,47 +1512,9 @@ impl Context {
tuple5, tuple5,
Const, Const,
); );
self.register_builtin_type(
tuple(vec![
mono_q("A"),
mono_q("B"),
mono_q("C"),
mono_q("D"),
mono_q("E"),
mono_q("F"),
]),
tuple6,
Const,
);
self.register_builtin_type(
tuple(vec![
mono_q("A"),
mono_q("B"),
mono_q("C"),
mono_q("D"),
mono_q("E"),
mono_q("F"),
mono_q("G"),
]),
tuple7,
Const,
);
self.register_builtin_type(
tuple(vec![
mono_q("A"),
mono_q("B"),
mono_q("C"),
mono_q("D"),
mono_q("E"),
mono_q("F"),
mono_q("G"),
mono_q("H"),
]),
tuple8,
Const,
);
self.register_builtin_type(builtin_mono("Record"), record, Const); self.register_builtin_type(builtin_mono("Record"), record, Const);
self.register_builtin_type(builtin_mono("RecordType"), record_type, Const); self.register_builtin_type(builtin_mono("RecordType"), record_type, Const);
self.register_builtin_type(or_t, or, Const);
self.register_builtin_type(builtin_mono("Int!"), int_mut, Const); self.register_builtin_type(builtin_mono("Int!"), int_mut, Const);
self.register_builtin_type(builtin_mono("Nat!"), nat_mut, Const); self.register_builtin_type(builtin_mono("Nat!"), nat_mut, Const);
self.register_builtin_type(builtin_mono("Float!"), float_mut, Const); self.register_builtin_type(builtin_mono("Float!"), float_mut, Const);
@ -1744,12 +1535,19 @@ impl Context {
fn init_builtin_funcs(&mut self) { fn init_builtin_funcs(&mut self) {
let t_abs = nd_func(vec![kw("n", builtin_mono("Num"))], None, Nat); let t_abs = nd_func(vec![kw("n", builtin_mono("Num"))], None, Nat);
let t_ascii = nd_func(vec![kw("object", Obj)], None, Str);
let t_assert = func( let t_assert = func(
vec![kw("condition", Bool)], vec![kw("condition", Bool)],
None, None,
vec![kw("err_message", Str)], vec![kw("err_message", Str)],
NoneType, NoneType,
); );
let t_bin = nd_func(vec![kw("n", Int)], None, Str);
let t_chr = nd_func(
vec![kw("i", Type::from(value(0usize)..=value(1_114_111usize)))],
None,
Str,
);
let t_classof = nd_func(vec![kw("old", Obj)], None, ClassType); let t_classof = nd_func(vec![kw("old", Obj)], None, ClassType);
let t_compile = nd_func(vec![kw("src", Str)], None, Code); let t_compile = nd_func(vec![kw("src", Str)], None, Code);
let t_cond = nd_func( let t_cond = nd_func(
@ -1786,6 +1584,27 @@ impl Context {
module(mono_q_tp("Path")), module(mono_q_tp("Path")),
); );
let t_import = quant(t_import, set! {static_instance("Path", Str)}); let t_import = quant(t_import, set! {static_instance("Path", Str)});
let t_isinstance = nd_func(
vec![
kw("object", Obj),
kw("classinfo", ClassType), // TODO: => ClassInfo
],
None,
Bool,
);
let t_issubclass = nd_func(
vec![
kw("subclass", ClassType),
kw("classinfo", ClassType), // TODO: => ClassInfo
],
None,
Bool,
);
let t_len = nd_func(
vec![kw("s", builtin_poly("Seq", vec![TyParam::erased(Type)]))],
None,
Nat,
);
let t_log = func( let t_log = func(
vec![], vec![],
Some(kw("objects", ref_(Obj))), Some(kw("objects", ref_(Obj))),
@ -1797,31 +1616,57 @@ impl Context {
], ],
NoneType, NoneType,
); );
let t_oct = nd_func(vec![kw("x", Int)], None, Str);
let t_ord = nd_func(vec![kw("c", Str)], None, Nat);
let t_panic = nd_func(vec![kw("err_message", Str)], None, Never);
let m = mono_q("M");
// TODO: mod
let t_pow = nd_func(
vec![kw("base", m.clone()), kw("exp", m.clone())],
None,
m.clone(),
);
let t_pow = quant(
t_pow,
set! {static_instance("M", builtin_poly("Mul", vec![ty_tp(m)]))},
);
let t_pyimport = nd_func( let t_pyimport = nd_func(
vec![anon(tp_enum(Str, set! {mono_q_tp("Path")}))], vec![anon(tp_enum(Str, set! {mono_q_tp("Path")}))],
None, None,
module(mono_q_tp("Path")), module(mono_q_tp("Path")),
); );
let t_panic = nd_func(vec![kw("err_message", Str)], None, NoneType);
let t_pyimport = quant(t_pyimport, set! {static_instance("Path", Str)}); let t_pyimport = quant(t_pyimport, set! {static_instance("Path", Str)});
let t_quit = func(vec![], None, vec![kw("code", Int)], NoneType); let t_quit = func(vec![], None, vec![kw("code", Int)], NoneType);
let t_exit = t_quit.clone(); let t_exit = t_quit.clone();
let t_repr = nd_func(vec![kw("object", Obj)], None, Str);
let t_round = nd_func(vec![kw("number", Float)], None, Int);
self.register_builtin_impl("abs", t_abs, Immutable, Private); self.register_builtin_impl("abs", t_abs, Immutable, Private);
self.register_builtin_impl("ascii", t_ascii, Immutable, Private);
self.register_builtin_impl("assert", t_assert, Const, Private); // assert casting に悪影響が出る可能性があるため、Constとしておく self.register_builtin_impl("assert", t_assert, Const, Private); // assert casting に悪影響が出る可能性があるため、Constとしておく
self.register_builtin_impl("bin", t_bin, Immutable, Private);
self.register_builtin_impl("chr", t_chr, Immutable, Private);
self.register_builtin_impl("classof", t_classof, Immutable, Private); self.register_builtin_impl("classof", t_classof, Immutable, Private);
self.register_builtin_impl("compile", t_compile, Immutable, Private); self.register_builtin_impl("compile", t_compile, Immutable, Private);
self.register_builtin_impl("cond", t_cond, Immutable, Private); self.register_builtin_impl("cond", t_cond, Immutable, Private);
self.register_builtin_impl("discard", t_discard, Immutable, Private); self.register_builtin_impl("discard", t_discard, Immutable, Private);
self.register_builtin_impl("exit", t_exit, Immutable, Private); self.register_builtin_impl("exit", t_exit, Immutable, Private);
self.register_builtin_impl("if", t_if, Immutable, Private); self.register_builtin_impl("if", t_if, Immutable, Private);
self.register_builtin_impl("log", t_log, Immutable, Private);
self.register_builtin_impl("import", t_import, Immutable, Private); self.register_builtin_impl("import", t_import, Immutable, Private);
self.register_builtin_impl("isinstance", t_isinstance, Immutable, Private);
self.register_builtin_impl("issubclass", t_issubclass, Immutable, Private);
self.register_builtin_impl("len", t_len, Immutable, Private);
self.register_builtin_impl("log", t_log, Immutable, Private);
self.register_builtin_impl("oct", t_oct, Immutable, Private);
self.register_builtin_impl("ord", t_ord, Immutable, Private);
self.register_builtin_impl("panic", t_panic, Immutable, Private); self.register_builtin_impl("panic", t_panic, Immutable, Private);
self.register_builtin_impl("pow", t_pow, Immutable, Private);
if cfg!(feature = "debug") { if cfg!(feature = "debug") {
self.register_builtin_impl("py", t_pyimport.clone(), Immutable, Private); self.register_builtin_impl("py", t_pyimport.clone(), Immutable, Private);
} }
self.register_builtin_impl("pyimport", t_pyimport, Immutable, Private); self.register_builtin_impl("pyimport", t_pyimport, Immutable, Private);
self.register_builtin_impl("quit", t_quit, Immutable, Private); self.register_builtin_impl("quit", t_quit, Immutable, Private);
self.register_builtin_impl("repr", t_repr, Immutable, Private);
self.register_builtin_impl("round", t_round, Immutable, Private);
} }
fn init_builtin_const_funcs(&mut self) { fn init_builtin_const_funcs(&mut self) {
@ -2051,7 +1896,7 @@ impl Context {
self.register_builtin_decl("__rorng__", op_t.clone(), Private); self.register_builtin_decl("__rorng__", op_t.clone(), Private);
self.register_builtin_decl("__orng__", op_t, Private); self.register_builtin_decl("__orng__", op_t, Private);
// TODO: use existential type: |T: Type| (T, In(T)) -> Bool // TODO: use existential type: |T: Type| (T, In(T)) -> Bool
let op_t = bin_op(mono_q("T"), mono_q("I"), Bool); let op_t = bin_op(mono_q("I"), mono_q("T"), Bool);
let op_t = quant( let op_t = quant(
op_t, op_t,
set! { static_instance("T", Type), subtypeof(mono_q("I"), builtin_poly("In", vec![ty_tp(mono_q("T"))])) }, set! { static_instance("T", Type), subtypeof(mono_q("I"), builtin_poly("In", vec![ty_tp(mono_q("T"))])) },

View file

@ -17,7 +17,7 @@ use erg_parser::ast::{self, Identifier};
use erg_parser::token::Token; use erg_parser::token::Token;
use erg_type::constructors::{ use erg_type::constructors::{
anon, builtin_mono, free_var, func, module, mono_proj, subr_t, v_enum, anon, builtin_mono, builtin_poly, free_var, func, module, mono_proj, subr_t, v_enum,
}; };
use erg_type::free::Constraint; use erg_type::free::Constraint;
use erg_type::typaram::TyParam; use erg_type::typaram::TyParam;
@ -87,6 +87,31 @@ impl Context {
}) })
} }
pub(crate) fn get_mut_current_scope_var(&mut self, name: &str) -> Option<&mut VarInfo> {
self.locals
.get_mut(name)
.or_else(|| self.decls.get_mut(name))
.or_else(|| {
self.params
.iter_mut()
.find(|(opt_name, _)| {
opt_name
.as_ref()
.map(|n| &n.inspect()[..] == name)
.unwrap_or(false)
})
.map(|(_, vi)| vi)
})
.or_else(|| {
for (_, methods) in self.methods_list.iter_mut() {
if let Some(vi) = methods.get_mut_current_scope_var(name) {
return Some(vi);
}
}
None
})
}
pub(crate) fn get_local_kv(&self, name: &str) -> Option<(&VarName, &VarInfo)> { pub(crate) fn get_local_kv(&self, name: &str) -> Option<(&VarName, &VarInfo)> {
self.locals.get_key_value(name) self.locals.get_key_value(name)
} }
@ -1160,8 +1185,19 @@ impl Context {
} }
pub(crate) fn get_similar_name(&self, name: &str) -> Option<&str> { pub(crate) fn get_similar_name(&self, name: &str) -> Option<&str> {
match name {
"true" => return Some("True"),
"false" => return Some("False"),
"Null" | "Nil" | "null" | "nil" | "none" => return Some("None"),
"del" => return Some("Del"),
"int" => return Some("Int"),
"nat" => return Some("Nat"),
"str" => return Some("Str"),
"bool" => return Some("Bool"),
_ => {}
}
let name = readable_name(name); let name = readable_name(name);
// TODO: add decls // REVIEW: add decls?
get_similar_name( get_similar_name(
self.params self.params
.iter() .iter()
@ -1298,35 +1334,6 @@ impl Context {
concatenated concatenated
} }
pub(crate) fn _get_nominal_super_trait_ctxs<'a>(
&'a self,
t: &Type,
) -> Option<impl Iterator<Item = &'a Context>> {
let ctx = self.get_nominal_type_ctx(t)?;
Some(ctx.super_traits.iter().map(|sup| {
let sup_ctx = self
.get_nominal_type_ctx(sup)
.unwrap_or_else(|| todo!("{} not found", sup));
sup_ctx
}))
}
pub(crate) fn _get_nominal_super_class_ctxs<'a>(
&'a self,
t: &Type,
) -> Option<impl Iterator<Item = &'a Context>> {
// if `t` is {S: Str | ...}, `ctx_t` will be Str
// else if `t` is Array(Int, 10), `ctx_t` will be Array(T, N) (if Array(Int, 10) is not specialized)
let ctx = self.get_nominal_type_ctx(t)?;
// t: {S: Str | ...} => ctx.super_traits: [Eq(Str), Mul(Nat), ...]
// => return: [(Str, Eq(Str)), (Str, Mul(Nat)), ...] (the content of &'a Type isn't {S: Str | ...})
Some(
ctx.super_classes
.iter()
.map(|sup| self.get_nominal_type_ctx(sup).unwrap()),
)
}
pub(crate) fn get_nominal_super_type_ctxs<'a>(&'a self, t: &Type) -> Option<Vec<&'a Context>> { pub(crate) fn get_nominal_super_type_ctxs<'a>(&'a self, t: &Type) -> Option<Vec<&'a Context>> {
match t { match t {
Type::FreeVar(fv) if fv.is_linked() => self.get_nominal_super_type_ctxs(&fv.crack()), Type::FreeVar(fv) if fv.is_linked() => self.get_nominal_super_type_ctxs(&fv.crack()),
@ -1364,6 +1371,7 @@ impl Context {
} }
} }
/// include `t` itself
fn get_simple_nominal_super_type_ctxs<'a>( fn get_simple_nominal_super_type_ctxs<'a>(
&'a self, &'a self,
t: &Type, t: &Type,
@ -1377,6 +1385,19 @@ impl Context {
Some(vec![ctx].into_iter().chain(sups)) Some(vec![ctx].into_iter().chain(sups))
} }
/// if `typ` is a refinement type, include the base type (refine.t)
pub(crate) fn get_super_classes(&self, typ: &Type) -> Option<impl Iterator<Item = Type>> {
self.get_nominal_type_ctx(typ).map(|ctx| {
let super_classes = ctx.super_classes.clone();
let derefined = typ.derefine();
if typ != &derefined {
vec![derefined].into_iter().chain(super_classes)
} else {
vec![].into_iter().chain(super_classes)
}
})
}
// TODO: Never // TODO: Never
pub(crate) fn get_nominal_type_ctx<'a>(&'a self, typ: &Type) -> Option<&'a Context> { pub(crate) fn get_nominal_type_ctx<'a>(&'a self, typ: &Type) -> Option<&'a Context> {
match typ { match typ {
@ -1433,7 +1454,7 @@ impl Context {
} }
Type::Poly { path, name, .. } => { Type::Poly { path, name, .. } => {
if self.path() == path { if self.path() == path {
if let Some((_, ctx)) = self.rec_get_mono_type(name) { if let Some((_, ctx)) = self.rec_get_poly_type(name) {
return Some(ctx); return Some(ctx);
} }
} }
@ -1448,7 +1469,7 @@ impl Context {
.and_then(|cache| cache.ref_ctx(path.as_path())) .and_then(|cache| cache.ref_ctx(path.as_path()))
}) })
{ {
if let Some((_, ctx)) = ctx.rec_get_mono_type(name) { if let Some((_, ctx)) = ctx.rec_get_poly_type(name) {
return Some(ctx); return Some(ctx);
} }
} }
@ -1495,16 +1516,10 @@ impl Context {
return Some(res); return Some(res);
} }
} }
Type::Or(l, r) => { Type::Or(_l, _r) => {
let lctx = self.get_nominal_type_ctx(l)?; if let Some(ctx) = self.get_nominal_type_ctx(&builtin_poly("Or", vec![])) {
let rctx = self.get_nominal_type_ctx(r)?; return Some(ctx);
// use smaller context }
return match (self.supertype_of(l, r), self.supertype_of(r, l)) {
(true, true) => Some(lctx),
(true, false) => Some(rctx),
(false, true) => Some(lctx),
(false, false) => None,
};
} }
// FIXME: `F()`などの場合、実際は引数が省略されていてもmonomorphicになる // FIXME: `F()`などの場合、実際は引数が省略されていてもmonomorphicになる
other if other.is_monomorphic() => { other if other.is_monomorphic() => {

View file

@ -26,7 +26,6 @@ use erg_type::{HasType, ParamTy, Predicate, SubrKind, TyBound, Type};
use TyParamOrdering::*; use TyParamOrdering::*;
use Type::*; use Type::*;
use crate::context::eval::eval_lit;
use crate::context::{Context, RegistrationMode}; use crate::context::{Context, RegistrationMode};
use crate::error::{SingleTyCheckResult, TyCheckError, TyCheckErrors, TyCheckResult}; use crate::error::{SingleTyCheckResult, TyCheckError, TyCheckErrors, TyCheckResult};
use crate::hir; use crate::hir;
@ -577,7 +576,7 @@ impl Context {
self.instantiate_typespec(&spec_with_op.t_spec, opt_decl_t, tmp_tv_ctx, mode)? self.instantiate_typespec(&spec_with_op.t_spec, opt_decl_t, tmp_tv_ctx, mode)?
} else { } else {
match &sig.pat { match &sig.pat {
ast::ParamPattern::Lit(lit) => v_enum(set![eval_lit(lit)]), ast::ParamPattern::Lit(lit) => v_enum(set![self.eval_lit(lit)?]),
// TODO: Array<Lit> // TODO: Array<Lit>
_ => { _ => {
let level = if mode == PreRegister { let level = if mode == PreRegister {
@ -613,7 +612,7 @@ impl Context {
let t = self.instantiate_param_sig_t(sig, opt_decl_t, tmp_tv_ctx, mode)?; let t = self.instantiate_param_sig_t(sig, opt_decl_t, tmp_tv_ctx, mode)?;
match (sig.inspect(), &sig.opt_default_val) { match (sig.inspect(), &sig.opt_default_val) {
(Some(name), Some(default)) => { (Some(name), Some(default)) => {
let default = self.instantiate_const_expr(default); let default = self.instantiate_const_expr(default)?;
Ok(ParamTy::kw_default( Ok(ParamTy::kw_default(
name.clone(), name.clone(),
t, t,
@ -665,7 +664,7 @@ impl Context {
if let Some(first) = args.next() { if let Some(first) = args.next() {
let t = self.instantiate_const_expr_as_type(&first.expr)?; let t = self.instantiate_const_expr_as_type(&first.expr)?;
let len = args.next().unwrap(); let len = args.next().unwrap();
let len = self.instantiate_const_expr(&len.expr); let len = self.instantiate_const_expr(&len.expr)?;
Ok(array(t, len)) Ok(array(t, len))
} else { } else {
Ok(builtin_mono("GenericArray")) Ok(builtin_mono("GenericArray"))
@ -707,23 +706,28 @@ impl Context {
} }
other => { other => {
// FIXME: kw args // FIXME: kw args
let params = simple.args.pos_args().map(|arg| match &arg.expr { let mut new_params = vec![];
ast::ConstExpr::Lit(lit) => TyParam::Value(eval_lit(lit)), for arg in simple.args.pos_args() {
_ => { match &arg.expr {
todo!() ast::ConstExpr::Lit(lit) => {
new_params.push(TyParam::Value(self.eval_lit(lit)?));
}
_ => {
todo!()
}
} }
}); }
// FIXME: non-builtin // FIXME: non-builtin
Ok(builtin_poly(Str::rc(other), params.collect())) Ok(builtin_poly(Str::rc(other), new_params))
} }
} }
} }
pub(crate) fn instantiate_const_expr(&self, expr: &ast::ConstExpr) -> TyParam { pub(crate) fn instantiate_const_expr(&self, expr: &ast::ConstExpr) -> TyCheckResult<TyParam> {
match expr { match expr {
ast::ConstExpr::Lit(lit) => TyParam::Value(eval_lit(lit)), ast::ConstExpr::Lit(lit) => Ok(TyParam::Value(self.eval_lit(lit)?)),
ast::ConstExpr::Accessor(ast::ConstAccessor::Local(name)) => { ast::ConstExpr::Accessor(ast::ConstAccessor::Local(name)) => {
TyParam::Mono(name.inspect().clone()) Ok(TyParam::Mono(name.inspect().clone()))
} }
_ => todo!(), _ => todo!(),
} }
@ -780,13 +784,13 @@ impl Context {
)), )),
TypeSpec::Array(arr) => { TypeSpec::Array(arr) => {
let elem_t = self.instantiate_typespec(&arr.ty, opt_decl_t, tmp_tv_ctx, mode)?; let elem_t = self.instantiate_typespec(&arr.ty, opt_decl_t, tmp_tv_ctx, mode)?;
let len = self.instantiate_const_expr(&arr.len); let len = self.instantiate_const_expr(&arr.len)?;
Ok(array(elem_t, len)) Ok(builtin_poly("ArrayType", vec![ty_tp(elem_t), len]))
} }
TypeSpec::Set(set) => { TypeSpec::Set(set) => {
let elem_t = self.instantiate_typespec(&set.ty, opt_decl_t, tmp_tv_ctx, mode)?; let elem_t = self.instantiate_typespec(&set.ty, opt_decl_t, tmp_tv_ctx, mode)?;
let len = self.instantiate_const_expr(&set.len); let len = self.instantiate_const_expr(&set.len)?;
Ok(erg_type::constructors::set(elem_t, len)) Ok(builtin_poly("SetType", vec![ty_tp(elem_t), len]))
} }
// FIXME: unwrap // FIXME: unwrap
TypeSpec::Tuple(tys) => Ok(tuple( TypeSpec::Tuple(tys) => Ok(tuple(
@ -797,18 +801,18 @@ impl Context {
}) })
.collect(), .collect(),
)), )),
// TODO: エラー処理(リテラルでない、ダブりがある)はパーサーにやらせる // TODO: エラー処理(リテラルでない)はパーサーにやらせる
TypeSpec::Enum(set) => Ok(v_enum( TypeSpec::Enum(set) => {
set.pos_args() let mut new_set = set! {};
.map(|arg| { for arg in set.pos_args() {
if let ast::ConstExpr::Lit(lit) = &arg.expr { if let ast::ConstExpr::Lit(lit) = &arg.expr {
eval_lit(lit) new_set.insert(self.eval_lit(lit)?);
} else { } else {
todo!() todo!()
} }
}) }
.collect::<Set<_>>(), Ok(v_enum(new_set))
)), }
TypeSpec::Interval { op, lhs, rhs } => { TypeSpec::Interval { op, lhs, rhs } => {
let op = match op.kind { let op = match op.kind {
TokenKind::Closed => IntervalOp::Closed, TokenKind::Closed => IntervalOp::Closed,
@ -817,9 +821,9 @@ impl Context {
TokenKind::Open => IntervalOp::Open, TokenKind::Open => IntervalOp::Open,
_ => assume_unreachable!(), _ => assume_unreachable!(),
}; };
let l = self.instantiate_const_expr(lhs); let l = self.instantiate_const_expr(lhs)?;
let l = self.eval_tp(&l)?; let l = self.eval_tp(&l)?;
let r = self.instantiate_const_expr(rhs); let r = self.instantiate_const_expr(rhs)?;
let r = self.eval_tp(&r)?; let r = self.eval_tp(&r)?;
if let Some(Greater) = self.try_cmp(&l, &r) { if let Some(Greater) = self.try_cmp(&l, &r) {
panic!("{l}..{r} is not a valid interval type (should be lhs <= rhs)") panic!("{l}..{r} is not a valid interval type (should be lhs <= rhs)")

View file

@ -281,6 +281,7 @@ pub enum OperationKind {
Import, Import,
PyImport, PyImport,
Del, Del,
AssertCast,
} }
impl OperationKind { impl OperationKind {

View file

@ -14,8 +14,9 @@ use ast::{DefId, Identifier, VarName};
use erg_parser::ast; use erg_parser::ast;
use erg_type::constructors::{func, func1, proc, ref_, ref_mut, v_enum}; use erg_type::constructors::{func, func1, proc, ref_, ref_mut, v_enum};
use erg_type::free::{Constraint, Cyclicity, FreeKind};
use erg_type::value::{GenTypeObj, TypeKind, TypeObj, ValueObj}; use erg_type::value::{GenTypeObj, TypeKind, TypeObj, ValueObj};
use erg_type::{ParamTy, SubrType, Type}; use erg_type::{HasType, ParamTy, SubrType, Type};
use crate::build_hir::HIRBuilder; use crate::build_hir::HIRBuilder;
use crate::context::{ use crate::context::{
@ -1076,4 +1077,75 @@ impl Context {
))) )))
} }
} }
pub(crate) fn cast(
&mut self,
type_spec: ast::TypeSpec,
call: &mut hir::Call,
) -> TyCheckResult<()> {
let cast_to =
self.instantiate_typespec(&type_spec, None, None, RegistrationMode::Normal)?;
let lhs = enum_unwrap!(
call.args.get_mut_left_or_key("pred").unwrap(),
hir::Expr::BinOp
)
.lhs
.as_mut();
match (
self.supertype_of(lhs.ref_t(), &cast_to),
self.subtype_of(lhs.ref_t(), &cast_to),
) {
// assert 1 in {1}
(true, true) => Ok(()),
// assert x in Int (x: Nat)
(false, true) => Ok(()), // TODO: warn (needless)
// assert x in Nat (x: Int)
(true, false) => {
if let hir::Expr::Accessor(ref acc) = lhs {
self.change_var_type(acc, cast_to.clone())?;
}
match lhs.ref_t() {
Type::FreeVar(fv) if fv.is_linked() => {
let constraint = Constraint::new_subtype_of(cast_to, Cyclicity::Not);
fv.replace(FreeKind::new_unbound(self.level, constraint));
}
Type::FreeVar(fv) => {
let new_constraint = Constraint::new_subtype_of(cast_to, Cyclicity::Not);
fv.update_constraint(new_constraint);
}
_ => {
*lhs.ref_mut_t() = cast_to;
}
}
Ok(())
}
// assert x in Str (x: Int)
(false, false) => Err(TyCheckErrors::from(TyCheckError::invalid_type_cast_error(
self.cfg.input.clone(),
line!() as usize,
lhs.loc(),
self.caused_by(),
&lhs.to_string(),
&cast_to,
None,
))),
}
}
fn change_var_type(&mut self, acc: &hir::Accessor, t: Type) -> TyCheckResult<()> {
#[allow(clippy::single_match)]
match acc {
hir::Accessor::Ident(ident) => {
if let Some(vi) = self.get_mut_current_scope_var(ident.inspect()) {
vi.t = t;
} else {
todo!()
}
}
_ => {
// TODO: support other accessors
}
}
Ok(())
}
} }

View file

@ -671,6 +671,13 @@ impl Context {
} }
Ok(()) Ok(())
} }
hir::Array::WithLength(arr) => {
let loc = arr.loc();
arr.t = self.deref_tyvar(mem::take(&mut arr.t), Covariant, loc)?;
self.resolve_expr_t(&mut arr.elem)?;
self.resolve_expr_t(&mut arr.len)?;
Ok(())
}
_ => todo!(), _ => todo!(),
}, },
hir::Expr::Tuple(tuple) => match tuple { hir::Expr::Tuple(tuple) => match tuple {
@ -683,12 +690,20 @@ impl Context {
}, },
hir::Expr::Set(set) => match set { hir::Expr::Set(set) => match set {
hir::Set::Normal(st) => { hir::Set::Normal(st) => {
let loc = st.loc();
st.t = self.deref_tyvar(mem::take(&mut st.t), Covariant, loc)?;
for elem in st.elems.pos_args.iter_mut() { for elem in st.elems.pos_args.iter_mut() {
self.resolve_expr_t(&mut elem.expr)?; self.resolve_expr_t(&mut elem.expr)?;
} }
Ok(()) Ok(())
} }
hir::Set::WithLength(_) => todo!(), hir::Set::WithLength(st) => {
let loc = st.loc();
st.t = self.deref_tyvar(mem::take(&mut st.t), Covariant, loc)?;
self.resolve_expr_t(&mut st.elem)?;
self.resolve_expr_t(&mut st.len)?;
Ok(())
}
}, },
hir::Expr::Dict(_dict) => { hir::Expr::Dict(_dict) => {
todo!() todo!()

View file

@ -990,6 +990,30 @@ impl EvalError {
caused_by, caused_by,
) )
} }
pub fn invalid_literal(
input: Input,
errno: usize,
loc: Location,
caused_by: AtomicStr,
) -> Self {
Self::new(
ErrorCore::new(
errno,
SyntaxError,
loc,
switch_lang!(
"japanese" => "リテラルが不正です",
"simplified_chinese" => "字面量不合法",
"traditional_chinese" => "字面量不合法",
"english" => "invalid literal",
),
None,
),
input,
caused_by,
)
}
} }
pub type EffectError = TyCheckError; pub type EffectError = TyCheckError;
@ -1568,6 +1592,34 @@ impl LowerError {
caused_by, caused_by,
) )
} }
#[allow(clippy::too_many_arguments)]
pub fn invalid_type_cast_error(
input: Input,
errno: usize,
loc: Location,
caused_by: AtomicStr,
name: &str,
cast_to: &Type,
hint: Option<AtomicStr>,
) -> Self {
Self::new(
ErrorCore::new(
errno,
TypeError,
loc,
switch_lang!(
"japanese" => format!("{YELLOW}{name}{RESET}の型を{RED}{cast_to}{RESET}にキャストすることはできません"),
"simplified_chinese" => format!("{YELLOW}{name}{RESET}的类型无法转换为{RED}{cast_to}{RESET}"),
"traditional_chinese" => format!("{YELLOW}{name}{RESET}的類型無法轉換為{RED}{cast_to}{RESET}"),
"english" => format!("the type of {YELLOW}{name}{RESET} cannot be cast to {RED}{cast_to}{RESET}"),
),
hint,
),
input,
caused_by,
)
}
} }
#[derive(Debug)] #[derive(Debug)]

View file

@ -47,14 +47,16 @@ impl Locational for Literal {
} }
} }
impl From<Token> for Literal { impl TryFrom<Token> for Literal {
fn from(token: Token) -> Self { type Error = ();
let data = ValueObj::from_str(type_from_token_kind(token.kind), token.content.clone()); fn try_from(token: Token) -> Result<Self, ()> {
Self { let data =
ValueObj::from_str(type_from_token_kind(token.kind), token.content.clone()).ok_or(())?;
Ok(Self {
t: data.t(), t: data.t(),
value: data, value: data,
token, token,
} })
} }
} }
@ -282,6 +284,20 @@ impl Args {
} }
} }
pub fn get_mut_left_or_key(&mut self, key: &str) -> Option<&mut Expr> {
if !self.pos_args.is_empty() {
Some(&mut self.pos_args.get_mut(0)?.expr)
} else if let Some(pos) = self
.kw_args
.iter()
.position(|arg| &arg.keyword.inspect()[..] == key)
{
Some(&mut self.kw_args.get_mut(pos)?.expr)
} else {
None
}
}
pub fn insert_pos(&mut self, idx: usize, pos: PosArg) { pub fn insert_pos(&mut self, idx: usize, pos: PosArg) {
self.pos_args.insert(idx, pos); self.pos_args.insert(idx, pos);
} }
@ -351,8 +367,8 @@ impl Identifier {
) )
} }
pub fn private(name: Str) -> Self { pub fn private(name: &'static str) -> Self {
Self::bare(None, VarName::from_str(name)) Self::bare(None, VarName::from_static(name))
} }
pub fn private_with_line(name: Str, line: usize) -> Self { pub fn private_with_line(name: Str, line: usize) -> Self {

View file

@ -59,6 +59,10 @@ impl<'a> Linker<'a> {
self.replace_import(&mut elem.expr); self.replace_import(&mut elem.expr);
} }
} }
Array::WithLength(arr) => {
self.replace_import(&mut arr.elem);
self.replace_import(&mut arr.len);
}
_ => todo!(), _ => todo!(),
}, },
Expr::Tuple(tuple) => match tuple { Expr::Tuple(tuple) => match tuple {
@ -74,9 +78,11 @@ impl<'a> Linker<'a> {
self.replace_import(&mut elem.expr); self.replace_import(&mut elem.expr);
} }
} }
Set::WithLength(_) => todo!(), Set::WithLength(st) => {
self.replace_import(&mut st.elem);
self.replace_import(&mut st.len);
}
}, },
Expr::Dict(_dict) => { Expr::Dict(_dict) => {
todo!() todo!()
} }
@ -241,7 +247,7 @@ impl<'a> Linker<'a> {
mod_name_lit.ln_begin().unwrap(), mod_name_lit.ln_begin().unwrap(),
mod_name_lit.col_begin().unwrap(), mod_name_lit.col_begin().unwrap(),
); );
let mod_name = Expr::Lit(Literal::from(token)); let mod_name = Expr::Lit(Literal::try_from(token).unwrap());
args.insert_pos(0, PosArg::new(mod_name)); args.insert_pos(0, PosArg::new(mod_name));
let line = expr.ln_begin().unwrap_or(0); let line = expr.ln_begin().unwrap_or(0);
for attr in comps { for attr in comps {

View file

@ -15,6 +15,7 @@ use erg_parser::ast;
use erg_parser::ast::AST; use erg_parser::ast::AST;
use erg_parser::build_ast::ASTBuilder; use erg_parser::build_ast::ASTBuilder;
use erg_parser::token::{Token, TokenKind}; use erg_parser::token::{Token, TokenKind};
use erg_parser::Parser;
use erg_type::constructors::{ use erg_type::constructors::{
array, array_mut, builtin_mono, builtin_poly, free_var, func, mono, proc, quant, set, set_mut, array, array_mut, builtin_mono, builtin_poly, free_var, func, mono, proc, quant, set, set_mut,
@ -182,6 +183,19 @@ impl ASTLowerer {
} }
} }
fn lower_literal(&self, lit: ast::Literal) -> LowerResult<hir::Literal> {
let loc = lit.loc();
let lit = hir::Literal::try_from(lit.token).map_err(|_| {
LowerError::invalid_literal(
self.cfg.input.clone(),
line!() as usize,
loc,
self.ctx.caused_by(),
)
})?;
Ok(lit)
}
fn lower_array(&mut self, array: ast::Array) -> LowerResult<hir::Array> { fn lower_array(&mut self, array: ast::Array) -> LowerResult<hir::Array> {
log!(info "entered {}({array})", fn_name!()); log!(info "entered {}({array})", fn_name!());
match array { match array {
@ -260,6 +274,8 @@ impl ASTLowerer {
"ArrayWithMutType!", "ArrayWithMutType!",
vec![TyParam::t(elem.t()), TyParam::Value(v)], vec![TyParam::t(elem.t()), TyParam::Value(v)],
) )
} else if self.ctx.subtype_of(&elem.t(), &Type::Type) {
builtin_poly("ArrayType", vec![TyParam::t(elem.t()), TyParam::Value(v)])
} else { } else {
array(elem.t(), TyParam::Value(v)) array(elem.t(), TyParam::Value(v))
} }
@ -429,6 +445,8 @@ impl ASTLowerer {
"SetWithMutType!", "SetWithMutType!",
vec![TyParam::t(elem.t()), TyParam::Value(v)], vec![TyParam::t(elem.t()), TyParam::Value(v)],
) )
} else if self.ctx.subtype_of(&elem.t(), &Type::Type) {
builtin_poly("SetType", vec![TyParam::t(elem.t()), TyParam::Value(v)])
} else { } else {
set(elem.t(), TyParam::Value(v)) set(elem.t(), TyParam::Value(v))
} }
@ -489,7 +507,7 @@ impl ASTLowerer {
} }
ast::Accessor::TupleAttr(t_attr) => { ast::Accessor::TupleAttr(t_attr) => {
let obj = self.lower_expr(*t_attr.obj)?; let obj = self.lower_expr(*t_attr.obj)?;
let index = hir::Literal::from(t_attr.index.token); let index = self.lower_literal(t_attr.index)?;
let n = enum_unwrap!(index.value, ValueObj::Nat); let n = enum_unwrap!(index.value, ValueObj::Nat);
let t = enum_unwrap!( let t = enum_unwrap!(
obj.ref_t().typarams().get(n as usize).unwrap().clone(), obj.ref_t().typarams().get(n as usize).unwrap().clone(),
@ -562,9 +580,27 @@ impl ASTLowerer {
Ok(hir::UnaryOp::new(unary.op, expr, t)) Ok(hir::UnaryOp::new(unary.op, expr, t))
} }
// TODO: single `import`
fn lower_call(&mut self, call: ast::Call) -> LowerResult<hir::Call> { fn lower_call(&mut self, call: ast::Call) -> LowerResult<hir::Call> {
log!(info "entered {}({}{}(...))", fn_name!(), call.obj, fmt_option!(call.method_name)); log!(info "entered {}({}{}(...))", fn_name!(), call.obj, fmt_option!(call.method_name));
let opt_cast_to = if call.is_assert_cast() {
if let Some(typ) = call.assert_cast_target_type() {
Some(Parser::expr_to_type_spec(typ.clone()).map_err(|e| {
let e = LowerError::new(e.into(), self.input().clone(), self.ctx.caused_by());
LowerErrors::from(e)
})?)
} else {
return Err(LowerErrors::from(LowerError::syntax_error(
self.input().clone(),
line!() as usize,
call.args.loc(),
self.ctx.caused_by(),
"invalid assert casting type",
None,
)));
}
} else {
None
};
let (pos_args, kw_args, paren) = call.args.deconstruct(); let (pos_args, kw_args, paren) = call.args.deconstruct();
let mut hir_args = hir::Args::new( let mut hir_args = hir::Args::new(
Vec::with_capacity(pos_args.len()), Vec::with_capacity(pos_args.len()),
@ -597,7 +633,7 @@ impl ASTLowerer {
} else { } else {
None None
}; };
let call = hir::Call::new(obj, method_name, hir_args, sig_t); let mut call = hir::Call::new(obj, method_name, hir_args, sig_t);
match call.additional_operation() { match call.additional_operation() {
Some(kind @ (OperationKind::Import | OperationKind::PyImport)) => { Some(kind @ (OperationKind::Import | OperationKind::PyImport)) => {
let mod_name = let mod_name =
@ -621,7 +657,12 @@ impl ASTLowerer {
))) )))
} }
}, },
_ => {} _ => {
if let Some(type_spec) = opt_cast_to {
log!(err "cast({type_spec}): {call}");
self.ctx.cast(type_spec, &mut call)?;
}
}
} }
Ok(call) Ok(call)
} }
@ -1241,7 +1282,7 @@ impl ASTLowerer {
fn lower_expr(&mut self, expr: ast::Expr) -> LowerResult<hir::Expr> { fn lower_expr(&mut self, expr: ast::Expr) -> LowerResult<hir::Expr> {
log!(info "entered {}", fn_name!()); log!(info "entered {}", fn_name!());
match expr { match expr {
ast::Expr::Lit(lit) => Ok(hir::Expr::Lit(hir::Literal::from(lit.token))), ast::Expr::Lit(lit) => Ok(hir::Expr::Lit(self.lower_literal(lit)?)),
ast::Expr::Array(arr) => Ok(hir::Expr::Array(self.lower_array(arr)?)), ast::Expr::Array(arr) => Ok(hir::Expr::Array(self.lower_array(arr)?)),
ast::Expr::Tuple(tup) => Ok(hir::Expr::Tuple(self.lower_tuple(tup)?)), ast::Expr::Tuple(tup) => Ok(hir::Expr::Tuple(self.lower_tuple(tup)?)),
ast::Expr::Record(rec) => Ok(hir::Expr::Record(self.lower_record(rec)?)), ast::Expr::Record(rec) => Ok(hir::Expr::Record(self.lower_record(rec)?)),

View file

@ -156,6 +156,10 @@ impl OwnershipChecker {
self.check_expr(&a.expr, ownership, false); self.check_expr(&a.expr, ownership, false);
} }
} }
Array::WithLength(arr) => {
self.check_expr(&arr.elem, ownership, false);
self.check_expr(&arr.len, ownership, false);
}
_ => todo!(), _ => todo!(),
}, },
Expr::Tuple(tuple) => match tuple { Expr::Tuple(tuple) => match tuple {
@ -182,12 +186,15 @@ impl OwnershipChecker {
} }
} }
Expr::Set(set) => match set { Expr::Set(set) => match set {
hir::Set::Normal(set) => { hir::Set::Normal(st) => {
for a in set.elems.pos_args.iter() { for a in st.elems.pos_args.iter() {
self.check_expr(&a.expr, ownership, false); self.check_expr(&a.expr, ownership, false);
} }
} }
hir::Set::WithLength(_) => todo!(), hir::Set::WithLength(st) => {
self.check_expr(&st.elem, ownership, false);
self.check_expr(&st.len, ownership, false);
}
}, },
// TODO: capturing // TODO: capturing
Expr::Lambda(lambda) => { Expr::Lambda(lambda) => {

View file

@ -0,0 +1,107 @@
from collections.abc import Iterable, Sequence, Iterator, Container
def in_operator(x, y):
if type(y) == type:
if isinstance(x, y):
return True
# TODO: trait check
return False
elif (type(y) == list or type(y) == set) and type(y[0]) == type:
# FIXME:
type_check = in_operator(x[0], y[0])
len_check = len(x) == len(y)
return type_check and len_check
elif type(y) == dict and type(y[0]) == type:
NotImplemented
else:
return x in y
class Range:
def __init__(self, start, end):
self.start = start
self.end = end
def __contains__(self, item):
pass
def __getitem__(self, item):
pass
def __len__(self):
pass
def __iter__(self):
return RangeIterator(rng=self)
Sequence.register(Range)
Container.register(Range)
Iterable.register(Range)
# represents `start<..end`
class LeftOpenRange(Range):
def __contains__(self, item):
return self.start < item <= self.end
def __getitem__(self, item):
return NotImplemented
def __len__(self):
return NotImplemented
# represents `start..<end`
class RightOpenRange(Range):
def __contains__(self, item):
return self.start <= item < self.end
def __getitem__(self, item):
return NotImplemented
def __len__(self):
return NotImplemented
# represents `start<..<end`
class OpenRange(Range):
def __contains__(self, item):
return self.start < item < self.end
def __getitem__(self, item):
return NotImplemented
def __len__(self):
return NotImplemented
# represents `start..end`
class ClosedRange(Range):
def __contains__(self, item):
return self.start <= item <= self.end
def __getitem__(self, item):
return NotImplemented
def __len__(self):
return NotImplemented
class RangeIterator:
def __init__(self, rng):
self.rng = rng
self.needle = self.rng.start
if type(self.rng.start) == int:
if not(self.needle in self.rng):
self.needle += 1
elif type(self.rng.start) == str:
if not(self.needle in self.rng):
self.needle = chr(ord(self.needle) + 1)
else:
if not(self.needle in self.rng):
self.needle = self.needle.incremented()
def __iter__(self):
return self
def __next__(self):
if type(self.rng.start) == int:
if self.needle in self.rng:
result = self.needle
self.needle += 1
return result
elif type(self.rng.start) == str:
if self.needle in self.rng:
result = self.needle
self.needle = chr(ord(self.needle) + 1)
return result
else:
if self.needle in self.rng:
result = self.needle
self.needle = self.needle.incremented()
return result
raise StopIteration
Iterator.register(RangeIterator)

View file

@ -2,7 +2,8 @@ discard _x = None
discard 1 discard 1
cond c, then, else = # if: |T, U|(Bool, T, U) -> T or U
cond|T: Type|(c: Bool, then: T, else: T): T =
if c: if c:
do then do then
do else do else

View file

@ -1,22 +1,22 @@
[package] [package]
name = "erg_parser" name = "erg_parser"
version = "0.5.7"
description = "The Erg parser" description = "The Erg parser"
authors = ["erg-lang team <moderation.erglang@gmail.com>"] documentation = "http://docs.rs/erg_parser"
license = "MIT OR Apache-2.0" version.workspace = true
edition = "2021" authors.workspace = true
repository = "https://github.com/erg-lang/erg/tree/main/src/erg_compiler/erg_parser" license.workspace = true
documentation = "https://docs.rs/erg_parser" edition.workspace = true
homepage = "https://erg-lang.github.io/" repository.workspace = true
homepage.workspace = true
[features] [features]
debug = [ "erg_common/debug" ] debug = ["erg_common/debug"]
japanese = [ "erg_common/japanese" ] japanese = ["erg_common/japanese"]
simplified_chinese = [ "erg_common/simplified_chinese" ] simplified_chinese = ["erg_common/simplified_chinese"]
traditional_chinese = [ "erg_common/traditional_chinese" ] traditional_chinese = ["erg_common/traditional_chinese"]
[dependencies] [dependencies]
erg_common = { version = "0.5.7", path = "../erg_common" } erg_common = { version = "0.5.9-nightly.0", path = "../erg_common" }
[lib] [lib]
path = "lib.rs" path = "lib.rs"

View file

@ -11,7 +11,7 @@ use erg_common::{
fmt_option, fmt_vec, impl_display_for_enum, impl_display_for_single_struct, fmt_option, fmt_vec, impl_display_for_enum, impl_display_for_single_struct,
impl_display_from_nested, impl_displayable_stream_for_wrapper, impl_locational, impl_display_from_nested, impl_displayable_stream_for_wrapper, impl_locational,
impl_locational_for_enum, impl_nested_display_for_chunk_enum, impl_nested_display_for_enum, impl_locational_for_enum, impl_nested_display_for_chunk_enum, impl_nested_display_for_enum,
impl_stream, impl_stream_for_wrapper, impl_stream, impl_stream_for_wrapper, option_enum_unwrap,
}; };
use erg_common::{fmt_vec_split_with, Str}; use erg_common::{fmt_vec_split_with, Str};
@ -960,6 +960,32 @@ impl Call {
args, args,
} }
} }
pub fn is_match(&self) -> bool {
self.obj
.get_name()
.map(|s| &s[..] == "match")
.unwrap_or(false)
}
pub fn is_assert_cast(&self) -> bool {
self.obj
.get_name()
.map(|s| &s[..] == "assert")
.unwrap_or(false)
&& self
.args
.get_left_or_key("pred")
.map(|pred| pred.is_bin_in())
.unwrap_or(false)
}
pub fn assert_cast_target_type(&self) -> Option<&Expr> {
self.args
.get_left_or_key("pred")
.and_then(|pred| option_enum_unwrap!(pred, Expr::BinOp))
.map(|bin| bin.args[1].as_ref())
}
} }
/// e.g. `Data::{x = 1; y = 2}` /// e.g. `Data::{x = 1; y = 2}`
@ -3132,7 +3158,11 @@ impl_locational_for_enum!(Expr; Lit, Accessor, Array, Tuple, Dict, Set, Record,
impl Expr { impl Expr {
pub fn is_match_call(&self) -> bool { pub fn is_match_call(&self) -> bool {
matches!(self, Expr::Call(Call{ obj, .. }) if obj.get_name().map(|s| &s[..] == "match").unwrap_or(false)) matches!(self, Expr::Call(call) if call.is_match())
}
pub fn is_bin_in(&self) -> bool {
matches!(self, Expr::BinOp(bin) if bin.op.is(TokenKind::InOp))
} }
pub fn is_const_acc(&self) -> bool { pub fn is_const_acc(&self) -> bool {

View file

@ -11,6 +11,18 @@ use erg_common::{impl_display_and_error, impl_stream_for_wrapper, switch_lang};
#[derive(Debug)] #[derive(Debug)]
pub struct LexError(ErrorCore); pub struct LexError(ErrorCore);
impl From<ErrorCore> for LexError {
fn from(core: ErrorCore) -> Self {
Self(core)
}
}
impl From<LexError> for ErrorCore {
fn from(err: LexError) -> Self {
err.0
}
}
#[derive(Debug)] #[derive(Debug)]
pub struct LexErrors(Vec<LexError>); pub struct LexErrors(Vec<LexError>);

View file

@ -461,15 +461,30 @@ impl Lexer /*<'a>*/ {
let mut num = mantissa; let mut num = mantissa;
debug_power_assert!(self.peek_cur_ch(), ==, Some('e')); debug_power_assert!(self.peek_cur_ch(), ==, Some('e'));
num.push(self.consume().unwrap()); // e num.push(self.consume().unwrap()); // e
num.push(self.consume().unwrap()); // + | - if self.peek_cur_ch().is_some() {
while let Some(cur) = self.peek_cur_ch() { num.push(self.consume().unwrap()); // + | -
if cur.is_ascii_digit() || cur == '_' { while let Some(cur) = self.peek_cur_ch() {
num.push(self.consume().unwrap()); if cur.is_ascii_digit() || cur == '_' {
} else { num.push(self.consume().unwrap());
break; } else {
break;
}
} }
Ok(self.emit_token(RatioLit, &num))
} else {
let token = self.emit_token(RatioLit, &num);
Err(LexError::syntax_error(
0,
token.loc(),
switch_lang!(
"japanese" => format!("`{}`は無効な十進数リテラルです", &token.content),
"simplified_chinese" => format!("`{}`是无效的十进制字词", &token.content),
"traditional_chinese" => format!("`{}`是無效的十進製文字", &token.content),
"english" => format!("`{}` is invalid decimal literal", &token.content),
),
None,
))
} }
Ok(self.emit_token(RatioLit, &num))
} }
/// `_` will be removed at compiletime /// `_` will be removed at compiletime
@ -851,6 +866,10 @@ impl Iterator for Lexer /*<'a>*/ {
))) )))
} }
} }
Some('-') => {
self.consume();
self.accept(Inclusion, "<-")
}
Some('=') => { Some('=') => {
self.consume(); self.consume();
self.accept(LessEq, "<=") self.accept(LessEq, "<=")

View file

@ -471,7 +471,8 @@ impl Parser {
} }
} }
} }
Some(t) if t.is(LSqBr) => { // x[...] (`x [...]` will interpreted as `x([...])`)
Some(t) if t.is(LSqBr) && acc.col_end().unwrap() == t.col_begin().unwrap() => {
self.skip(); self.skip();
let index = self let index = self
.try_reduce_expr(false, false, false) .try_reduce_expr(false, false, false)
@ -510,52 +511,6 @@ impl Parser {
Ok(acc) Ok(acc)
} }
fn validate_const_expr(&mut self, expr: Expr) -> ParseResult<ConstExpr> {
match expr {
Expr::Lit(l) => Ok(ConstExpr::Lit(l)),
Expr::Accessor(Accessor::Ident(local)) => {
let local = ConstLocal::new(local.name.into_token());
Ok(ConstExpr::Accessor(ConstAccessor::Local(local)))
}
Expr::Array(array) => match array {
Array::Normal(arr) => {
let (elems, _, _) = arr.elems.deconstruct();
let mut const_elems = vec![];
for elem in elems.into_iter() {
let const_expr = self.validate_const_expr(elem.expr)?;
const_elems.push(ConstPosArg::new(const_expr));
}
let elems = ConstArgs::new(const_elems, vec![], None);
let const_arr = ConstArray::new(arr.l_sqbr, arr.r_sqbr, elems, None);
Ok(ConstExpr::Array(const_arr))
}
other => {
self.errs.push(ParseError::feature_error(
line!() as usize,
other.loc(),
"???",
));
Err(())
}
},
// TODO: App, Record, BinOp, UnaryOp,
other => {
self.errs.push(ParseError::syntax_error(
0,
other.loc(),
switch_lang!(
"japanese" => "この式はコンパイル時計算できないため、型引数には使用できません",
"simplified_chinese" => "此表达式在编译时不可计算,因此不能用作类型参数",
"traditional_chinese" => "此表達式在編譯時不可計算,因此不能用作類型參數",
"english" => "this expression is not computable at the compile-time, so cannot used as a type-argument",
),
None,
));
Err(())
}
}
}
/// For parsing elements of arrays and tuples /// For parsing elements of arrays and tuples
fn try_reduce_elems(&mut self) -> ParseResult<ArrayInner> { fn try_reduce_elems(&mut self) -> ParseResult<ArrayInner> {
debug_call_info!(self); debug_call_info!(self);
@ -950,9 +905,7 @@ impl Parser {
} }
} }
let defs = RecordAttrs::from(defs); let defs = RecordAttrs::from(defs);
let class = self let class = Self::expr_to_type_spec(class).map_err(|e| self.errs.push(e))?;
.convert_rhs_to_type_spec(class)
.map_err(|_| self.stack_dec())?;
self.level -= 1; self.level -= 1;
Ok(Methods::new(class, vis, defs)) Ok(Methods::new(class, vis, defs))
} }
@ -1036,9 +989,7 @@ impl Parser {
let t_spec = self let t_spec = self
.try_reduce_expr(false, false, false) .try_reduce_expr(false, false, false)
.map_err(|_| self.stack_dec())?; .map_err(|_| self.stack_dec())?;
let t_spec = self let t_spec = Self::expr_to_type_spec(t_spec).map_err(|e| self.errs.push(e))?;
.convert_rhs_to_type_spec(t_spec)
.map_err(|_| self.stack_dec())?;
let expr = Expr::TypeAsc(TypeAscription::new(lhs, op, t_spec)); let expr = Expr::TypeAsc(TypeAscription::new(lhs, op, t_spec));
stack.push(ExprOrOp::Expr(expr)); stack.push(ExprOrOp::Expr(expr));
} }
@ -1280,9 +1231,7 @@ impl Parser {
let t_spec = self let t_spec = self
.try_reduce_expr(false, in_type_args, in_brace) .try_reduce_expr(false, in_type_args, in_brace)
.map_err(|_| self.stack_dec())?; .map_err(|_| self.stack_dec())?;
let t_spec = self let t_spec = Self::expr_to_type_spec(t_spec).map_err(|e| self.errs.push(e))?;
.convert_rhs_to_type_spec(t_spec)
.map_err(|_| self.stack_dec())?;
let expr = Expr::TypeAsc(TypeAscription::new(lhs, op, t_spec)); let expr = Expr::TypeAsc(TypeAscription::new(lhs, op, t_spec));
stack.push(ExprOrOp::Expr(expr)); stack.push(ExprOrOp::Expr(expr));
} }
@ -2173,9 +2122,7 @@ impl Parser {
pack: DataPack, pack: DataPack,
) -> ParseResult<VarDataPackPattern> { ) -> ParseResult<VarDataPackPattern> {
debug_call_info!(self); debug_call_info!(self);
let class = self let class = Self::expr_to_type_spec(*pack.class).map_err(|e| self.errs.push(e))?;
.convert_rhs_to_type_spec(*pack.class)
.map_err(|_| self.stack_dec())?;
let args = self let args = self
.convert_record_to_record_pat(pack.args) .convert_record_to_record_pat(pack.args)
.map_err(|_| self.stack_dec())?; .map_err(|_| self.stack_dec())?;
@ -2463,7 +2410,7 @@ impl Parser {
fn convert_kw_arg_to_default_param(&mut self, arg: KwArg) -> ParseResult<ParamSignature> { fn convert_kw_arg_to_default_param(&mut self, arg: KwArg) -> ParseResult<ParamSignature> {
debug_call_info!(self); debug_call_info!(self);
let pat = ParamPattern::VarName(VarName::new(arg.keyword)); let pat = ParamPattern::VarName(VarName::new(arg.keyword));
let expr = self.validate_const_expr(arg.expr)?; let expr = Self::validate_const_expr(arg.expr).map_err(|e| self.errs.push(e))?;
let param = ParamSignature::new(pat, arg.t_spec, Some(expr)); let param = ParamSignature::new(pat, arg.t_spec, Some(expr));
self.level -= 1; self.level -= 1;
Ok(param) Ok(param)
@ -2672,95 +2619,51 @@ impl Parser {
TypeBoundSpecs::empty(), TypeBoundSpecs::empty(),
)) ))
} }
}
fn convert_rhs_to_type_spec(&mut self, rhs: Expr) -> ParseResult<TypeSpec> { // The APIs defined below are also used by `ASTLowerer` to interpret expressions as types.
debug_call_info!(self); impl Parser {
match rhs { fn validate_const_expr(expr: Expr) -> Result<ConstExpr, ParseError> {
Expr::Accessor(acc) => { match expr {
let t_spec = self Expr::Lit(l) => Ok(ConstExpr::Lit(l)),
.convert_accessor_to_type_spec(acc) Expr::Accessor(Accessor::Ident(local)) => {
.map_err(|_| self.stack_dec())?; let local = ConstLocal::new(local.name.into_token());
self.level -= 1; Ok(ConstExpr::Accessor(ConstAccessor::Local(local)))
Ok(t_spec)
} }
Expr::Call(call) => { Expr::Array(array) => match array {
let predecl = self Array::Normal(arr) => {
.convert_call_to_predecl_type_spec(call) let (elems, _, _) = arr.elems.deconstruct();
.map_err(|_| self.stack_dec())?; let mut const_elems = vec![];
self.level -= 1; for elem in elems.into_iter() {
Ok(TypeSpec::PreDeclTy(predecl)) let const_expr = Self::validate_const_expr(elem.expr)?;
} const_elems.push(ConstPosArg::new(const_expr));
Expr::Lambda(lambda) => { }
let lambda = self let elems = ConstArgs::new(const_elems, vec![], None);
.convert_lambda_to_subr_type_spec(lambda) let const_arr = ConstArray::new(arr.l_sqbr, arr.r_sqbr, elems, None);
.map_err(|_| self.stack_dec())?; Ok(ConstExpr::Array(const_arr))
self.level -= 1;
Ok(TypeSpec::Subr(lambda))
}
Expr::Array(array) => {
let array = self
.convert_array_to_array_type_spec(array)
.map_err(|_| self.stack_dec())?;
self.level -= 1;
Ok(TypeSpec::Array(array))
}
Expr::Set(set) => {
let set = self
.convert_set_to_set_type_spec(set)
.map_err(|_| self.stack_dec())?;
self.level -= 1;
Ok(TypeSpec::Set(set))
}
Expr::BinOp(bin) => {
if bin.op.kind.is_range_op() {
let op = bin.op;
let mut args = bin.args.into_iter();
let lhs = self
.validate_const_expr(*args.next().unwrap())
.map_err(|_| self.stack_dec())?;
let rhs = self
.validate_const_expr(*args.next().unwrap())
.map_err(|_| self.stack_dec())?;
self.level -= 1;
Ok(TypeSpec::Interval { op, lhs, rhs })
} else if bin.op.kind == TokenKind::AndOp {
let mut args = bin.args.into_iter();
let lhs = self
.convert_rhs_to_type_spec(*args.next().unwrap())
.map_err(|_| self.stack_dec())?;
let rhs = self
.convert_rhs_to_type_spec(*args.next().unwrap())
.map_err(|_| self.stack_dec())?;
self.level -= 1;
Ok(TypeSpec::and(lhs, rhs))
} else if bin.op.kind == TokenKind::OrOp {
let mut args = bin.args.into_iter();
let lhs = self
.convert_rhs_to_type_spec(*args.next().unwrap())
.map_err(|_| self.stack_dec())?;
let rhs = self
.convert_rhs_to_type_spec(*args.next().unwrap())
.map_err(|_| self.stack_dec())?;
self.level -= 1;
Ok(TypeSpec::or(lhs, rhs))
} else {
self.level -= 1;
let err = ParseError::simple_syntax_error(line!() as usize, bin.loc());
self.errs.push(err);
Err(())
} }
} other => Err(ParseError::feature_error(
other => { line!() as usize,
self.level -= 1; other.loc(),
let err = ParseError::simple_syntax_error(line!() as usize, other.loc()); "???",
self.errs.push(err); )),
Err(()) },
} // TODO: App, Record, BinOp, UnaryOp,
other => Err(ParseError::syntax_error(
line!() as usize,
other.loc(),
switch_lang!(
"japanese" => "この式はコンパイル時計算できないため、型引数には使用できません",
"simplified_chinese" => "此表达式在编译时不可计算,因此不能用作类型参数",
"traditional_chinese" => "此表達式在編譯時不可計算,因此不能用作類型參數",
"english" => "this expression is not computable at the compile-time, so cannot used as a type-argument",
),
None,
)),
} }
} }
fn convert_accessor_to_type_spec(&mut self, accessor: Accessor) -> ParseResult<TypeSpec> { fn accessor_to_type_spec(accessor: Accessor) -> Result<TypeSpec, ParseError> {
debug_call_info!(self);
let t_spec = match accessor { let t_spec = match accessor {
Accessor::Ident(ident) => { Accessor::Ident(ident) => {
let predecl = let predecl =
@ -2768,32 +2671,22 @@ impl Parser {
TypeSpec::PreDeclTy(predecl) TypeSpec::PreDeclTy(predecl)
} }
Accessor::TypeApp(tapp) => { Accessor::TypeApp(tapp) => {
let spec = self let spec = Self::expr_to_type_spec(*tapp.obj)?;
.convert_rhs_to_type_spec(*tapp.obj)
.map_err(|_| self.stack_dec())?;
TypeSpec::type_app(spec, tapp.type_args) TypeSpec::type_app(spec, tapp.type_args)
} }
other => { other => {
self.level -= 1;
let err = ParseError::simple_syntax_error(line!() as usize, other.loc()); let err = ParseError::simple_syntax_error(line!() as usize, other.loc());
self.errs.push(err); return Err(err);
return Err(());
} }
}; };
self.level -= 1;
Ok(t_spec) Ok(t_spec)
} }
fn convert_call_to_predecl_type_spec(&mut self, _call: Call) -> ParseResult<PreDeclTypeSpec> { fn call_to_predecl_type_spec(_call: Call) -> Result<PreDeclTypeSpec, ParseError> {
debug_call_info!(self);
todo!() todo!()
} }
fn convert_lambda_to_subr_type_spec( fn lambda_to_subr_type_spec(mut lambda: Lambda) -> Result<SubrTypeSpec, ParseError> {
&mut self,
mut lambda: Lambda,
) -> ParseResult<SubrTypeSpec> {
debug_call_info!(self);
let bounds = lambda.sig.bounds; let bounds = lambda.sig.bounds;
let lparen = lambda.sig.params.parens.map(|(l, _)| l); let lparen = lambda.sig.params.parens.map(|(l, _)| l);
let mut non_defaults = vec![]; let mut non_defaults = vec![];
@ -2838,8 +2731,7 @@ impl Parser {
}; };
defaults.push(param); defaults.push(param);
} }
let return_t = self.convert_rhs_to_type_spec(lambda.body.remove(0))?; let return_t = Self::expr_to_type_spec(lambda.body.remove(0))?;
self.level -= 1;
Ok(SubrTypeSpec::new( Ok(SubrTypeSpec::new(
bounds, bounds,
lparen, lparen,
@ -2851,45 +2743,86 @@ impl Parser {
)) ))
} }
fn convert_array_to_array_type_spec(&mut self, array: Array) -> ParseResult<ArrayTypeSpec> { fn array_to_array_type_spec(array: Array) -> Result<ArrayTypeSpec, ParseError> {
debug_call_info!(self);
match array { match array {
Array::Normal(arr) => { Array::Normal(arr) => {
// TODO: add hint // TODO: add hint
self.errs let err = ParseError::simple_syntax_error(line!() as usize, arr.loc());
.push(ParseError::simple_syntax_error(line!() as usize, arr.loc())); Err(err)
Err(())
} }
Array::WithLength(arr) => { Array::WithLength(arr) => {
let t_spec = self.convert_rhs_to_type_spec(arr.elem.expr)?; let t_spec = Self::expr_to_type_spec(arr.elem.expr)?;
let len = self.validate_const_expr(*arr.len)?; let len = Self::validate_const_expr(*arr.len)?;
self.level -= 1;
Ok(ArrayTypeSpec::new(t_spec, len)) Ok(ArrayTypeSpec::new(t_spec, len))
} }
Array::Comprehension(arr) => { Array::Comprehension(arr) => {
// TODO: add hint // TODO: add hint
self.errs let err = ParseError::simple_syntax_error(line!() as usize, arr.loc());
.push(ParseError::simple_syntax_error(line!() as usize, arr.loc())); Err(err)
Err(())
} }
} }
} }
fn convert_set_to_set_type_spec(&mut self, set: Set) -> ParseResult<SetTypeSpec> { fn set_to_set_type_spec(set: Set) -> Result<SetTypeSpec, ParseError> {
debug_call_info!(self);
match set { match set {
Set::Normal(arr) => { Set::Normal(arr) => {
// TODO: add hint // TODO: add hint
self.errs let err = ParseError::simple_syntax_error(line!() as usize, arr.loc());
.push(ParseError::simple_syntax_error(line!() as usize, arr.loc())); Err(err)
Err(())
} }
Set::WithLength(set) => { Set::WithLength(set) => {
let t_spec = self.convert_rhs_to_type_spec(set.elem.expr)?; let t_spec = Self::expr_to_type_spec(set.elem.expr)?;
let len = self.validate_const_expr(*set.len)?; let len = Self::validate_const_expr(*set.len)?;
self.level -= 1;
Ok(SetTypeSpec::new(t_spec, len)) Ok(SetTypeSpec::new(t_spec, len))
} }
} }
} }
pub fn expr_to_type_spec(rhs: Expr) -> Result<TypeSpec, ParseError> {
match rhs {
Expr::Accessor(acc) => Self::accessor_to_type_spec(acc),
Expr::Call(call) => {
let predecl = Self::call_to_predecl_type_spec(call)?;
Ok(TypeSpec::PreDeclTy(predecl))
}
Expr::Lambda(lambda) => {
let lambda = Self::lambda_to_subr_type_spec(lambda)?;
Ok(TypeSpec::Subr(lambda))
}
Expr::Array(array) => {
let array = Self::array_to_array_type_spec(array)?;
Ok(TypeSpec::Array(array))
}
Expr::Set(set) => {
let set = Self::set_to_set_type_spec(set)?;
Ok(TypeSpec::Set(set))
}
Expr::BinOp(bin) => {
if bin.op.kind.is_range_op() {
let op = bin.op;
let mut args = bin.args.into_iter();
let lhs = Self::validate_const_expr(*args.next().unwrap())?;
let rhs = Self::validate_const_expr(*args.next().unwrap())?;
Ok(TypeSpec::Interval { op, lhs, rhs })
} else if bin.op.kind == TokenKind::AndOp {
let mut args = bin.args.into_iter();
let lhs = Self::expr_to_type_spec(*args.next().unwrap())?;
let rhs = Self::expr_to_type_spec(*args.next().unwrap())?;
Ok(TypeSpec::and(lhs, rhs))
} else if bin.op.kind == TokenKind::OrOp {
let mut args = bin.args.into_iter();
let lhs = Self::expr_to_type_spec(*args.next().unwrap())?;
let rhs = Self::expr_to_type_spec(*args.next().unwrap())?;
Ok(TypeSpec::or(lhs, rhs))
} else {
let err = ParseError::simple_syntax_error(line!() as usize, bin.loc());
Err(err)
}
}
other => {
let err = ParseError::simple_syntax_error(line!() as usize, other.loc());
Err(err)
}
}
}
} }

View file

@ -109,6 +109,8 @@ pub enum TokenKind {
RefMutOp, RefMutOp,
/// = /// =
Equal, Equal,
/// <-
Inclusion,
/// := /// :=
Walrus, Walrus,
/// -> /// ->
@ -214,9 +216,8 @@ impl TokenKind {
| InfLit => TokenCategory::Literal, | InfLit => TokenCategory::Literal,
PrePlus | PreMinus | PreBitNot | Mutate | RefOp | RefMutOp => TokenCategory::UnaryOp, PrePlus | PreMinus | PreBitNot | Mutate | RefOp | RefMutOp => TokenCategory::UnaryOp,
Try => TokenCategory::PostfixOp, Try => TokenCategory::PostfixOp,
Comma | Colon | DblColon | SupertypeOf | SubtypeOf | Dot | Pipe | Walrus => { Comma | Colon | DblColon | SupertypeOf | SubtypeOf | Dot | Pipe | Walrus
TokenCategory::SpecialBinOp | Inclusion => TokenCategory::SpecialBinOp,
}
Equal => TokenCategory::DefOp, Equal => TokenCategory::DefOp,
FuncArrow | ProcArrow => TokenCategory::LambdaOp, FuncArrow | ProcArrow => TokenCategory::LambdaOp,
Semi | Newline => TokenCategory::Separator, Semi | Newline => TokenCategory::Separator,
@ -246,14 +247,14 @@ impl TokenKind {
BitOr => 120, // || BitOr => 120, // ||
Closed | LeftOpen | RightOpen | Open => 100, // range operators Closed | LeftOpen | RightOpen | Open => 100, // range operators
Less | Gre | LessEq | GreEq | DblEq | NotEq | InOp | NotInOp | IsOp | IsNotOp => 90, // < > <= >= == != in notin is isnot Less | Gre | LessEq | GreEq | DblEq | NotEq | InOp | NotInOp | IsOp | IsNotOp => 90, // < > <= >= == != in notin is isnot
AndOp => 80, // and AndOp => 80, // and
OrOp => 70, // or OrOp => 70, // or
FuncArrow | ProcArrow => 60, // -> => FuncArrow | ProcArrow | Inclusion => 60, // -> => <-
Colon | SupertypeOf | SubtypeOf => 50, // : :> <: Colon | SupertypeOf | SubtypeOf => 50, // : :> <:
Comma => 40, // , Comma => 40, // ,
Equal | Walrus => 20, // = := Equal | Walrus => 20, // = :=
Newline | Semi => 10, // \n ; Newline | Semi => 10, // \n ;
LParen | LBrace | LSqBr | Indent => 0, // ( { [ Indent LParen | LBrace | LSqBr | Indent => 0, // ( { [ Indent
_ => return None, _ => return None,
}; };
Some(prec) Some(prec)

View file

@ -1,25 +1,25 @@
[package] [package]
name = "erg_type" name = "erg_type"
version = "0.5.7"
description = "APIs for Erg types" description = "APIs for Erg types"
authors = ["erg-lang team <moderation.erglang@gmail.com>"] documentation = "http://docs.rs/erg_type"
license = "MIT OR Apache-2.0" version.workspace = true
edition = "2021" authors.workspace = true
repository = "https://github.com/erg-lang/erg/tree/main/compiler/erg_type" license.workspace = true
documentation = "https://docs.rs/erg_type" edition.workspace = true
homepage = "https://erg-lang.github.io/" repository.workspace = true
homepage.workspace = true
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[features] [features]
debug = [ "erg_common/debug" ] debug = ["erg_common/debug"]
japanese = [ "erg_common/japanese" ] japanese = ["erg_common/japanese"]
simplified_chinese = [ "erg_common/simplified_chinese" ] simplified_chinese = ["erg_common/simplified_chinese"]
traditional_chinese = [ "erg_common/traditional_chinese" ] traditional_chinese = ["erg_common/traditional_chinese"]
[dependencies] [dependencies]
erg_common = { version = "0.5.7", path = "../erg_common" } erg_common = { version = "0.5.9-nightly.0", path = "../erg_common" }
erg_parser = { version = "0.5.7", path = "../erg_parser" } erg_parser = { version = "0.5.9-nightly.0", path = "../erg_parser" }
[lib] [lib]
path = "lib.rs" path = "lib.rs"

View file

@ -330,7 +330,17 @@ pub fn callable(param_ts: Vec<Type>, return_t: Type) -> Type {
#[inline] #[inline]
pub fn builtin_mono<S: Into<Str>>(name: S) -> Type { pub fn builtin_mono<S: Into<Str>>(name: S) -> Type {
Type::BuiltinMono(name.into()) let name = name.into();
if cfg!(feature = "debug") {
// do not use for: `Int`, `Nat`, ...
match &name[..] {
"Obj" | "Int" | "Nat" | "Ratio" | "Float" | "Bool" | "Str" | "NoneType" | "Code"
| "Frame" | "Error" | "Inf" | "NegInf" | "Type" | "ClassType" | "TraitType"
| "Patch" | "NotImplemented" | "Ellipsis" | "Never" => todo!("{name}"),
_ => {}
}
}
Type::BuiltinMono(name)
} }
#[inline] #[inline]

View file

@ -325,6 +325,17 @@ impl<T> FreeKind<T> {
} }
} }
pub fn new_unbound(lev: Level, constraint: Constraint) -> Self {
UNBOUND_ID.with(|id| {
*id.borrow_mut() += 1;
Self::Unbound {
id: *id.borrow(),
lev,
constraint,
}
})
}
pub const fn named_unbound(name: Str, lev: Level, constraint: Constraint) -> Self { pub const fn named_unbound(name: Str, lev: Level, constraint: Constraint) -> Self {
Self::NamedUnbound { Self::NamedUnbound {
name, name,
@ -440,6 +451,14 @@ impl<T: Clone + HasLevel> Free<T> {
*self.borrow_mut() = FreeKind::Linked(to.clone()); *self.borrow_mut() = FreeKind::Linked(to.clone());
} }
pub fn replace(&self, to: FreeKind<T>) {
// prevent linking to self
if self.is_linked() && addr_eq!(*self.borrow(), to) {
return;
}
*self.borrow_mut() = to;
}
/// NOTE: Do not use this except to rewrite circular references. /// NOTE: Do not use this except to rewrite circular references.
/// No reference to any type variable may be left behind when rewriting. /// No reference to any type variable may be left behind when rewriting.
/// However, `get_bound_types` is safe because it does not return references. /// However, `get_bound_types` is safe because it does not return references.

View file

@ -1284,15 +1284,9 @@ impl PartialEq for Type {
rhs: rrhs, rhs: rrhs,
}, },
) => lhs == rlhs && rhs == rrhs, ) => lhs == rlhs && rhs == rrhs,
(Self::FreeVar(fv), other) if fv.is_linked() => &*fv.crack() == other,
(_self, Self::FreeVar(fv)) if fv.is_linked() => _self == &*fv.crack(),
(Self::FreeVar(l), Self::FreeVar(r)) => l == r, (Self::FreeVar(l), Self::FreeVar(r)) => l == r,
(Self::FreeVar(fv), other) => match &*fv.borrow() {
FreeKind::Linked(t) => t == other,
_ => false,
},
(self_, Self::FreeVar(fv)) => match &*fv.borrow() {
FreeKind::Linked(t) => t == self_,
_ => false,
},
(Self::Failure, Self::Failure) | (Self::Uninited, Self::Uninited) => true, (Self::Failure, Self::Failure) | (Self::Uninited, Self::Uninited) => true,
_ => false, _ => false,
} }
@ -1922,11 +1916,6 @@ impl Type {
matches!(self, Self::FreeVar(_)) matches!(self, Self::FreeVar(_))
} }
/// FIXME: `Int or Str` should be monomorphic
pub fn is_monomorphic(&self) -> bool {
matches!(self.typarams_len(), Some(0) | None)
}
pub const fn is_callable(&self) -> bool { pub const fn is_callable(&self) -> bool {
matches!(self, Self::Subr { .. } | Self::Callable { .. }) matches!(self, Self::Subr { .. } | Self::Callable { .. })
} }
@ -1935,6 +1924,18 @@ impl Type {
matches!(self, Self::FreeVar(fv) if fv.is_unbound() || fv.crack().is_unbound_var()) matches!(self, Self::FreeVar(fv) if fv.is_unbound() || fv.crack().is_unbound_var())
} }
/// See also: `is_monomorphized`
pub fn is_monomorphic(&self) -> bool {
matches!(self.typarams_len(), Some(0) | None)
}
/// `Set(Int, 3)` is not monomorphic but monomorphized
pub fn is_monomorphized(&self) -> bool {
matches!(self.typarams_len(), Some(0) | None)
|| (self.has_no_qvar() && self.has_no_unbound_var())
}
/// if the type is polymorphic
pub fn has_qvar(&self) -> bool { pub fn has_qvar(&self) -> bool {
match self { match self {
Self::MonoQVar(_) | Self::PolyQVar { .. } => true, Self::MonoQVar(_) | Self::PolyQVar { .. } => true,
@ -1972,6 +1973,10 @@ impl Type {
} }
} }
pub fn has_no_qvar(&self) -> bool {
!self.has_qvar()
}
pub fn is_cachable(&self) -> bool { pub fn is_cachable(&self) -> bool {
match self { match self {
Self::FreeVar(_) => false, Self::FreeVar(_) => false,

View file

@ -406,27 +406,35 @@ impl ValueObj {
matches!(self, Self::Mut(_)) matches!(self, Self::Mut(_))
} }
pub fn from_str(t: Type, content: Str) -> Self { pub fn from_str(t: Type, content: Str) -> Option<Self> {
match t { match t {
Type::Int => Self::Int(content.replace('_', "").parse::<i32>().unwrap()), Type::Int => content.replace('_', "").parse::<i32>().ok().map(Self::Int),
Type::Nat => Self::Nat(content.replace('_', "").parse::<u64>().unwrap()), Type::Nat => content.replace('_', "").parse::<u64>().ok().map(Self::Nat),
Type::Float => Self::Float(content.replace('_', "").parse::<f64>().unwrap()), Type::Float => content
.replace('_', "")
.parse::<f64>()
.ok()
.map(Self::Float),
// TODO: // TODO:
Type::Ratio => Self::Float(content.replace('_', "").parse::<f64>().unwrap()), Type::Ratio => content
.replace('_', "")
.parse::<f64>()
.ok()
.map(Self::Float),
Type::Str => { Type::Str => {
if &content[..] == "\"\"" { if &content[..] == "\"\"" {
Self::Str(Str::from("")) Some(Self::Str(Str::from("")))
} else { } else {
let replaced = content.trim_start_matches('\"').trim_end_matches('\"'); let replaced = content.trim_start_matches('\"').trim_end_matches('\"');
Self::Str(Str::rc(replaced)) Some(Self::Str(Str::rc(replaced)))
} }
} }
Type::Bool => Self::Bool(&content[..] == "True"), Type::Bool => Some(Self::Bool(&content[..] == "True")),
Type::NoneType => Self::None, Type::NoneType => Some(Self::None),
Type::Ellipsis => Self::Ellipsis, Type::Ellipsis => Some(Self::Ellipsis),
Type::NotImplemented => Self::NotImplemented, Type::NotImplemented => Some(Self::NotImplemented),
Type::Inf => Self::Inf, Type::Inf => Some(Self::Inf),
Type::NegInf => Self::NegInf, Type::NegInf => Some(Self::NegInf),
_ => todo!("{t} {content}"), _ => todo!("{t} {content}"),
} }
} }
@ -534,7 +542,7 @@ impl ValueObj {
Self::None => Type::NoneType, Self::None => Type::NoneType,
other => panic!("{other} object cannot be mutated"), other => panic!("{other} object cannot be mutated"),
}, },
Self::Illegal => todo!(), Self::Illegal => Type::Failure,
} }
} }

View file

@ -0,0 +1,9 @@
# Troubleshooting
## Q: Local builds succeed, but GitHub Actions builds fail
A: The branch you are working on may not be following the changes in `main`.
## Q: The pre-commit check fails
A: Try committing again. It may fail the first time. If it fails again and again, the code may contain a bug.

View file

@ -0,0 +1,12 @@
# トラブルシューティング
[![badge](https://img.shields.io/endpoint.svg?url=https%3A%2F%2Fgezf7g7pd5.execute-api.ap-northeast-1.amazonaws.com%2Fdefault%2Fsource_up_to_date%3Fowner%3Derg-lang%26repos%3Derg%26ref%3Dmain%26path%3Ddoc/EN/dev_guide/troubleshooting.md%26commit_hash%3De033e4942e70657008427f05def2d1b1bfb5ed66)](https://gezf7g7pd5.execute-api.ap-northeast-1.amazonaws.com/default/source_up_to_date?owner=erg-lang&repos=erg&ref=main&path=doc/EN/dev_guide/troubleshooting.md&commit_hash=e033e4942e70657008427f05def2d1b1bfb5ed66)
## Q: ローカルでのビルドは成功したが、GitHub Actionsのビルドが失敗する
A: あなたの作業しているブランチが`main`の変更に追従していない可能性があります。
## Q: pre-commitのチェックが失敗する
A: もう一度コミットを試みてください。最初の1回は失敗することがあります。何度やっても失敗する場合、コードにバグが含まれている可能性があります。

View file

@ -0,0 +1,11 @@
# 故障诊断
[![badge](https://img.shields.io/endpoint.svg?url=https%3A%2F%2Fgezf7g7pd5.execute-api.ap-northeast-1.amazonaws.com%2Fdefault%2Fsource_up_to_date%3Fowner%3Derg-lang%26repos%3Derg%26ref%3Dmain%26path%3Ddoc/EN/dev_guide/troubleshooting.md%26commit_hash%3De033e4942e70657008427f05def2d1b1bfb5ed66)](https://gezf7g7pd5.execute-api.ap-northeast-1.amazonaws.com/default/source_up_to_date?owner=erg-lang&repos=erg&ref=main&path=doc/EN/dev_guide/troubleshooting.md&commit_hash=e033e4942e70657008427f05def2d1b1bfb5ed66)
## Q: 本地生成成功, 但 GitHub Actions 生成失败
A: 您正在处理的分支可能没有Pull`main`中的更改
## Q: 提交前检查失败
A: 尝试再次提交, 第一次可能会误判, 如果一次又一次的失败, 那么你的代码可能包含错误

View file

@ -0,0 +1,11 @@
# 故障診斷
[![badge](https://img.shields.io/endpoint.svg?url=https%3A%2F%2Fgezf7g7pd5.execute-api.ap-northeast-1.amazonaws.com%2Fdefault%2Fsource_up_to_date%3Fowner%3Derg-lang%26repos%3Derg%26ref%3Dmain%26path%3Ddoc/EN/dev_guide/troubleshooting.md%26commit_hash%3De033e4942e70657008427f05def2d1b1bfb5ed66)](https://gezf7g7pd5.execute-api.ap-northeast-1.amazonaws.com/default/source_up_to_date?owner=erg-lang&repos=erg&ref=main&path=doc/EN/dev_guide/troubleshooting.md&commit_hash=e033e4942e70657008427f05def2d1b1bfb5ed66)
## Q: 本地生成成功, 但 GitHub Actions 生成失敗
A: 您正在處理的分支可能沒有Pull`main`中的更改
## Q: 提交前檢查失敗
A: 嘗試再次提交, 第一次可能會誤判, 如果一次又一次的失敗, 那麼你的代碼可能包含錯誤

3
examples/assert_cast.er Normal file
View file

@ -0,0 +1,3 @@
i: Int = 2 - 1
assert i in Nat
i: Nat

View file

@ -109,6 +109,9 @@ impl Runnable for DummyVM {
.replace(".er", ".pyc"); .replace(".er", ".pyc");
self.compiler self.compiler
.compile_and_dump_as_pyc(&filename, self.input().read(), "exec")?; .compile_and_dump_as_pyc(&filename, self.input().read(), "exec")?;
if self.cfg().dump_as_pyc {
return Ok(0);
}
let code = exec_pyc(&filename); let code = exec_pyc(&filename);
remove_file(&filename).unwrap(); remove_file(&filename).unwrap();
Ok(code.unwrap_or(1)) Ok(code.unwrap_or(1))

View file

@ -1,6 +1,6 @@
for! 1..<100, i => for! 1..<100, i =>
match (i % 3, i % 5): match [i % 3, i % 5]:
(0, 0) => print! "FizzBuzz" [0, 0] => print! "FizzBuzz"
(0, _) => print! "Fizz" [0, _] => print! "Fizz"
(_, 0) => print! "Buzz" [_, 0] => print! "Buzz"
(_, _) => print! i [_, _] => print! i

View file

@ -11,6 +11,11 @@ fn exec_addition() -> Result<(), ()> {
expect_failure("tests/addition.er") expect_failure("tests/addition.er")
} }
#[test]
fn exec_assert_cast() -> Result<(), ()> {
expect_success("examples/assert_cast.er")
}
#[test] #[test]
fn exec_class() -> Result<(), ()> { fn exec_class() -> Result<(), ()> {
expect_success("examples/class.er") expect_success("examples/class.er")
@ -51,6 +56,11 @@ fn exec_move_check() -> Result<(), ()> {
expect_failure("examples/move_check.er") expect_failure("examples/move_check.er")
} }
#[test]
fn exec_prelude() -> Result<(), ()> {
expect_success("compiler/erg_compiler/std/prelude.er")
}
#[test] #[test]
fn exec_quantified() -> Result<(), ()> { fn exec_quantified() -> Result<(), ()> {
expect_success("examples/quantified.er") expect_success("examples/quantified.er")