Merge remote-tracking branch 'upstream/main' into add-sync_to_translation_status.er

This commit is contained in:
toddlerer 2023-01-27 06:36:35 +09:00
commit c3d27fb059
No known key found for this signature in database
GPG key ID: 44060B0ACE658F8D
47 changed files with 462 additions and 237 deletions

View file

@ -56,3 +56,6 @@ bd_re = "build --features debug --release"
bd_ja_re = "build --features debug --features japanese --release"
bd_zh_cn_re = "build --features debug --features simplified_chinese --release"
bd_zh_tw_re = "build --features debug --features traditional_chinese --release"
inst = "install --path . --features els"
dinst = "install --path . --features debug --features els"

1
.gitignore vendored
View file

@ -17,6 +17,7 @@
/*/.DS_Store
/.idea/
/timeit.dat
**/__pycache__/
# Nix
.direnv

View file

@ -6,7 +6,7 @@ Beginners should read the instructions [here](https://github.com/erg-lang/erg/is
## Documents
If you are thinking of contributing to Erg, you should read documents under `doc/*/dev_guide`. In particular, please pre-install what is written in `env.md`.
If you are thinking of contributing to Erg, you should read documents under `doc/*/dev_guide`. In particular, please pre-install what is written in [`env.md`](doc/EN/dev_guide/env.md).
Or you are interested in the internal structure of Erg, `doc/*/compiler` may provide useful information.

View file

@ -77,7 +77,7 @@
even for and while expressions are just one of the subroutines, so this is possible.
```python
loop! block = while! do(True), block
loop! block! = while! do! True, block!
# equals to `while! do(True), do! print! "hello"`
loop! do!:

View file

@ -76,7 +76,7 @@
Ergでは特別扱いされる構文要素がとても少なく、例えば予約語が一つもありません。以下のような芸当も可能です。
```python
loop! block = while! do(True), block
loop! block! = while! do! True, block!
# `while! do(True), do! print! "hello"`と同じです
loop! do!:

View file

@ -76,7 +76,7 @@
在Erg中很少有东西被认为是特殊的没有关键字因此for和while表达式也只是子程序之一
```python
loop! block = while! do(True), block
loop! block! = while! do! True, block!
# equals to `while! do(True), do! print! "hello"`
loop! do!:

View file

@ -76,9 +76,9 @@
在Erg中很少有東西被認為是特殊的沒有關鍵字因此for和while表達式也只是子程序之一
```python
loop! block = while! do(True), block
loop! block! = while! do! True, block!
# equals to `while! do(True), do! print! "hello"`
# equals to `while! do! True, do! print! "hello"`
loop! do!:
print! "hello"
```

View file

@ -356,11 +356,11 @@ macro_rules! debug_enum_assert {
macro_rules! debug_info {
($output:ident) => {{
#[allow(unused_imports)]
use $crate::style::{CYAN, RESET};
use $crate::style::{colors::DEBUG, RESET};
write!(
$output,
"[{}DEBUG{}] {}:{:04}: ",
CYAN,
DEBUG,
RESET,
file!(),
line!()
@ -369,8 +369,8 @@ macro_rules! debug_info {
}};
() => {{
#[allow(unused_imports)]
use $crate::style::{CYAN, RESET};
print!("[{}DEBUG{}] {}:{:04}: ", CYAN, RESET, file!(), line!());
use $crate::style::{colors::DEBUG, RESET};
print!("[{}DEBUG{}] {}:{:04}: ", DEBUG, RESET, file!(), line!());
}};
}
@ -386,25 +386,25 @@ macro_rules! debug_info {
#[macro_export]
macro_rules! log {
(info $($arg: tt)*) => {{
$crate::log!(c GREEN, $($arg)*);
$crate::log!(c DEBUG_MAIN, $($arg)*);
}};
(err $($arg: tt)*) => {{
$crate::log!(c RED, $($arg)*);
$crate::log!(c DEBUG_ERROR, $($arg)*);
}};
(info_f $output:ident, $($arg: tt)*) => {{
$crate::log!(f+c $output, GREEN, $($arg)*);
$crate::log!(f+c $output, DEBUG_MAIN, $($arg)*);
}};
(err_f $output:ident, $($arg: tt)*) => {{
$crate::log!(f+c $output, RED, $($arg)*);
$crate::log!(f+c $output, DEBUG_ERROR, $($arg)*);
}};
(f $output: ident, $($arg: tt)*) => {{
if cfg!(feature = "debug") {
#[allow(unused_imports)]
use $crate::color::{RESET, GREEN, RED};
use $crate::color::{RESET, colors::DEBUG_MAIN, colors::DEBUG_ERROR};
$crate::debug_info!($output);
write!($output, $($arg)*).unwrap();
write!($output, "{}", RESET).unwrap(); // color color anyway
@ -415,7 +415,7 @@ macro_rules! log {
(c $color:ident, $($arg: tt)*) => {{
if cfg!(feature = "debug") {
#[allow(unused_imports)]
use $crate::style::{RESET, GREEN, RED};
use $crate::style::{RESET, colors::DEBUG_MAIN, colors::DEBUG_ERROR};
$crate::debug_info!();
print!("{}", $color);
println!($($arg)*);
@ -426,7 +426,7 @@ macro_rules! log {
(f+c $output:ident, $color:ident, $($arg: tt)*) => {{
if cfg!(feature = "debug") {
#[allow(unused_imports)]
use $crate::style::{RESET, GREEN};
use $crate::style::{RESET, colors::DEBUG_MAIN};
$crate::debug_info!($output);
write!($output, "{}{}{}", $color, $($arg)*, RESET).unwrap();
write!($output, $($arg)*).unwrap();

View file

@ -1,12 +1,15 @@
use self::colors::*;
use std::borrow::Cow;
pub const ATTR_RESET: &str = "\x1b[0m";
pub const BOLD: &str = "\x1b[1m";
pub const UNDERLINE: &str = "\x1b[4m";
pub const REVERSED: &str = "\x1b[7m";
pub const RESET: &str = "\x1b[m";
// Escape sequences change the color of the terminal
pub const RESET: &str = "\x1b[m";
#[cfg(not(feature = "pretty"))]
pub mod colors {
pub const BLACK: &str = "\x1b[30m";
pub const BLUE: &str = "\x1b[94m";
pub const CYAN: &str = "\x1b[96m";
@ -16,14 +19,26 @@ pub const MAGENTA: &str = "\x1b[95m";
pub const RED: &str = "\x1b[91m";
pub const WHITE: &str = "\x1b[97m";
pub const YELLOW: &str = "\x1b[93m";
pub const DEBUG_MAIN: &str = GREEN;
pub const DEBUG: &str = CYAN;
pub const DEBUG_ERROR: &str = RED;
}
// custom colors when use `pretty`
pub const CUSTOM_RED: &str = "\x1b[38;2;255;76;76m";
pub const CUSTOM_BLUE: &str = "\x1b[38;2;76;76;255m";
pub const CUSTOM_GRAY: &str = "\x1b[38;2;231;231;235m";
pub const CUSTOM_CYAN: &str = "\x1b[38;2;76;255;255m";
pub const CUSTOM_MAGENTA: &str = "\x1b[38;2;165;76;255m";
pub const CUSTOM_GREEN: &str = "\x1b[38;2;76;255;76m";
pub const CUSTOM_YELLOW: &str = "\x1b[38;2;255;255;76m";
#[cfg(feature = "pretty")]
pub mod colors {
pub const BLACK: &str = "\x1b[30m";
pub const BLUE: &str = "\x1b[38;2;76;76;255m";
pub const CYAN: &str = "\x1b[38;2;76;255;255m";
pub const GRAY: &str = "\x1b[38;2;231;231;235m";
pub const GREEN: &str = "\x1b[38;2;76;255;76m";
pub const MAGENTA: &str = "\x1b[38;2;165;76;255m";
pub const RED: &str = "\x1b[38;2;255;76;76m";
pub const WHITE: &str = "\x1b[97m";
pub const YELLOW: &str = "\x1b[38;2;255;255;76m";
pub const DEBUG_MAIN: &str = BLUE;
pub const DEBUG: &str = MAGENTA;
pub const DEBUG_ERROR: &str = CYAN;
}
pub fn remove_style(s: &str) -> String {
s.replace(RED, "")
@ -53,13 +68,6 @@ pub enum Color {
Red,
White,
Yellow,
CustomRed,
CustomBlue,
CustomGray,
CustomCyan,
CustomMagenta,
CustomGreen,
CustomYellow,
}
impl Color {
@ -75,13 +83,6 @@ impl Color {
Color::Red => RED,
Color::Yellow => YELLOW,
Color::White => WHITE,
Color::CustomRed => CUSTOM_RED,
Color::CustomBlue => CUSTOM_BLUE,
Color::CustomGray => CUSTOM_GRAY,
Color::CustomCyan => CUSTOM_CYAN,
Color::CustomMagenta => CUSTOM_MAGENTA,
Color::CustomGreen => CUSTOM_GREEN,
Color::CustomYellow => CUSTOM_YELLOW,
}
}
}
@ -115,7 +116,6 @@ pub struct ThemeColors {
pub accent: Color,
}
#[cfg(not(feature = "pretty"))]
pub const COLORS: ThemeColors = ThemeColors {
error: Color::Red,
warning: Color::Yellow,
@ -125,16 +125,6 @@ pub const COLORS: ThemeColors = ThemeColors {
accent: Color::White,
};
#[cfg(feature = "pretty")]
pub const COLORS: ThemeColors = ThemeColors {
error: Color::CustomRed,
warning: Color::CustomYellow,
exception: Color::CustomMagenta,
gutter: Color::CustomCyan,
hint: Color::CustomGreen,
accent: Color::CustomGray,
};
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct Characters {
hat: char, // error
@ -524,9 +514,6 @@ mod tests {
println!("{BLUE}Hello{RESET}, {GREEN}World{RESET}");
println!("{MAGENTA}Hello{RESET}, {BLACK}World{RESET}");
println!("{GRAY}Hello{RESET}, {WHITE}World{RESET}");
println!("{CUSTOM_BLUE}Hello{RESET}, {CUSTOM_CYAN}World{RESET}");
println!("{CUSTOM_GRAY}Hello{RESET}, {CUSTOM_GREEN}World{RESET}");
println!("{CUSTOM_MAGENTA}Hello{RESET}, {CUSTOM_RED}World{RESET}");
}
#[test]

View file

@ -46,6 +46,18 @@ use crate::ty::{HasType, Type, TypeCode, TypePair};
use erg_common::fresh::fresh_varname;
use AccessKind::*;
#[allow(dead_code)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum ControlKind {
If,
While,
For,
Match,
With,
Discard,
Assert,
}
/// patch method -> function
/// patch attr -> variable
fn debind(ident: &Identifier) -> Option<Str> {
@ -1604,6 +1616,21 @@ impl PyCodeGenerator {
self.emit_load_const(ValueObj::None);
}
fn deopt_instr(&mut self, kind: ControlKind, args: Args) {
if !self.control_loaded {
self.load_control();
}
let local = match kind {
ControlKind::If => Identifier::public("if__"),
ControlKind::For => Identifier::public("for__"),
ControlKind::While => Identifier::public("while__"),
ControlKind::With => Identifier::public("with__"),
ControlKind::Discard => Identifier::public("discard__"),
kind => todo!("{kind:?}"),
};
self.emit_call_local(local, args);
}
fn emit_if_instr(&mut self, mut args: Args) {
log!(info "entered {}", fn_name!());
let init_stack_len = self.stack_len();
@ -1670,6 +1697,9 @@ impl PyCodeGenerator {
fn emit_for_instr(&mut self, mut args: Args) {
log!(info "entered {} ({})", fn_name!(), args);
if !matches!(args.get(1).unwrap(), Expr::Lambda(_)) {
return self.deopt_instr(ControlKind::For, args);
}
let _init_stack_len = self.stack_len();
let iterable = args.remove(0);
self.emit_expr(iterable);
@ -1716,6 +1746,9 @@ impl PyCodeGenerator {
fn emit_while_instr(&mut self, mut args: Args) {
log!(info "entered {} ({})", fn_name!(), args);
if !matches!(args.get(1).unwrap(), Expr::Lambda(_)) {
return self.deopt_instr(ControlKind::While, args);
}
let _init_stack_len = self.stack_len();
// e.g. is_foo!: () => Bool, do!(is_bar)
let cond_block = args.remove(0);
@ -2008,9 +2041,11 @@ impl PyCodeGenerator {
}
}
fn emit_with_instr_311(&mut self, args: Args) {
fn emit_with_instr_311(&mut self, mut args: Args) {
log!(info "entered {}", fn_name!());
let mut args = args;
if !matches!(args.get(1).unwrap(), Expr::Lambda(_)) {
return self.deopt_instr(ControlKind::With, args);
}
let expr = args.remove(0);
let lambda = enum_unwrap!(args.remove(0), Expr::Lambda);
let params = self.gen_param_names(&lambda.params);
@ -2054,9 +2089,11 @@ impl PyCodeGenerator {
self.emit_load_name_instr(stash);
}
fn emit_with_instr_310(&mut self, args: Args) {
fn emit_with_instr_310(&mut self, mut args: Args) {
log!(info "entered {}", fn_name!());
let mut args = args;
if !matches!(args.get(1).unwrap(), Expr::Lambda(_)) {
return self.deopt_instr(ControlKind::With, args);
}
let expr = args.remove(0);
let lambda = enum_unwrap!(args.remove(0), Expr::Lambda);
let params = self.gen_param_names(&lambda.params);
@ -2105,9 +2142,11 @@ impl PyCodeGenerator {
self.emit_load_name_instr(stash);
}
fn emit_with_instr_308(&mut self, args: Args) {
fn emit_with_instr_308(&mut self, mut args: Args) {
log!(info "entered {}", fn_name!());
let mut args = args;
if !matches!(args.get(1).unwrap(), Expr::Lambda(_)) {
return self.deopt_instr(ControlKind::With, args);
}
let expr = args.remove(0);
let lambda = enum_unwrap!(args.remove(0), Expr::Lambda);
let params = self.gen_param_names(&lambda.params);

View file

@ -2,6 +2,7 @@
use std::option::Option; // conflicting to Type::Option
use erg_common::error::{Location, MultiErrorDisplay};
use erg_common::style::colors::DEBUG_ERROR;
use crate::ty::constructors::{and, not, or, poly};
use crate::ty::free::{Constraint, FreeKind};
@ -131,7 +132,7 @@ impl Context {
|| self.nominal_supertype_of(lhs, rhs)
}
};
log!("answer: {lhs} {RED}:>{RESET} {rhs} == {res}");
log!("answer: {lhs} {DEBUG_ERROR}:>{RESET} {rhs} == {res}");
res
}

View file

@ -113,7 +113,7 @@ impl Context {
None,
Bool,
);
let I = mono_q(KW_I, subtypeof(poly(KW_ITERABLE, vec![ty_tp(T.clone())])));
let I = mono_q(TY_I, subtypeof(poly(ITERABLE, vec![ty_tp(T.clone())])));
let t_iter = nd_func(vec![kw(KW_OBJECT, I.clone())], None, proj(I, ITERATOR)).quantify();
let t_len = nd_func(
vec![kw(KW_S, poly(SEQ, vec![TyParam::erased(Type)]))],

View file

@ -0,0 +1,31 @@
.abspath: (path: PathLike) -> Str
.basename: (path: PathLike) -> Str
.commonpath: (paths: Iterable PathLike) -> Str
.commonprefix: (list: [PathLike; _]) -> Str
.dirname: (path: PathLike) -> Str
.exists!: (path: PathLike) => Bool
.lexists!: (path: PathLike) => Bool
.expanduser!: (path: PathLike) => Str
.expandvars!: (path: PathLike) => Str
.getatime!: (path: PathLike) => Float
.getmtime!: (path: PathLike) => Float
.getctime!: (path: PathLike) => Float
.getsize!: (path: PathLike) => Int
.isabs: (path: PathLike) -> Bool
.isfile!: (path: PathLike) => Bool
.isdir!: (path: PathLike) => Bool
.islink!: (path: PathLike) => Bool
.ismount!: (path: PathLike) => Bool
.join: (path: PathLike, *paths: PathLike) -> Str
.normcase: (path: PathLike) -> Str
.normpath: (path: PathLike) -> Str
.realpath!: (path: PathLike, strict := Bool) => Str
.relpath: (path: PathLike, start := PathLike) -> Str
.samefile!: (path1: PathLike, path2: PathLike) => Bool
.sameopenfile!: (fp1: File! or PathLike, fp2: File! or PathLike) => Bool
.split: (path: PathLike) -> (Str, Str)
.splitdrive: (path: PathLike) -> (Str, Str)
.splitext: (path: PathLike) -> (Str, Str)
.supports_unicode_filenames: Bool

View file

@ -0,0 +1,31 @@
.abspath: (path: PathLike) -> Str
.basename: (p: PathLike) -> Str
.commonpath: (paths: Iterable PathLike) -> Str
.commonprefix: (list: [PathLike; _]) -> Str
.dirname: (p: PathLike) -> Str
.exists!: (path: PathLike) => Bool
.lexists!: (path: PathLike) => Bool
.expanduser!: (path: PathLike) => Str
.expandvars!: (path: PathLike) => Str
.getatime!: (path: PathLike) => Float
.getmtime!: (path: PathLike) => Float
.getctime!: (path: PathLike) => Float
.getsize!: (path: PathLike) => Int
.isabs: (s: PathLike) -> Bool
.isfile!: (path: PathLike) => Bool
.isdir!: (path: PathLike) => Bool
.islink!: (path: PathLike) => Bool
.ismount!: (path: PathLike) => Bool
.join: (a: PathLike, *p: PathLike) -> Str
.normcase: (path: PathLike) -> Str
.normpath: (s: PathLike) -> Str
.realpath!: (path: PathLike, strict := Bool) => Str
.relpath: (path: PathLike, start := PathLike or NoneType) -> Str
.samefile!: (path1: PathLike, path2: PathLike) => Bool
.sameopenfile!: (fp1: File! or PathLike, fp2: File! or PathLike) => Bool
.split: (p: PathLike) -> (Str, Str)
.splitdrive: (p: PathLike) -> (Str, Str)
.splitext: (p: PathLike) -> (Str, Str)
.supports_unicode_filenames: Bool

View file

@ -4,6 +4,7 @@ use erg_common::config::ErgConfig;
use erg_common::dict::Dict;
use erg_common::error::Location;
use erg_common::set::Set;
use erg_common::style::colors::DEBUG_MAIN;
use erg_common::traits::{Locational, Stream};
use erg_common::vis::Visibility;
use erg_common::Str;
@ -78,7 +79,7 @@ impl OwnershipChecker {
self.check_expr(chunk, Ownership::Owned, true);
}
log!(
"{GREEN}[DEBUG] the ownership checking process has completed, found errors: {}{RESET}",
"{DEBUG_MAIN}[DEBUG] the ownership checking process has completed, found errors: {}{RESET}",
self.errs.len()
);
if self.errs.is_empty() {

View file

@ -33,7 +33,7 @@ macro_rules! debug_call_info {
($self: ident) => {
$self.level += 1;
log!(
c GREEN,
c DEBUG_MAIN,
"\n{} ({}) entered {}, cur: {}",
"".repeat(($self.level as f32 / 4.0).floor() as usize),
$self.level,
@ -48,7 +48,7 @@ macro_rules! debug_exit_info {
($self: ident) => {
$self.level -= 1;
log!(
c GREEN,
c DEBUG_MAIN,
"\n{} ({}) exit {}, cur: {}",
"".repeat(($self.level as f32 / 4.0).floor() as usize),
$self.level,
@ -228,7 +228,7 @@ impl Parser {
pub(crate) fn stack_dec(&mut self, fn_name: &str) {
self.level -= 1;
log!(
c GREEN,
c DEBUG_MAIN,
"\n{} ({}) exit {}, cur: {}",
"".repeat((self.level as f32 / 4.0).floor() as usize),
self.level,

View file

@ -6,7 +6,7 @@
## ドキュメント
Erg への貢献を考えている場合は、`doc/*/dev_guide` にあるドキュメントを読む必要があります。特に`env.md`に書かれているものを事前にインストールしてください。
Erg への貢献を考えている場合は、`doc/*/dev_guide` にあるドキュメントを読む必要があります。特に[`env.md`](../JA/dev_guide/env.md)に書かれているものを事前にインストールしてください。
Erg の内部構造に興味がある場合は、`doc/*/compiler` が役に立つかもしれません。
@ -22,11 +22,11 @@ Ergのバグだと思われる動作を見つけた場合は、[報告](https://
私たちは常に、ドキュメントをさまざまな言語バージョンに翻訳してくれる人を探しています。
ドキュメントが他の言語に比べて古くなっていることに気づき、内容を更新したいという方も歓迎します ([こちら](https://github.com/erg-lang/erg/issues/48#issuecomment-1218247362) を参照)。これを行う方法について)。
ドキュメントが他の言語に比べて古くなっていることに気づき、内容を更新したいという方も歓迎します (これを行う方法については[こちら](https://github.com/erg-lang/erg/issues/48#issuecomment-1218247362) を参照)。
## 質問する
ご不明な点がございましたら、[Discord チャンネル](https://discord.gg/zfAAUbgGr4)でお気軽にお問い合わせください。
ご不明な点がございましたら、[Discord チャンネル](https://discord.gg/zfAAUbgGr4)でお気軽にお問い合わせください。
## 開発・実装に関して

View file

@ -1,6 +1,8 @@
# Architecture of `ergc`
## 1. Scan an Erg script (.er) and generate a `TokenStream` (parser/lex.rs)
## 1. Scan an Erg script (.er) and generate a `TokenStream`
src: [erg_parser\lex.rs](../../../crates/erg_parser/lex.rs)
* parser/lexer/Lexer generates `TokenStream` (this is an iterator of `Token`, `TokenStream` can be generated by `Lexer::collect()`)
* `Lexer` is constructed from `Lexer::new` or `Lexer::from_str`, where `Lexer::new` reads the code from a file or command option.
@ -9,21 +11,42 @@
* `LexerRunner` can also be used if you want to use `Lexer` as standalone; `Lexer` is just an iterator and does not implement the `Runnable` trait.
* `Runnable` is implemented by `LexerRunner`, `ParserRunner`, `Compiler`, and `DummyVM`.
## 2. Convert `TokenStream` -> `AST` (parser/parse.rs)
## 2. Convert `TokenStream` -> `AST`
src: [erg_parser\parse.rs](../../../crates/erg_parser/parse.rs)
* `Parser`, like `Lexer`, has two constructors, `Parser::new` and `Parser::from_str`, and `Parser::parse` will give the `AST`.
* `AST` is the wrapper type of `Vec<Expr>`. It is for "Abstract Syntax Tree".
### 2.1 Desugaring `AST`
src: [erg_parser/desugar.rs](../../../crates/erg_parser/desugar.rs)
* expand nested vars (`Desugarer::desugar_nest_vars_pattern`)
* desugar multiple pattern definition syntax (`Desugarer::desugar_multiple_pattern_def`)
### 2.2 Reordering & Linking `AST`
* Sort variables according to dependencies and link class methods to class definitions (`Linker::link`)
src: [erg_compiler/reorder.rs](../../../crates/erg_compiler/reorder.rs)
## 3. Type checking & inference, Convert `AST` -> `HIR` (compiler/lower.rs)
* link class methods to class definitions
* method definitions are allowed outside of the class definition file
* current implementation is incomplete, only in the same file
## 3. Convert `AST` -> `HIR`
(main) src: [erg_compiler/lower.rs](../../../crates/erg_compiler/lower.rs)
## 3.1 Name Resolution
In the current implementation it is done during type checking.
* All ASTs (including imported modules) are scanned for name resolution before type inference.
* In addition to performing constant cycle checking and reordering, a context is created for type inference (however, most of the information on variables registered in this context is not yet finalized).
### 3.2 Type checking & inference
src: [erg_compiler/lower.rs](../../../crates/erg_compiler/lower.rs)
* `HIR` has every variable's type information. It is for "High-level Intermediate Representation".
* `ASTLowerer` can be constructed in the same way as `Parser` and `Lexer`.
@ -31,19 +54,28 @@
* `ASTLowerer` is owned by `Compiler`. Unlike conventional structures, `ASTLowerer` handles code contexts and is not a one-time disposable.
* If the result of type inference is incomplete (if there is an unknown type variable), an error will occur during name resolution.
## 4. Check side-effects (compiler/effectcheck.rs)
## 4. Check side-effects
## 4. Check ownerships (compiler/memcheck.rs)
src: [erg_compiler/effectcheck.rs](../../../crates/erg_compiler/effectcheck.rs)
## 5. Desugar `HIR` (compiler/desugar_hir.rs)
## 5. Check ownerships
src: [erg_compiler/ownercheck.rs](../../../crates/erg_compiler/ownercheck.rs)
## 6. Desugar `HIR`
src: [erg_compiler/desugar_hir.rs](../../../crates/erg_compiler/desugar_hir.rs)
Convert parts that are not consistent with Python syntax
* Convert class member variables to functions
## 6. Generate Bytecode (`CodeObj`) from `HIR` (compiler/codegen.rs)
## 7. Link
## (7. (Future plans) Convert Bytecode -> LLVM IR)
src: [erg_compiler/link.rs](../../../crates/erg_compiler/link.rs)
* Bytecode is stack-based, whereas LLVM IR is register-based.
There will be several more layers of intermediate processes for this conversion process.
* Load all modules, resolve dependencies, and combine into a single HIR
## 8. Generate Bytecode (`CodeObj`) from `HIR`
src: [erg_compiler/codegen.rs](../../../crates/erg_compiler/codegen.rs)

View file

@ -36,3 +36,7 @@ Increase the thread stack size. Used for Windows execution and test execution.
`--language-server` option becomes available.
`erg --language-server` will start the Erg language server.
## py_compatible
Enable Python-compatible mode, which makes parts of the APIs and syntax compatible with Python. Used for [pylyzer](https://github.com/mtshiba/pylyzer).

View file

@ -7,6 +7,8 @@ Any document that does not follow the rules below is subject to correction.
* Always include definitions, meanings, or links to terms that appear for the first time in the document.
* Use parentheses as a proviso only for sentences that are supplementary but necessary for understanding the main text, and use footnotes for sentences that are not essential for understanding the main text[<sup id="f1">1</ sup>](#1).
* If the content of the document is outdated, update it according to [this method](https://github.com/erg-lang/erg/issues/48#issuecomment-1218247362).
* Files under `syntax` should have sequential numbers at the beginning of their file names, except for those not included in the document.
* Scripts that automatically insert and replace files exist in doc/script.
---

View file

@ -12,7 +12,9 @@
We use pre-commit to have clippy check and test automatically.
The checks may fail on the first run even if there are no bugs, in which case you should try committing again.
* Python3 interpreter
* Python3 interpreter (3.7~3.11)
If you want to check the behavior of Erg in various versions, it is recommended to install such as [pyenv](https://github.com/pyenv/pyenv).
## Recommendation

View file

@ -112,8 +112,8 @@ C = Class {x = Int}
.method self = ...
```
You can specify the language of the document by writing the language code immediately after the `'''`. The [Erg Language Server](https://github.com/erg-lang/erg/tree/main/compiler/els) will then display documents in the Markdown format for each language version (The default language is English).
See [here](https://github.com/erg-lang/erg/blob/main/doc/JA/dev_guide/i18n_messages.md) for registered language codes.
You can specify the language of the document by writing the language code immediately after the `'''`. The [Erg Language Server](https://github.com/erg-lang/erg/tree/main/crates/els) will then display documents in the Markdown format for each language version (The default language is English).
See [here](https://github.com/erg-lang/erg/blob/main/doc/EN/dev_guide/i18n_messages.md) for registered language codes.
```python
'''

View file

@ -76,25 +76,25 @@ Each of these literals has its own documentation describing them separately, so
[], [1], [1, 2, 3], ["1", "2",], ...
```
### [Tuple Literal](./11_tuple.md)
### [Tuple Literal](./13_tuple.md)
```python
(), (1, 2, 3), (1, "hello", True), ...
```
### [Dict Literal](./12_dict.md)
### [Dict Literal](./11_dict.md)
```python
{:}, {"one": 1}, {"one": 1, "two": 2}, {"1": 1, "2": 2}, {1: "1", 2: True, "three": [1]}, ...
```
### [Record Literal](./13_record.md)
### [Record Literal](./14_record.md)
```python
{=}, {one = 1}, {one = 1; two = 2}, {.name = "John"; .age = 12}, {.name = Str; .age = Nat}, ...
```
### [Set Literal](./14_set.md)
### [Set Literal](./15_set.md)
```python
{}, {1}, {1, 2, 3}, {"1", "2", "1"}, ...

View file

@ -98,11 +98,11 @@ The above code prints `π` when `x` is `3.141592653589793`. If `x` is changed to
Some objects cannot be bound as constants. Mutable objects, for example. Mutable objects are objects whose states can be changed, as described in detail later.
This is because of the rule that only constant expressions can be assigned to constants. Constant expressions are also discussed later.
```python,compile_fail
```python
X = 1 # OK
```
```python
```python,compile_fail
X = !1 # TypeError: cannot define Int! object as a constant
```

View file

@ -28,7 +28,7 @@ C!.
x
```
Procedural methods can also take [ownership](./18_ownership.md) of `self`. Remove `ref` or `ref!` from the method definition.
Procedural methods can also take [ownership](./19_ownership.md) of `self`. Remove `ref` or `ref!` from the method definition.
```python,compile_fail
n = 1

View file

@ -18,7 +18,7 @@ The difference from JavaScript object literals is that they are not accessible a
This is because access to the value is determined at compile-time, and because dictionaries and records are different things. In other words, `{"name": "John"}` is a Dict and `{name = "John"}` is a record.
So how should we use dictionaries and records?
In general, we recommend using records. Records have the advantages of being checked at compile-time for the existence of elements and of being able to specify __visibility_.
Specifying visibility is equivalent to specifying public/private in Java and other languages. For details, see [visibility](./19_visibility.md) for details.
Specifying visibility is equivalent to specifying public/private in Java and other languages. For details, see [visibility](./20_visibility.md) for details.
```python,compile_fail
a = {x = 1; .y = x + 1}
@ -53,7 +53,7 @@ assert o.i == 1
```
There is a notable syntax with respect to records. When all the attribute values of a record are classes (not structural types), the record itself behaves as a type with its own attributes as required attributes.
Such a type is called a record type. See the section [Record] for more details.
Such a type is called a record type. See the section [Record](../API/types/classes/Record.md) for more details.
```python
# record

View file

@ -8,15 +8,15 @@ Also, see [here](../terms.md) for terminology.
* ! → [side&nbsp;effect](./07_side_effect.md)
* !-type → [mutable&nbsp;type](./type/18_mut.md)
* ? → [error&nbsp;handling](./30_error_handling.md)
* &#35; → [Str](./00_basic.md/#comment)
* ? → [error&nbsp;handling](./31_error_handling.md)
* &#35; → [Str](./00_basic.md/#comments)
* $ → [shared](./type/advanced/shared.md)
* %
* &
* &&
* [&prime;&nbsp;(single&nbsp;quote)](./20_naming_rule.md#literal-identifiers)
* [&prime;&nbsp;(single&nbsp;quote)](./21_naming_rule.md#literal-identifiers)
* [&quot;&nbsp;(double&nbsp;quote)](./01_literal.md#str-literal)
* &lpar;&rpar; → [Tuple](./11_tuple.md)
* &lpar;&rpar; → [Tuple](./13_tuple.md)
* &ast;
* &ast; → [*-less&nbsp;multiplication](./01_literal.md/#less-multiplication)
* &plus; (prefix) → [operator](./06_operator.md)
@ -28,19 +28,19 @@ Also, see [here](../terms.md) for terminology.
* &minus;_ → &minus; (prefix)
* &minus; (infix) → [operator](./06_operator.md)
* &minus; (infix) → [Trait](./type/03_trait.md)
* &minus;> → [anonymous&nbsp;function](./21_lambda.md)
* . → [Visibility](./19_visibility.md)
* &minus;> → [anonymous&nbsp;function](./22_lambda.md)
* . → [Visibility](./20_visibility.md)
* .. → [closed range operator](./01_literal.md/#range-object)
* ..< → [right-open range operator](./01_literal.md/#range-object)
* ...
* ... → [Extract&nbsp;assignment](./28_spread_syntax.md#extract-assignment)
* ... → [Extract&nbsp;assignment](./29_spread_syntax.md#extract-assignment)
* ... → [Variable-length arguments](./04_function.md#variable-length-arguments)
* /
* :
* : → [Colon&nbsp;application&nbsp;style](./04_function.md)
* : → [Type ascription](./03_declaration.md.md)
* : → [Type ascription](./03_declaration.md)
* : → [Keyword&nbsp;arguments](./04_function.md)
* :: → [private variable modifier](./19_visibility.md)
* :: → [private variable modifier](./20_visibility.md)
* := → [default&nbsp;parameters](./04_function.md)
* ;
* &lt;
@ -49,13 +49,13 @@ Also, see [here](../terms.md) for terminology.
* &lt;=
* &lt;.. → [left-open range operator](./01_literal.md/#range-object)
* &lt;..&lt; → [open range operator](./01_literal.md/#range-object)
* = → [Variable](./19_visibility.md)
* = → [Variable](./20_visibility.md)
* ==
* => → [anonymous procedure operator](./08_procedure.md)
* &gt;
* &gt;&gt;
* &gt;=
* @ → [decorator](./29_decorator.md)
* @ → [decorator](./30_decorator.md)
* [] → [Array](./10_array.md)
* \ → [Escaping](./00_basic.md)
* ^
@ -63,11 +63,11 @@ Also, see [here](../terms.md) for terminology.
* _ → [Type&nbsp;erasure](./type/advanced/erasure.md)
* &#95;+&#95;&plus; (infix)
* &#95;-&#95;&minus; (infix)
* [``&nbsp;(back&nbsp;quote)](./22_subroutine.md#operator)
* [``&nbsp;(back&nbsp;quote)](./23_subroutine.md#operator)
* {}
* [{} type](./type/01_type_system.md)
* {=} → [Type&nbsp;System](./type/01_type_system.md#classification)
* [{=}&nbsp;type](./13_record.md#empty-record)
* [{=}&nbsp;type](./14_record.md#empty-record)
* |
* || → [Type variable list](./type/advanced/)
* ~
@ -83,11 +83,11 @@ Also, see [here](../terms.md) for terminology.
* [algebraic&nbsp;type](./type/13_algebraic.md)
* [And]
* [and]
* [anonymous&nbsp;function](./21_lambda.md)
* [anonymous&nbsp;function](./22_lambda.md)
* anonymous type → [Type&nbsp;system](./type/01_type_system.md)
* [Array](./10_array.md)
* [assert]
* [Attach](./29_decorator.md#attach)
* assert
* [Attach](./30_decorator.md#attach)
* [attribute](type/09_attributive.md)
* [Attribute&nbsp;definitions](./type/02_basic.md#attribute-definitions)
* [Attribute&nbsp;type](./type/09_attributive.md)
@ -96,7 +96,7 @@ Also, see [here](../terms.md) for terminology.
* [Bool, Boolean](./01_literal.md#boolean-object)
* [Boolean&nbsp;object](./01_literal.md#boolean-object)
* [borrowing](./18_ownership.md#borrow)
* [borrowing](./19_ownership.md#borrow)
### C
@ -104,43 +104,43 @@ Also, see [here](../terms.md) for terminology.
* [Comments](./00_basic.md#comments)
* [Complex&nbsp;object](./01_literal.md#complex-object)
* [Compile-time&nbsp;functions](./04_function.md#compile-time-functions)
* [circular&nbsp;references](./18_ownership.md#circular-references)
* [circular&nbsp;references](./19_ownership.md#circular-references)
* [Class](./type/04_class.md)
* [Class&nbsp;relationship](./type/04_class.md#class-relationships)
* [Class&nbsp;upcasting](./type/16_subtyping.md#class-upcasting)
* [Colon&nbsp;application&nbsp;style](./04_function.md#colon-application-style)
* [Closure](./23_closure.md)
* [Closure](./24_closure.md)
* [Compound literals](./01_literal.md#compound-literals)
* [Complement](./type/13_algebraic.md#complement)
* [Comprehension](./27_comprehension.md)
* [constant](./17_mutability.md#constant)
* [Comprehension](./28_comprehension.md)
* [constant](./18_mutability.md#constant)
* [Constants](./02_name.md#constants)
* [Context](./30_error_handling.md#context)
* [Context](./31_error_handling.md#context)
### D
* [Data&nbsp;type](./type/01_type_system.md#data-type)
* [Declaration](./03_declaration.md)
* [decorator](./29_decorator.md)
* [decorator](./30_decorator.md)
* [Default&nbsp;parameters](./04_function.md#default-parameters)
* [Del](./02_name.md#delete-an-variable)
* [Dependent&nbsp;type](./type/14_dependent.md)
* Deprecated
* [Dict](./12_dict.md)
* [Dict](./11_dict.md)
* [Diff](./type/13_algebraic.md#diff)
* distinct
* [Downcasting](./type/17_type_casting.md#downcasting)
### E
* [Empty&nbsp;record](./13_record.md#empty-record)
* [Empty&nbsp;record](./14_record.md#empty-record)
* [Enum&nbsp;class](./type/04_class.md#enum-class)
* [Enum&nbsp;type](./type/11_enum.md)
* [Enumerated,&nbsp;Interval&nbsp;and&nbsp;Refinement&nbsp;types](./type/12_refinement.md#enumerated-interval-and-refinement-types)
* [error&nbsp;handling](./30_error_handling.md)
* [error&nbsp;handling](./31_error_handling.md)
* [Existential&nbsp;type](./type/advanced/existential.md)
* [Exponential&nbsp;literal](./01_literal.md#exponential-literal)
* [Extract&nbsp;assignment](./28_spread_syntax.md#extract-assignment)
* [Extract&nbsp;assignment](./29_spread_syntax.md#extract-assignment)
### F
@ -148,14 +148,14 @@ Also, see [here](../terms.md) for terminology.
* [Float&nbsp;object](./01_literal.md#float-object)
* [for](./05_builtin_funcs.md#for)
* [For-All&nbsp;patch](./type/07_patch.md#for-all-patch)
* [freeze](./18_ownership.md#freeze)
* [freeze](./19_ownership.md#freeze)
* [Function](./04_function.md)
* [Function&nbsp;definition&nbsp;with&nbsp;multiple patterns](./04_function.md#function-definition-with-multiple-patterns)
### G
* [GADTs(Generalized&nbsp;Algebraic&nbsp;Data&nbsp;Types)](./type/advanced/GADTs.md)
* [Generator](./34_generator.md)
* [Generator](./35_generator.md)
* [Glue&nbsp;Patch](./type/07_patch.md#glue-patch)
### H
@ -166,19 +166,19 @@ Also, see [here](../terms.md) for terminology.
* [id](./09_builtin_procs.md#id)
* [if](./05_builtin_funcs.md#if)
* [import](./33_package_system.md)
* [impl](./29_decorator.md#impl)
* [in]
* [import](./34_package_system.md)
* [impl](./30_decorator.md#impl)
* in
* [Indention](./00_basic.md#indentation)
* [Instant&nbsp;block](./13_record.md#instant-block)
* [Instant&nbsp;block](./14_record.md#instant-block)
* [Instance/class&nbsp;attributes](./type/04_class.md#instance-and-class-attributes)
* [inheritable](./29_decorator.md#inheritable)
* [inheritable](./30_decorator.md#inheritable)
* [inheritance](./type/05_inheritance.md)
* [Int](./01_literal.md)
* [Integration&nbsp;with&nbsp;Python](./32_integration_with_Python.md)
* [Integration&nbsp;with&nbsp;Python](./33_integration_with_Python.md)
* [Interval&nbsp;Type](./type/10_interval.md)
* [Intersection](./type/13_algebraic.md#intersection)
* [Iterator](./16_iterator.md)
* [Iterator](./17_iterator.md)
### J
@ -189,59 +189,59 @@ Also, see [here](../terms.md) for terminology.
### L
* lambda → [anonymous&nbsp;function](./21_lambda.md)
* lambda → [anonymous&nbsp;function](./22_lambda.md)
* let-polymorphism → [rank&nbsp;1&nbsp;polymorphism]
* [Literal&nbsp;Identifiers](./20_naming_rule.md#literal-identifiers)
* [Literal&nbsp;Identifiers](./21_naming_rule.md#literal-identifiers)
### M
* [match]
* match
* [Marker&nbsp;trait](./type/advanced/marker_trait.md)
* [Method](./07_side_effect.md#methods)
* Modifier → [decorator](./29_decorator.md)
* [module](./24_module.md)
* Modifier → [decorator](./30_decorator.md)
* [module](./25_module.md)
* [Multiple&nbsp;inheritance](type/05_inheritance.md#multiple-inheritance)
* [Multi-layer&nbsp;(multi-level)&nbsp;Inheritance](type/05_inheritance.md#multi-layer-multi-level-inheritance)
* [Mutable&nbsp;type](./type/18_mut.md)
* [Mutable&nbsp;structure&nbsp;type](./type/advanced/mut_struct.md)
* [Mutability](./17_mutability.md)
* [Mutability](./18_mutability.md)
### N
* [Nat](./01_literal.md#int-literal)
* [Never]
* Never
* [New&nbsp;type](./type/advanced/newtype.md)
* [Heterogeneous&nbsp;Dict](./12_dict.md#heterogeneous-dict)
* [Heterogeneous&nbsp;Dict](./11_dict.md#heterogeneous-dict)
* None → [None&nbsp;Object]
* [None&nbsp;Object]
* None&nbsp;Object
* Nominal&nbsp;Subtyping → [Class](./type/04_class.md)
* [Not]
* [not]
* Not
* not
### O
* [Object](./25_object_system.md)
* [Object](./26_object_system.md)
* [Option]
* [Or]
* [or]
* [Ord]
* [ownership&nbsp;system](./18_ownership.md)
* [ownership&nbsp;system](./19_ownership.md)
* [Overloading](./type/advanced/overloading.md)
* [Overriding](./type/05_inheritance.md#overriding)
* [Override&nbsp;in&nbsp;trait](./type/03_trait.md#override-in-trait)
### P
* [Panic](./30_error_handling.md#panic)
* [Panic](./31_error_handling.md#panic)
* [Patch](./type/07_patch.md)
* [Pattern&nbsp;match](./26_pattern_matching.md)
* [Pattern&nbsp;match](./27_pattern_matching.md)
* [Phantom&nbsp;class](./type/advanced/phantom.md)
* [pipeline&nbsp;operator](./31_pipeline.md)
* [pipeline&nbsp;operator](./32_pipeline.md)
* [Predicate](./type/19_bound.md#predicate)
* [print!]
* print!
* [Procedures](./08_procedure.md)
* [Projection&nbsp;type](./type/advanced/projection.md)
* Python → [Integration&nbsp;with&nbsp;Python](./32_integration_with_Python.md)
* Python → [Integration&nbsp;with&nbsp;Python](./33_integration_with_Python.md)
### Q
@ -251,15 +251,15 @@ Also, see [here](../terms.md) for terminology.
### R
* [Range&nbsp;Object](./01_literal.md#range-object)
* [ref]
* [ref!]
* [Record](./13_record.md)
* ref
* ref!
* [Record](./14_record.md)
* [Recursive&nbsp;functions](./04_function.md#recursive-functions)
* [Refinement&nbsp;pattern](./type/12_refinement.md#refinement-pattern)
* [Refinement&nbsp;type](./type/12_refinement.md)
* [replication](./18_ownership.md#replication)
* [replication](./19_ownership.md#replication)
* [Replacing&nbsp;traits](./type/05_inheritance.md#replacing-traits-or-what-looks-like-it)
* Result → [error&nbsp;handling](./30_error_handling.md)
* Result → [error&nbsp;handling](./31_error_handling.md)
### S
@ -269,9 +269,9 @@ Also, see [here](../terms.md) for terminology.
* [Shared&nbsp;reference](./type/advanced/shared.md)
* [side-effect](./07_side_effect.md)
* [Smart&nbsp;cast](./type/12_refinement.md#smart-cast)
* [Spread&nbsp;assignment](./28_spread_syntax.md)
* [Spread&nbsp;assignment](./29_spread_syntax.md)
* [special&nbsp;type&nbsp;variables](./type/advanced/special.md#special-type-variables)
* [Stack&nbsp;trace](30_error_handling.md#stack-trace)
* [Stack&nbsp;trace](./31_error_handling.md#stack-trace)
* [Structure&nbsp;type](./type/01_type_system.md#structure-type-anonymous-type)
* [Structural&nbsp;patch](./type/07_patch.md#structural-patch)
* [Structural&nbsp;trait](./type/03_trait.md#structural-traits)
@ -282,17 +282,17 @@ Also, see [here](../terms.md) for terminology.
* [Subtyping&nbsp;of&nbsp;subroutines](./type/16_subtyping.md#subtyping-of-subroutines)
* [Subtype&nbsp;specification](./type/02_basic.md#subtype-specification)
* [Subtyping&nbsp;of&nbsp;polymorphic&nbsp;function types](./type/15_quantified.md#subtyping-of-polymorphic-function-types)
* [Subroutine&nbsp;signatures](./22_subroutine.md)
* [Subroutine&nbsp;signatures](./23_subroutine.md)
### T
* [Test](./29_decorator.md#test)
* [Test](./30_decorator.md#test)
* [Traits](./type/03_trait.md)
* [Trait&nbsp;inclusion](./type/03_trait.md#trait-inclusion)
* True → [Boolean&nbsp;object](./01_literal.md#boolean-object)
* [True&nbsp;algebraic&nbsp;type](./type/13_algebraic.md#true-algebraic-type)
* [Type]
* [type](./15_type.md)
* Type
* [type](./16_type.md)
* [Type&nbsp;arguments&nbsp;in&nbsp;method&nbsp;definitions](./type/15_quantified.md#type-arguments-in-method-definitions)
* [Type&nbsp;bound](./type/19_bound.md)
* [Type&nbsp;definitions](./type/01_type_system.md#type-definitions)
@ -301,12 +301,12 @@ Also, see [here](../terms.md) for terminology.
* [Type&nbsp;specification](./type/02_basic.md#type-specification)
* [Type&nbsp;system](./type/01_type_system.md)
* [Type&nbsp;widening](./type/advanced/widening.md)
* [Tuple](./11_tuple.md)
* [Tuple](./13_tuple.md)
### U
* [union](type/13_algebraic.md#union)
* [Unit](./11_tuple.md#unit)
* [Unit](./13_tuple.md#unit)
* [Upcasting](type/17_type_casting.md#upcasting)
### V
@ -317,7 +317,7 @@ Also, see [here](../terms.md) for terminology.
### W
* [while]
* while!
### X

View file

@ -2,7 +2,9 @@
[![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/compiler/architecture.md%26commit_hash%3Da711efa99b325ba1012f6897e7b0e2bdb947d8a1)](https://gezf7g7pd5.execute-api.ap-northeast-1.amazonaws.com/default/source_up_to_date?owner=erg-lang&repos=erg&ref=main&path=doc/EN/compiler/architecture.md&commit_hash=a711efa99b325ba1012f6897e7b0e2bdb947d8a1)
## 1. Erg スクリプト (.er) をスキャンし、`TokenStream` (parser/lex.rs) を生成する
## 1. Erg スクリプト (.er) をスキャンし、`TokenStream` を生成する
src: [erg_parser/lex.rs](../../../crates/erg_parser/lex.rs)
* parser/lexer/Lexer が `TokenStream` を生成する (これは `Token` のイテレータである。`TokenStream``Lexer::collect()` によって生成できる)
* [`Lexer`](./phases/01_lex.md) は `Lexer::new` または `Lexer::from_str` から構築される。`Lexer::new` はファイルまたはコマンド オプションからコードを読み取る。
@ -11,29 +13,43 @@
* `Lexer` を単体で使用する場合は、代わりに`LexerRunner` を使用します。`Lexer` は単なるイテレータであり、`Runnable` トレイトを実装していない。
* `Runnable` は、 `LexerRunner``ParserRunner``Compiler` 、および `DummyVM` に実装されている。
## 2. `TokenStream` -> `AST` (parser/parse.rs)
## 2. `TokenStream` -> `AST`
src: [erg_parser/parse.rs](../../../crates/erg_parser/parse.rs)
* [`Parser`](./phases/02_parse.md) は `Lexer` と同様に `Parser::new``Parser::from_str` の 2 つのコンストラクタを持ち、`Parser::parse``AST` を返す。
* `AST``Vec<Expr>`のラッパー型で、「抽象構文木」を表す。
### 2.1 `AST`の脱糖
src: [erg_parser/desugar.rs](../../../crates/erg_parser/desugar.rs)
* [`Desugarer`](./phases/03_desugar.md)
* パターンマッチを単一の変数代入列へ変換 (`Desugarer::desugar_nest_vars_pattern`)
* 複数パターン定義構文をmatchへ変換 (`Desugarer::desugar_multiple_pattern_def`)
### 2.2 `AST`の並び替え・結合
src: [erg_compiler/reorder.rs](../../../crates\erg_compiler\reorder.rs)
* クラスメソッドをクラス定義に結合する
* メソッド定義は定義ファイル外でも可能となっている
* 現在の実装は不完全、同一ファイル内のみ
## 3. `AST` -> `HIR`
(主要な)ソースコード: [erg_compiler/lower.rs](../../../compiler/erg_compiler/lower.rs)
(主要な)ソースコード: [erg_compiler/lower.rs](../../../crates/erg_compiler/lower.rs)
## 3.1 名前解決
現在の実装では型チェック中に行われる
* 型推論の前に全てのAST(importされたモジュール含む)を走査し、名前解決を行う
* 定数の循環検査や並び替えなどが行われるほか、型推論のためのContextが作成される(ただし、このContextに登録された変数の情報ははまだ殆どが未確定)
### 3.2 型チェックと推論
ソースコード: [erg_compiler/lower.rs](../../../compiler/erg_compiler/lower.rs)
ソースコード: [erg_compiler/lower.rs](../../../crates/erg_compiler/lower.rs)
* `HIR` は、すべての変数の型情報を持っており、「高レベルの中間表現」を表す。
* `ASTLowerer` は Parser や Lexer と同じように構築できる。
@ -43,23 +59,25 @@
## 4. 副作用のチェック
ソースコード: [erg_compiler/effectcheck.rs](../../../compiler/erg_compiler/effectcheck.rs)
ソースコード: [erg_compiler/effectcheck.rs](../../../crates/erg_compiler/effectcheck.rs)
## 4. 所有権の確認
## 5. 所有権の確認
ソースコード: [erg_compiler/ownercheck.rs](../../../compiler/erg_compiler/ownercheck.rs)
ソースコード: [erg_compiler/ownercheck.rs](../../../crates/erg_compiler/ownercheck.rs)
## 5. `HIR`の脱糖
## 6. `HIR`の脱糖
ソースコード: [erg_compiler/desugar_hir.rs](../../../compiler/erg_compiler/desugar_hir.rs)
ソースコード: [erg_compiler/desugar_hir.rs](../../../crates/erg_compiler/desugar_hir.rs)
* Pythonの文法と整合しない部分を変換する
* クラスのメンバ変数を関数に変換
## 6. リンク
## 7. リンク
ソースコード: [erg_compiler/link.rs](../../../crates/erg_compiler/link.rs)
* 全てのモジュールを読み込み、依存関係を解決し、単一のHIRに結合する
## 7. `HIR` からバイトコード (`CodeObj`) を生成
## 8. `HIR` からバイトコード (`CodeObj`) を生成
ソースコード: [erg_compiler/codegen.rs](../../../compiler/erg_compiler/codegen.rs)
ソースコード: [erg_compiler/codegen.rs](../../../crates/erg_compiler/codegen.rs)

View file

@ -38,3 +38,7 @@ Erg 内部オプション、ヘルプ (ヘルプ、著作権、ライセンス
`--language-server`オプションが利用可能になる。
`erg --language-server`でLanguage Serverが起動する。
## py_compatible
Python互換モードを有効にする。APIや文法の一部がPythonと互換になる。[pylyzer](https://github.com/mtshiba/pylyzer)のために使用される。

View file

@ -9,6 +9,8 @@
* ドキュメント内で初出の用語は、必ず定義や意味、またはリンクを併記する。
* ただし書きとしての()は、補助的ではあるものの本文の理解に必要な文の場合のみ使用し、本文の理解に必須でない文は脚注を使用する[<sup id="f1">1</sup>](#1)。
* ドキュメントの内容が古くなっていた場合は、[この方法](https://github.com/erg-lang/erg/issues/48#issuecomment-1218247362)に従って更新する。
* syntax以下のファイルは、ドキュメントに含めないものを除きファイル名の頭に連番を付ける。
* 挿入や入れ替えを自動で行うスクリプトがdoc/script内に存在する。
---

View file

@ -14,7 +14,9 @@
pre-commitを使ってclippyのチェックやテストを自動で行わせています。
バグがなくても最初の実行でチェックが失敗する場合があります。その場合はもう一度コミットを試みてください。
* Python3インタープリタ
* Python3インタープリタ (3.7~3.11)
様々なバージョンでErgの挙動を検査したい場合は [pyenv](https://github.com/pyenv/pyenv) 等の導入をお勧めします。
## 推奨

View file

@ -89,7 +89,7 @@ C = Class {x = Int}
.method self = ...
```
`'''`の直後に言語コードを記述することで、ドキュメントの言語を指定することが出来ます。すると[Erg Language Server](https://github.com/erg-lang/erg/tree/main/compiler/els)は各言語バージョンに合わせたドキュメントをMarkdown形式で表示します(デフォルトの言語は英語です)。
`'''`の直後に言語コードを記述することで、ドキュメントの言語を指定することが出来ます。すると[Erg Language Server](https://github.com/erg-lang/erg/tree/main/crates/els)は各言語バージョンに合わせたドキュメントをMarkdown形式で表示します(デフォルトの言語は英語です)。
登録されている言語コードについては[こちら](https://github.com/erg-lang/erg/blob/main/doc/JA/dev_guide/i18n_messages.md)を参照してください。
```python

View file

@ -82,25 +82,25 @@ assert 1e-10 == 0.0000000001
[], [1], [1, 2, 3], ["1", "2",], ...
```
### [組リテラル(Tuple Literal)](./11_tuple.md)
### [組リテラル(Tuple Literal)](./13_tuple.md)
```python
(), (1, 2, 3), (1, "hello", True), ...
```
### [辞書リテラル(Dict Literal)](./12_dict.md)
### [辞書リテラル(Dict Literal)](./11_dict.md)
```python
{:}, {"one": 1}, {"one": 1, "two": 2}, {"1": 1, "2": 2}, {1: "1", 2: True, "three": [1]}, ...
```
### [レコードリテラル(Record Literal)](./13_record.md)
### [レコードリテラル(Record Literal)](./14_record.md)
```python
{=}, {one = 1}, {one = 1; two = 2}, {.name = "John"; .age = 12}, {.name = Str; .age = Nat}, ...
```
### [集合リテラル(Set Literal)](./14_set.md)
### [集合リテラル(Set Literal)](./15_set.md)
```python
{}, {1}, {1, 2, 3}, {"1", "2", "1"}, ...

View file

@ -112,7 +112,7 @@ X = !1 # TypeError: cannot define Int! object as a constant
`Del`関数を使うことで、代数を削除することが出来ます。その代数に依存している(その代数の値を直接参照している)他の代数もまとめて削除されます。
```python
```python,compile_fail
x = 1
y = 2
z = 3

View file

@ -0,0 +1,23 @@
import os
import glob
"""
Align file prefixes when they are not numbered consecutively.
existing files: 01_foo.md, 03_bar.md, 04_baz.md
result: 01_foo.md, 02_bar.md, 03_baz.md
"""
if __name__ == '__main__':
prev = None
diff = None
for f in sorted(glob.glob("[0-9][0-9]_*")):
if prev != None:
now_file_no = int(f.split("_")[0])
diff = now_file_no - prev
if diff != 1:
replace_to = "_".join([f"{now_file_no-diff+1:02d}", *f.split("_")[1:]])
os.rename(f, replace_to)
prev = now_file_no - diff + 1
else:
prev = now_file_no
else:
prev = int(f.split("_")[0])

View file

@ -0,0 +1,43 @@
import os
import sys
import glob
"""
Insert a file into files followed by a sequential number. Existing files are shifted by one.
example:
existing files: 01_foo.md, 02_bar.md, 03_baz.md
1st arg(inserting file): qux.md
2nd arg(file no): 2
result: 01_foo.md, 02_qux.md, 03_bar.md, 04_baz.md
"""
if __name__ == '__main__':
file = sys.argv[1]
file_no = sys.argv[2]
if not file_no.isdigit():
raise ValueError('File number must be a number')
else:
file_no = int(file_no)
if len(glob.glob("_[0-9][0-9]_*")) > 0:
raise Exception("Escaped file already exists, rename it")
# escaping
for esc in sorted(glob.glob("[0-9][0-9]_*")):
if int(esc.split("_")[0]) < file_no: continue
else: os.rename(esc, "_" + esc)
target = f"{file_no:02d}_" + file
if os.path.exists(target):
raise OSError(f"File {target} already exists")
os.rename(file, target)
while True:
nxt = glob.glob(f"_{file_no:02d}_*")
if len(nxt) == 0:
exit(0)
elif len(nxt) >= 2:
raise ValueError("More than one file with the same number")
else:
target = nxt[0]
replace_to = "_".join([f"{file_no+1:02d}", *target.split("_")[2:]])
os.rename(target, replace_to)
file_no += 1

View file

@ -108,7 +108,7 @@ C = Class {x = Int}
```
您可以通过在`'''`之后立即写入语言代码来指定文档的语言。然后,[Erg语言服务器](https://github.com/erg-lang/erg/tree/main/compiler/els)将以Markdown格式显示每种语言版本的文档(默认语言为英语)。
参见[这里](https://github.com/erg-lang/erg/blob/main/doc/JA/dev_guide/i18n_messages.md)获取多语言相关文档
参见[这里](https://github.com/erg-lang/erg/blob/main/doc/zh_CN/dev_guide/i18n_messages.md)获取多语言相关文档
```python
'''

View file

@ -78,25 +78,25 @@ assert 1e-10 == 0.0000000001
[], [1], [1, 2, 3], ["1", "2",], [1, "1", True, [1]], ...
```
### [元组字面量](./11_tuple.md)
### [元组字面量](./13_tuple.md)
```python
(), (1, 2, 3), (1, "hello", True), ...
```
### [字典字面量](./12_dict.md)
### [字典字面量](./11_dict.md)
```python
{:}, {"one": 1}, {"one": 1, "two": 2}, {"1": 1, "2": 2}, {1: "1", 2: True, "three": [1]}, ...
```
### [Record 字面量](./13_record.md)
### [Record 字面量](./14_record.md)
```python
{=}, {one = 1}, {one = 1; two = 2}, {.name = "John"; .age = 12}, {.name = Str; .age = Nat}, ...
```
### [Set 字面量](./14_set.md)
### [Set 字面量](./15_set.md)
```python
{}, {1}, {1, 2, 3}, {"1", "2", "1"}, {1, "1", True, [1]} ...

View file

@ -3,6 +3,7 @@
[![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/syntax/02_name.md%26commit_hash%3D14b0c449efc9e9da3e10a09c912a960ecfaf1c9d)](https://gezf7g7pd5.execute-api.ap-northeast-1.amazonaws.com/default/source_up_to_date?owner=erg-lang&repos=erg&ref=main&path=doc/EN/syntax/02_name.md&commit_hash=14b0c449efc9e9da3e10a09c912a960ecfaf1c9d)
## 变量
变量是一种代数; Erg 中的代数 - 如果没有混淆,有时简称为变量 - 指的是命名对象并使它们可从代码的其他地方引用的功能
变量定义如下
@ -24,9 +25,12 @@ n: Nat = 1
请注意,与其他语言不同,不允许多次分配
```python
```python,compile_fail
# NG
l1 = l2 = [1, 2, 3] # 语法错误: 不允许多重赋值
```
```python
# OK
l1 = [1, 2, 3]
l2 = l1.clone()
@ -67,7 +71,7 @@ assert x == 0
常数也是一种代数。如果标识符以大写字母开头,则将其视为常量。它们被称为常量,因为一旦定义,它们就不会改变
`N` 部分称为常量名(或标识符)。否则,它与变量相同
```python
```python,compile_fail
N = 0
if True, do:
N = 1 # 赋值错误: 常量不能被遮蔽
@ -100,6 +104,9 @@ match! x:
```python
X = 1 # OK
```
```python,compile_fail
X = !1 # 类型错误: 无法定义 Int 对象作为常量
```
@ -107,7 +114,7 @@ X = !1 # 类型错误: 无法定义 Int 对象作为常量
您可以使用 `Del` 函数删除变量。依赖于变量的所有其他变量(即直接引用变量值的变量)也将被删除
```python
```python,checker_ignore
x = 1
y = 2
z = 3
@ -122,7 +129,7 @@ f(2) # 名称错误: f 未定义(在第 6 行中删除)
注意 `Del` 只能删除用户自定义模块中定义的变量。无法删除诸如"True"之类的内置常量
```python
```python,compile_fail
Del True # 类型错误: 无法删除内置常量
Del print! # TypeError: 无法删除内置变量
```

View file

@ -107,8 +107,8 @@ C = Class {x = Int}
.method self = ...
```
您可以通過在`'''`之后立即寫入語言代碼來指定文檔的語言。然后,[Erg語言服務器](https://github.com/erg-lang/erg/tree/main/compiler/els)將以Markdown格式顯示每種語言版本的文檔(默認語言為英語)。
參見[這里](https://github.com/erg-lang/erg/blob/main/doc/JA/dev_guide/i18n_messages.md)獲取多語言相關文檔
您可以通過在`'''`之后立即寫入語言代碼來指定文檔的語言。然后,[Erg語言服務器](https://github.com/erg-lang/erg/tree/main/crates/els)將以Markdown格式顯示每種語言版本的文檔(默認語言為英語)。
參見[這里](https://github.com/erg-lang/erg/blob/main/doc/zh_TW/dev_guide/i18n_messages.md)獲取多語言相關文檔
```python
'''

View file

@ -78,25 +78,25 @@ assert 1e-10 == 0.0000000001
[], [1], [1, 2, 3], ["1", "2",], [1, "1", True, [1]], ...
```
### [元組字面量](./11_tuple.md)
### [元組字面量](./13_tuple.md)
```python
(), (1, 2, 3), (1, "hello", True), ...
```
### [字典字面量](./12_dict.md)
### [字典字面量](./11_dict.md)
```python
{:}, {"one": 1}, {"one": 1, "two": 2}, {"1": 1, "2": 2}, {1: "1", 2: True, "three": [1]}, ...
```
### [Record 字面量](./13_record.md)
### [Record 字面量](./14_record.md)
```python
{=}, {one = 1}, {one = 1; two = 2}, {.name = "John"; .age = 12}, {.name = Str; .age = Nat}, ...
```
### [Set 字面量](./14_set.md)
### [Set 字面量](./15_set.md)
```python
{}, {1}, {1, 2, 3}, {"1", "2", "1"}, {1, "1", True, [1]} ...

View file

@ -3,6 +3,7 @@
[![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/syntax/02_name.md%26commit_hash%3D14b0c449efc9e9da3e10a09c912a960ecfaf1c9d)](https://gezf7g7pd5.execute-api.ap-northeast-1.amazonaws.com/default/source_up_to_date?owner=erg-lang&repos=erg&ref=main&path=doc/EN/syntax/02_name.md&commit_hash=14b0c449efc9e9da3e10a09c912a960ecfaf1c9d)
## 變量
變量是一種代數; Erg 中的代數 - 如果沒有混淆,有時簡稱為變量 - 指的是命名對象并使它們可從代碼的其他地方引用的功能
變量定義如下
@ -24,9 +25,12 @@ n: Nat = 1
請注意,與其他語言不同,不允許多次分配
```python
```python,compile_fail
# NG
l1 = l2 = [1, 2, 3] # 語法錯誤: 不允許多重賦值
```
```python
# OK
l1 = [1, 2, 3]
l2 = l1.clone()
@ -67,7 +71,7 @@ assert x == 0
常數也是一種代數。如果標識符以大寫字母開頭,則將其視為常量。它們被稱為常量,因為一旦定義,它們就不會改變
`N` 部分稱為常量名(或標識符)。否則,它與變量相同
```python
```python,compile_fail
N = 0
if True, do:
N = 1 # 賦值錯誤: 常量不能被遮蔽
@ -100,6 +104,9 @@ match! x:
```python
X = 1 # OK
```
```python,compile_fail
X = !1 # 類型錯誤: 無法定義 Int 對象作為常量
```
@ -107,7 +114,7 @@ X = !1 # 類型錯誤: 無法定義 Int 對象作為常量
您可以使用 `Del` 函數刪除變量。依賴于變量的所有其他變量(即直接引用變量值的變量)也將被刪除
```python
```python,compile_fail
x = 1
y = 2
z = 3
@ -122,7 +129,7 @@ f(2) # 名稱錯誤: f 未定義(在第 6 行中刪除)
注意 `Del` 只能刪除用戶自定義模塊中定義的變量。無法刪除諸如"True"之類的內置常量
```python
```python,compile_fail
Del True # 類型錯誤: 無法刪除內置常量
Del print! # TypeError: 無法刪除內置變量
```

View file

@ -19,6 +19,14 @@ use erg_compiler::Compiler;
pub type EvalError = CompileError;
pub type EvalErrors = CompileErrors;
fn find_available_port() -> u16 {
let socket = SocketAddrV4::new(Ipv4Addr::LOCALHOST, 0);
TcpListener::bind(socket)
.and_then(|listener| listener.local_addr())
.map(|sock_addr| sock_addr.port())
.expect("No free port found.")
}
/// Open the Python interpreter as a server and act as an Erg interpreter by mediating communication
///
/// Pythonインタープリタをサーバーとして開き、通信を仲介することでErgインタープリタとして振る舞う
@ -208,24 +216,3 @@ impl DummyVM {
Runnable::eval(self, src)
}
}
#[cfg(test)]
fn find_available_port() -> u16 {
require_free_port()
}
#[cfg(not(test))]
fn find_available_port() -> u16 {
const DEFAULT_PORT: u16 = 8736;
TcpListener::bind(SocketAddrV4::new(Ipv4Addr::LOCALHOST, DEFAULT_PORT))
.is_ok()
.then_some(DEFAULT_PORT)
.unwrap_or_else(require_free_port)
}
fn require_free_port() -> u16 {
let socket = SocketAddrV4::new(Ipv4Addr::LOCALHOST, 0);
TcpListener::bind(socket)
.and_then(|listener| listener.local_addr())
.map(|sock_addr| sock_addr.port())
.expect("No free port found.")
}

View file

@ -5,9 +5,7 @@ import sys as __sys
import importlib as __importlib
import io as __io
__server_socket = __socket.socket(__socket.AF_INET, __socket.SOCK_STREAM)
if __sys.platform == 'linux':
__server_socket.setsockopt(__socket.SOL_SOCKET, __socket.SO_REUSEADDR, 1)
__server_socket = __socket.socket()
# DummyVM will replace this __PORT__ with free port
__server_socket.bind(('127.0.0.1', __PORT__))
__server_socket.listen(1)

View file

@ -5,7 +5,7 @@ use erg_common::config::{DummyStdin, ErgConfig, Input};
use erg_common::error::MultiErrorDisplay;
use erg_common::python_util::PythonVersion;
use erg_common::spawn::exec_new_thread;
use erg_common::style::{GREEN, RESET};
use erg_common::style::{colors::DEBUG_MAIN, RESET};
use erg_common::traits::{ExitStatus, Runnable, Stream};
use erg_compiler::error::CompileErrors;
@ -107,7 +107,7 @@ fn set_cfg(mut cfg: ErgConfig) -> ErgConfig {
/// The test is intend to run only on 3.11 for fast execution.
/// To execute on other versions, change the version and magic number.
fn _exec_file(file_path: &'static str) -> Result<i32, CompileErrors> {
println!("{GREEN}[test] exec {file_path}{RESET}");
println!("{DEBUG_MAIN}[test] exec {file_path}{RESET}");
let cfg = ErgConfig::with_main_path(PathBuf::from(file_path));
let mut vm = DummyVM::new(set_cfg(cfg));
vm.exec()
@ -115,7 +115,7 @@ fn _exec_file(file_path: &'static str) -> Result<i32, CompileErrors> {
/// WARN: You must quit REPL manually (use `:exit`, `:quit` or call something shutdowns the interpreter)
pub fn _exec_repl(name: &'static str, lines: Vec<String>) -> Result<ExitStatus, CompileErrors> {
println!("{GREEN}[test] exec dummy REPL: {lines:?}{RESET}");
println!("{DEBUG_MAIN}[test] exec dummy REPL: {lines:?}{RESET}");
let cfg = ErgConfig {
input: Input::DummyREPL(DummyStdin::new(name.to_string(), lines)),
quiet_repl: true,