Merge pull request #138 from erg-lang/class

Implement class syntax
This commit is contained in:
Shunsuke Shibayama 2022-09-10 20:24:43 +09:00 committed by GitHub
commit d56fd68058
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
63 changed files with 5146 additions and 2705 deletions

10
Cargo.lock generated
View file

@ -15,7 +15,7 @@ dependencies = [
[[package]] [[package]]
name = "erg" name = "erg"
version = "0.3.2" version = "0.4.0-beta.1"
dependencies = [ dependencies = [
"erg_common", "erg_common",
"erg_compiler", "erg_compiler",
@ -25,14 +25,14 @@ dependencies = [
[[package]] [[package]]
name = "erg_common" name = "erg_common"
version = "0.3.2" version = "0.4.0-beta.1"
dependencies = [ dependencies = [
"atty", "atty",
] ]
[[package]] [[package]]
name = "erg_compiler" name = "erg_compiler"
version = "0.3.2" version = "0.4.0-beta.1"
dependencies = [ dependencies = [
"erg_common", "erg_common",
"erg_parser", "erg_parser",
@ -41,14 +41,14 @@ dependencies = [
[[package]] [[package]]
name = "erg_parser" name = "erg_parser"
version = "0.3.2" version = "0.4.0-beta.1"
dependencies = [ dependencies = [
"erg_common", "erg_common",
] ]
[[package]] [[package]]
name = "erg_type" name = "erg_type"
version = "0.3.2" version = "0.4.0-beta.1"
dependencies = [ dependencies = [
"erg_common", "erg_common",
] ]

View file

@ -1,6 +1,6 @@
[package] [package]
name = "erg" name = "erg"
version = "0.3.2" version = "0.4.0-beta.1"
description = "The Erg programming language" description = "The Erg programming language"
authors = ["Shunsuke Shibayama <sbym1346@gmail.com>"] authors = ["Shunsuke Shibayama <sbym1346@gmail.com>"]
license = "MIT OR Apache-2.0" license = "MIT OR Apache-2.0"
@ -46,10 +46,10 @@ traditional_chinese = [
] ]
[dependencies] [dependencies]
erg_common = { version = "0.3.2", path = "./compiler/erg_common" } erg_common = { version = "0.4.0-beta.1", path = "./compiler/erg_common" }
erg_parser = { version = "0.3.2", path = "./compiler/erg_parser" } erg_parser = { version = "0.4.0-beta.1", path = "./compiler/erg_parser" }
erg_compiler = { version = "0.3.2", path = "./compiler/erg_compiler" } erg_compiler = { version = "0.4.0-beta.1", path = "./compiler/erg_compiler" }
erg_type = { version = "0.3.2", path = "./compiler/erg_type" } erg_type = { version = "0.4.0-beta.1", path = "./compiler/erg_type" }
# [workspace] # [workspace]
# member = ["cm", "dyne"] # member = ["cm", "dyne"]

View file

@ -4,7 +4,7 @@ if %~dp0 == C:%homepath%\GitHub\erg\ (
cd compiler/erg_common cd compiler/erg_common
echo publish erg_common ... echo publish erg_common ...
cargo publish cargo publish
timeout 10 timeout 12
cd ../erg_type cd ../erg_type
echo publish erg_type ... echo publish erg_type ...
cargo publish cargo publish

View file

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

View file

@ -153,6 +153,14 @@ impl<K: Hash + Eq, V> Dict<K, V> {
self.dict.get_mut(k) self.dict.get_mut(k)
} }
pub fn get_key_value<Q: ?Sized>(&self, k: &Q) -> Option<(&K, &V)>
where
K: Borrow<Q>,
Q: Hash + Eq,
{
self.dict.get_key_value(k)
}
#[inline] #[inline]
pub fn contains_key<Q: ?Sized>(&self, k: &Q) -> bool pub fn contains_key<Q: ?Sized>(&self, k: &Q) -> bool
where where

View file

@ -35,6 +35,10 @@ pub enum ErrorKind {
PurityError, PurityError,
HasEffect, HasEffect,
MoveError, MoveError,
NotConstExpr,
InheritanceError,
VisibilityError,
DummyError,
/* compile warnings */ /* compile warnings */
AttributeWarning = 60, AttributeWarning = 60,
CastWarning, CastWarning,
@ -201,9 +205,9 @@ impl From<&str> for ErrorKind {
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum Location { pub enum Location {
RangePair { RangePair {
ln_begin: usize, ln_first: (usize, usize),
col_first: (usize, usize), col_first: (usize, usize),
ln_end: usize, ln_second: (usize, usize),
col_second: (usize, usize), col_second: (usize, usize),
}, },
Range { Range {
@ -238,16 +242,19 @@ impl Location {
pub fn pair(lhs: Self, rhs: Self) -> Self { pub fn pair(lhs: Self, rhs: Self) -> Self {
Self::RangePair { Self::RangePair {
ln_begin: lhs.ln_begin().unwrap(), ln_first: (lhs.ln_begin().unwrap(), lhs.ln_end().unwrap()),
col_first: (lhs.col_begin().unwrap(), lhs.col_end().unwrap()), col_first: (lhs.col_begin().unwrap(), lhs.col_end().unwrap()),
ln_end: rhs.ln_end().unwrap(), ln_second: (rhs.ln_begin().unwrap(), rhs.ln_end().unwrap()),
col_second: (rhs.col_begin().unwrap(), rhs.col_end().unwrap()), col_second: (rhs.col_begin().unwrap(), rhs.col_end().unwrap()),
} }
} }
pub const fn ln_begin(&self) -> Option<usize> { pub const fn ln_begin(&self) -> Option<usize> {
match self { match self {
Self::RangePair { ln_begin, .. } Self::RangePair {
ln_first: (ln_begin, _),
..
}
| Self::Range { ln_begin, .. } | Self::Range { ln_begin, .. }
| Self::LineRange(ln_begin, _) | Self::LineRange(ln_begin, _)
| Self::Line(ln_begin) => Some(*ln_begin), | Self::Line(ln_begin) => Some(*ln_begin),
@ -257,7 +264,10 @@ impl Location {
pub const fn ln_end(&self) -> Option<usize> { pub const fn ln_end(&self) -> Option<usize> {
match self { match self {
Self::RangePair { ln_end, .. } Self::RangePair {
ln_second: (_, ln_end),
..
}
| Self::Range { ln_end, .. } | Self::Range { ln_end, .. }
| Self::LineRange(ln_end, _) | Self::LineRange(ln_end, _)
| Self::Line(ln_end) => Some(*ln_end), | Self::Line(ln_end) => Some(*ln_end),
@ -316,8 +326,18 @@ impl ErrorCore {
} }
} }
pub fn dummy(errno: usize) -> Self {
Self::new(
errno,
DummyError,
Location::Line(errno as usize),
"<dummy>",
None,
)
}
pub fn unreachable(fn_name: &str, line: u32) -> Self { pub fn unreachable(fn_name: &str, line: u32) -> Self {
Self::bug(line as usize, Location::Unknown, fn_name, line) Self::bug(line as usize, Location::Line(line as usize), fn_name, line)
} }
pub fn bug(errno: usize, loc: Location, fn_name: &str, line: u32) -> Self { pub fn bug(errno: usize, loc: Location, fn_name: &str, line: u32) -> Self {
@ -339,6 +359,41 @@ impl ErrorCore {
pub const VBAR_UNICODE: &str = ""; pub const VBAR_UNICODE: &str = "";
pub const VBAR_BREAK_UNICODE: &str = "·"; pub const VBAR_BREAK_UNICODE: &str = "·";
fn format_code_and_pointer<E: ErrorDisplay + ?Sized>(
e: &E,
ln_begin: usize,
ln_end: usize,
col_begin: usize,
col_end: usize,
) -> String {
let codes = if e.input() == &Input::REPL {
vec![e.input().reread()]
} else {
e.input().reread_lines(ln_begin, ln_end)
};
let mut res = CYAN.to_string();
let final_step = ln_end - ln_begin;
for (i, lineno) in (ln_begin..=ln_end).enumerate() {
let mut pointer = " ".repeat(lineno.to_string().len() + 2); // +2 means `| `
if i == 0 && i == final_step {
pointer += &" ".repeat(col_begin);
pointer += &"^".repeat(cmp::max(1, col_end - col_begin));
} else if i == 0 {
pointer += &" ".repeat(col_begin);
pointer += &"^".repeat(cmp::max(1, codes[i].len() - col_begin));
} else if i == final_step {
pointer += &"^".repeat(col_end);
} else {
pointer += &"^".repeat(cmp::max(1, codes[i].len()));
}
res += &format!(
"{lineno}{VBAR_UNICODE} {code}\n{pointer}\n",
code = codes[i]
);
}
res + RESET
}
/// format: /// format:
/// ```console /// ```console
/// Error[#{.errno}]: File {file}, line {.loc (as line)}, in {.caused_by} /// Error[#{.errno}]: File {file}, line {.loc (as line)}, in {.caused_by}
@ -418,13 +473,15 @@ pub trait ErrorDisplay {
Location::Range { Location::Range {
ln_begin, ln_end, .. ln_begin, ln_end, ..
} if ln_begin == ln_end => format!(", line {ln_begin}"), } if ln_begin == ln_end => format!(", line {ln_begin}"),
Location::RangePair { Location::Range {
ln_begin, ln_end, ..
}
| Location::Range {
ln_begin, ln_end, .. ln_begin, ln_end, ..
} }
| Location::LineRange(ln_begin, ln_end) => format!(", line {ln_begin}..{ln_end}"), | Location::LineRange(ln_begin, ln_end) => format!(", line {ln_begin}..{ln_end}"),
Location::RangePair {
ln_first: (l1, l2),
ln_second: (l3, l4),
..
} => format!(", line {l1}..{l2}, {l3}..{l4}"),
Location::Line(lineno) => format!(", line {lineno}"), Location::Line(lineno) => format!(", line {lineno}"),
Location::Unknown => "".to_string(), Location::Unknown => "".to_string(),
}; };
@ -442,33 +499,37 @@ pub trait ErrorDisplay {
fn format_code_and_pointer(&self) -> String { fn format_code_and_pointer(&self) -> String {
match self.core().loc { match self.core().loc {
Location::RangePair { .. } => todo!(), Location::RangePair {
ln_first,
col_first,
ln_second,
col_second,
} => {
format_code_and_pointer(self, ln_first.0, ln_first.1, col_first.0, col_first.1)
+ &format_code_and_pointer(
self,
ln_second.0,
ln_second.1,
col_second.0,
col_second.1,
)
}
Location::Range { Location::Range {
ln_begin, ln_begin,
col_begin, col_begin,
ln_end, ln_end,
col_end, col_end,
} => { } => format_code_and_pointer(self, ln_begin, ln_end, col_begin, col_end),
Location::LineRange(ln_begin, ln_end) => {
let codes = if self.input() == &Input::REPL { let codes = if self.input() == &Input::REPL {
vec![self.input().reread()] vec![self.input().reread()]
} else { } else {
self.input().reread_lines(ln_begin, ln_end) self.input().reread_lines(ln_begin, ln_end)
}; };
let mut res = CYAN.to_string(); let mut res = CYAN.to_string();
let final_step = ln_end - ln_begin;
for (i, lineno) in (ln_begin..=ln_end).enumerate() { for (i, lineno) in (ln_begin..=ln_end).enumerate() {
let mut pointer = " ".repeat(lineno.to_string().len() + 2); // +2 means `| ` let mut pointer = " ".repeat(lineno.to_string().len() + 2); // +2 means `| `
if i == 0 && i == final_step { pointer += &"^".repeat(cmp::max(1, codes[i].len()));
pointer += &" ".repeat(col_begin);
pointer += &"^".repeat(cmp::max(1, col_end - col_begin));
} else if i == 0 {
pointer += &" ".repeat(col_begin);
pointer += &"^".repeat(cmp::max(1, codes[i].len() - col_begin));
} else if i == final_step {
pointer += &"^".repeat(col_end);
} else {
pointer += &"^".repeat(cmp::max(1, codes[i].len()));
}
res += &format!( res += &format!(
"{lineno}{VBAR_UNICODE} {code}\n{pointer}\n", "{lineno}{VBAR_UNICODE} {code}\n{pointer}\n",
code = codes[i] code = codes[i]
@ -476,9 +537,6 @@ pub trait ErrorDisplay {
} }
res + RESET res + RESET
} }
Location::LineRange(_begin, _end) => {
todo!()
}
Location::Line(lineno) => { Location::Line(lineno) => {
let code = if self.input() == &Input::REPL { let code = if self.input() == &Input::REPL {
self.input().reread() self.input().reread()

View file

@ -87,6 +87,9 @@ macro_rules! enum_unwrap {
($ex: expr, $Enum: path :( $Cons: path :(_) ) $(,)*) => {{ ($ex: expr, $Enum: path :( $Cons: path :(_) ) $(,)*) => {{
if let $Enum($Cons(res)) = $ex { res } else { $crate::switch_unreachable!() } if let $Enum($Cons(res)) = $ex { res } else { $crate::switch_unreachable!() }
}}; }};
($ex: expr, $Enum: path :( $Cons: path :( $Cons2: path :(_) ) ) $(,)*) => {{
if let $Enum($Cons($Cons2(res))) = $ex { res } else { $crate::switch_unreachable!() }
}};
// X::A{a, b} // X::A{a, b}
($ex: expr, $Enum: path {$($fields: ident $(,)*)*}) => {{ ($ex: expr, $Enum: path {$($fields: ident $(,)*)*}) => {{
if let $Enum{$($fields,)*} = $ex { ($($fields,)*) } else { $crate::switch_unreachable!() } if let $Enum{$($fields,)*} = $ex { ($($fields,)*) } else { $crate::switch_unreachable!() }

View file

@ -63,6 +63,7 @@ pub enum Opcode {
PRINT_EXPR = 70, PRINT_EXPR = 70,
LOAD_BUILD_CLASS = 71, LOAD_BUILD_CLASS = 71,
LOAD_ASSERTION_ERROR = 74, LOAD_ASSERTION_ERROR = 74,
LIST_TO_TUPLE = 82,
RETURN_VALUE = 83, RETURN_VALUE = 83,
/* ↓ These opcodes take an arg */ /* ↓ These opcodes take an arg */
STORE_NAME = 90, STORE_NAME = 90,
@ -101,8 +102,10 @@ pub enum Opcode {
LOAD_DEREF = 136, LOAD_DEREF = 136,
STORE_DEREF = 137, STORE_DEREF = 137,
CALL_FUNCTION_KW = 141, CALL_FUNCTION_KW = 141,
CALL_FUNCTION_EX = 142,
LOAD_METHOD = 160, LOAD_METHOD = 160,
CALL_METHOD = 161, CALL_METHOD = 161,
LIST_EXTEND = 162,
// Erg-specific opcodes (must have a unary `ERG_`) // Erg-specific opcodes (must have a unary `ERG_`)
// Define in descending order from 219, 255 // Define in descending order from 219, 255
ERG_POP_NTH = 196, ERG_POP_NTH = 196,
@ -205,6 +208,7 @@ impl From<u8> for Opcode {
70 => PRINT_EXPR, 70 => PRINT_EXPR,
71 => LOAD_BUILD_CLASS, 71 => LOAD_BUILD_CLASS,
74 => LOAD_ASSERTION_ERROR, 74 => LOAD_ASSERTION_ERROR,
82 => LIST_TO_TUPLE,
83 => RETURN_VALUE, 83 => RETURN_VALUE,
/* ↓ These opcodes take an arg */ /* ↓ These opcodes take an arg */
90 => STORE_NAME, 90 => STORE_NAME,
@ -243,8 +247,10 @@ impl From<u8> for Opcode {
136 => LOAD_DEREF, 136 => LOAD_DEREF,
137 => STORE_DEREF, 137 => STORE_DEREF,
141 => CALL_FUNCTION_KW, 141 => CALL_FUNCTION_KW,
142 => CALL_FUNCTION_EX,
160 => LOAD_METHOD, 160 => LOAD_METHOD,
161 => CALL_METHOD, 161 => CALL_METHOD,
162 => LIST_EXTEND,
// Erg-specific opcodes // Erg-specific opcodes
196 => ERG_POP_NTH, 196 => ERG_POP_NTH,
197 => ERG_PEEK_NTH, 197 => ERG_PEEK_NTH,

View file

@ -119,6 +119,13 @@ pub trait Stream<T>: Sized {
fn take_all(&mut self) -> Vec<T> { fn take_all(&mut self) -> Vec<T> {
self.ref_mut_payload().drain(..).collect() self.ref_mut_payload().drain(..).collect()
} }
fn extend<I>(&mut self, iter: I)
where
I: IntoIterator<Item = T>,
{
self.ref_mut_payload().extend(iter);
}
} }
#[macro_export] #[macro_export]
@ -400,7 +407,10 @@ pub trait Locational {
fn ln_begin(&self) -> Option<usize> { fn ln_begin(&self) -> Option<usize> {
match self.loc() { match self.loc() {
Location::RangePair { ln_begin, .. } Location::RangePair {
ln_first: (ln_begin, _),
..
}
| Location::Range { ln_begin, .. } | Location::Range { ln_begin, .. }
| Location::LineRange(ln_begin, _) => Some(ln_begin), | Location::LineRange(ln_begin, _) => Some(ln_begin),
Location::Line(lineno) => Some(lineno), Location::Line(lineno) => Some(lineno),
@ -410,7 +420,10 @@ pub trait Locational {
fn ln_end(&self) -> Option<usize> { fn ln_end(&self) -> Option<usize> {
match self.loc() { match self.loc() {
Location::RangePair { ln_end, .. } Location::RangePair {
ln_second: (_, ln_end),
..
}
| Location::Range { ln_end, .. } | Location::Range { ln_end, .. }
| Location::LineRange(_, ln_end) => Some(ln_end), | Location::LineRange(_, ln_end) => Some(ln_end),
Location::Line(lineno) => Some(lineno), Location::Line(lineno) => Some(lineno),

View file

@ -22,8 +22,8 @@ impl Visibility {
/// same structure as `Identifier`, but only for Record fields. /// same structure as `Identifier`, but only for Record fields.
#[derive(Debug, Clone, PartialEq, Eq, Hash)] #[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct Field { pub struct Field {
vis: Visibility, pub vis: Visibility,
symbol: Str, pub symbol: Str,
} }
impl fmt::Display for Field { impl fmt::Display for Field {

View file

@ -1,6 +1,6 @@
[package] [package]
name = "erg_compiler" name = "erg_compiler"
version = "0.3.2" version = "0.4.0-beta.1"
description = "Centimetre: the Erg compiler" description = "Centimetre: the Erg compiler"
authors = ["Shunsuke Shibayama <sbym1346@gmail.com>"] authors = ["Shunsuke Shibayama <sbym1346@gmail.com>"]
license = "MIT OR Apache-2.0" license = "MIT OR Apache-2.0"
@ -17,9 +17,9 @@ simplified_chinese = [ "erg_common/simplified_chinese", "erg_parser/simplified_c
traditional_chinese = [ "erg_common/traditional_chinese", "erg_parser/traditional_chinese", "erg_type/traditional_chinese" ] traditional_chinese = [ "erg_common/traditional_chinese", "erg_parser/traditional_chinese", "erg_type/traditional_chinese" ]
[dependencies] [dependencies]
erg_common = { version = "0.3.2", path = "../erg_common" } erg_common = { version = "0.4.0-beta.1", path = "../erg_common" }
erg_parser = { version = "0.3.2", path = "../erg_parser" } erg_parser = { version = "0.4.0-beta.1", path = "../erg_parser" }
erg_type = { version = "0.3.2", path = "../erg_type" } erg_type = { version = "0.4.0-beta.1", path = "../erg_type" }
[lib] [lib]
path = "lib.rs" path = "lib.rs"

View file

@ -11,26 +11,39 @@ use erg_common::opcode::Opcode;
use erg_common::traits::{Locational, Stream}; use erg_common::traits::{Locational, Stream};
use erg_common::Str; use erg_common::Str;
use erg_common::{ use erg_common::{
debug_power_assert, enum_unwrap, fn_name_full, impl_stream_for_wrapper, log, switch_unreachable, debug_power_assert, enum_unwrap, fn_name, fn_name_full, impl_stream_for_wrapper, log,
switch_unreachable,
}; };
use erg_parser::ast::DefId;
use erg_type::codeobj::{CodeObj, CodeObjFlags}; use erg_type::codeobj::{CodeObj, CodeObjFlags};
use Opcode::*; use Opcode::*;
use erg_parser::ast::{Identifier, ParamPattern, Params, VarName}; use erg_parser::ast::{ParamPattern, ParamSignature, Params, VarName};
use erg_parser::token::{Token, TokenKind}; use erg_parser::token::{Token, TokenKind};
use erg_type::free::fresh_varname;
use erg_type::value::TypeKind;
use erg_type::value::ValueObj; use erg_type::value::ValueObj;
use erg_type::{HasType, 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::error::{CompileError, CompileErrors, CompileResult}; use crate::error::{CompileError, CompileErrors, CompileResult};
use crate::eval::eval_lit; use crate::hir::AttrDef;
use crate::hir::Attribute;
use crate::hir::{ use crate::hir::{
Accessor, Args, Array, Block, Call, DefBody, Expr, Local, Signature, SubrSignature, Tuple, Accessor, Args, Array, Block, Call, ClassDef, DefBody, Expr, Identifier, Literal, PosArg,
VarSignature, HIR, Signature, SubrSignature, Tuple, VarSignature, HIR,
}; };
use AccessKind::*; use AccessKind::*;
fn is_python_special(name: &str) -> bool {
match name {
"__call__" | "__init__" => true,
_ => false,
}
}
fn is_python_global(name: &str) -> bool { fn is_python_global(name: &str) -> bool {
match name { match name {
"ArithmeticError" "ArithmeticError"
@ -196,6 +209,7 @@ fn convert_to_python_attr(class: &str, uniq_obj_name: Option<&str>, name: Str) -
("Array!", _, "push!") => Str::ever("append"), ("Array!", _, "push!") => Str::ever("append"),
("Complex" | "Real" | "Int" | "Nat" | "Float", _, "Real") => Str::ever("real"), ("Complex" | "Real" | "Int" | "Nat" | "Float", _, "Real") => Str::ever("real"),
("Complex" | "Real" | "Int" | "Nat" | "Float", _, "Imag") => Str::ever("imag"), ("Complex" | "Real" | "Int" | "Nat" | "Float", _, "Imag") => Str::ever("imag"),
(_, _, "__new__") => Str::ever("__call__"),
("StringIO!", _, "getvalue!") => Str::ever("getvalue"), ("StringIO!", _, "getvalue!") => Str::ever("getvalue"),
("Module", Some("importlib"), "reload!") => Str::ever("reload"), ("Module", Some("importlib"), "reload!") => Str::ever("reload"),
("Module", Some("random"), "randint!") => Str::ever("randint"), ("Module", Some("random"), "randint!") => Str::ever("randint"),
@ -207,11 +221,17 @@ fn convert_to_python_attr(class: &str, uniq_obj_name: Option<&str>, name: Str) -
} }
} }
fn escape_attr(class: &str, uniq_obj_name: Option<&str>, name: Str) -> Str { fn escape_attr(class: &str, uniq_obj_name: Option<&str>, ident: Identifier) -> Str {
let mut name = convert_to_python_attr(class, uniq_obj_name, name).to_string(); let vis = ident.vis();
let mut name =
convert_to_python_attr(class, uniq_obj_name, ident.name.into_token().content).to_string();
name = name.replace('!', "__erg_proc__"); name = name.replace('!', "__erg_proc__");
name = name.replace('$', "__erg_shared__"); name = name.replace('$', "__erg_shared__");
Str::rc(&name) if vis.is_public() || is_python_global(&name) || is_python_special(&name) {
Str::from(name)
} else {
Str::from("::".to_string() + &name)
}
} }
fn convert_to_python_name(name: Str) -> Str { fn convert_to_python_name(name: Str) -> Str {
@ -247,7 +267,7 @@ fn escape_name(ident: Identifier) -> Str {
let mut name = convert_to_python_name(ident.name.into_token().content).to_string(); let mut name = convert_to_python_name(ident.name.into_token().content).to_string();
name = name.replace('!', "__erg_proc__"); name = name.replace('!', "__erg_proc__");
name = name.replace('$', "__erg_shared__"); name = name.replace('$', "__erg_shared__");
if vis.is_public() || is_python_global(&name) { if vis.is_public() || is_python_global(&name) || is_python_special(&name) {
Str::from(name) Str::from(name)
} else { } else {
Str::from("::".to_string() + &name) Str::from("::".to_string() + &name)
@ -312,7 +332,7 @@ impl_stream_for_wrapper!(CodeGenStack, CodeGenUnit);
pub struct CodeGenerator { pub struct CodeGenerator {
cfg: ErgConfig, cfg: ErgConfig,
str_cache: CacheSet<str>, str_cache: CacheSet<str>,
namedtuple_loaded: bool, prelude_loaded: bool,
unit_size: usize, unit_size: usize,
units: CodeGenStack, units: CodeGenStack,
pub(crate) errs: CompileErrors, pub(crate) errs: CompileErrors,
@ -323,7 +343,7 @@ impl CodeGenerator {
Self { Self {
cfg, cfg,
str_cache: CacheSet::new(), str_cache: CacheSet::new(),
namedtuple_loaded: false, prelude_loaded: false,
unit_size: 0, unit_size: 0,
units: CodeGenStack::empty(), units: CodeGenStack::empty(),
errs: CompileErrors::empty(), errs: CompileErrors::empty(),
@ -439,7 +459,7 @@ impl CodeGenerator {
self.stack_inc(); self.stack_inc();
} }
fn local_search(&self, name: &str, acc_kind: AccessKind) -> Option<Name> { fn local_search(&self, name: &str, _acc_kind: AccessKind) -> Option<Name> {
let current_is_toplevel = self.cur_block() == self.toplevel_block(); let current_is_toplevel = self.cur_block() == self.toplevel_block();
if let Some(idx) = self if let Some(idx) = self
.cur_block_codeobj() .cur_block_codeobj()
@ -447,11 +467,7 @@ impl CodeGenerator {
.iter() .iter()
.position(|n| &**n == name) .position(|n| &**n == name)
{ {
if current_is_toplevel || !acc_kind.is_local() { Some(Name::local(idx))
Some(Name::local(idx))
} else {
Some(Name::global(idx))
}
} else if let Some(idx) = self } else if let Some(idx) = self
.cur_block_codeobj() .cur_block_codeobj()
.varnames .varnames
@ -497,9 +513,8 @@ impl CodeGenerator {
Some(StoreLoadKind::Global) Some(StoreLoadKind::Global)
} }
fn register_name(&mut self, ident: Identifier) -> Name { fn register_name(&mut self, name: Str) -> Name {
let current_is_toplevel = self.cur_block() == self.toplevel_block(); let current_is_toplevel = self.cur_block() == self.toplevel_block();
let name = escape_name(ident);
match self.rec_search(&name) { match self.rec_search(&name) {
Some(st @ (StoreLoadKind::Local | StoreLoadKind::Global)) => { Some(st @ (StoreLoadKind::Local | StoreLoadKind::Global)) => {
let st = if current_is_toplevel { let st = if current_is_toplevel {
@ -530,24 +545,22 @@ impl CodeGenerator {
} }
} }
fn register_attr(&mut self, class: &str, uniq_obj_name: Option<&str>, name: Str) -> Name { fn register_attr(&mut self, name: Str) -> Name {
let name = Str::rc(name.split('.').last().unwrap());
let name = escape_attr(class, uniq_obj_name, name);
self.mut_cur_block_codeobj().names.push(name); self.mut_cur_block_codeobj().names.push(name);
Name::local(self.cur_block_codeobj().names.len() - 1) Name::local(self.cur_block_codeobj().names.len() - 1)
} }
fn register_method(&mut self, class: &str, uniq_obj_name: Option<&str>, name: Str) -> Name { fn register_method(&mut self, name: Str) -> Name {
let name = Str::rc(name.split('.').last().unwrap());
let name = escape_attr(class, uniq_obj_name, name);
self.mut_cur_block_codeobj().names.push(name); self.mut_cur_block_codeobj().names.push(name);
Name::local(self.cur_block_codeobj().names.len() - 1) Name::local(self.cur_block_codeobj().names.len() - 1)
} }
fn emit_load_name_instr(&mut self, ident: Identifier) -> CompileResult<()> { fn emit_load_name_instr(&mut self, ident: Identifier) -> CompileResult<()> {
log!(info "entered {}", fn_name!());
let escaped = escape_name(ident);
let name = self let name = self
.local_search(ident.inspect(), Name) .local_search(&escaped, Name)
.unwrap_or_else(|| self.register_name(ident)); .unwrap_or_else(|| self.register_name(escaped));
let instr = match name.kind { let instr = match name.kind {
StoreLoadKind::Fast | StoreLoadKind::FastConst => Opcode::LOAD_FAST, StoreLoadKind::Fast | StoreLoadKind::FastConst => Opcode::LOAD_FAST,
StoreLoadKind::Global | StoreLoadKind::GlobalConst => Opcode::LOAD_GLOBAL, StoreLoadKind::Global | StoreLoadKind::GlobalConst => Opcode::LOAD_GLOBAL,
@ -561,9 +574,11 @@ impl CodeGenerator {
} }
fn emit_import_name_instr(&mut self, ident: Identifier) -> CompileResult<()> { fn emit_import_name_instr(&mut self, ident: Identifier) -> CompileResult<()> {
log!(info "entered {}", fn_name!());
let escaped = escape_name(ident);
let name = self let name = self
.local_search(ident.inspect(), Name) .local_search(&escaped, Name)
.unwrap_or_else(|| self.register_name(ident)); .unwrap_or_else(|| self.register_name(escaped));
self.write_instr(IMPORT_NAME); self.write_instr(IMPORT_NAME);
self.write_arg(name.idx as u8); self.write_arg(name.idx as u8);
self.stack_dec(); // (level + from_list) -> module object self.stack_dec(); // (level + from_list) -> module object
@ -571,9 +586,11 @@ impl CodeGenerator {
} }
fn emit_import_from_instr(&mut self, ident: Identifier) -> CompileResult<()> { fn emit_import_from_instr(&mut self, ident: Identifier) -> CompileResult<()> {
log!(info "entered {}", fn_name!());
let escaped = escape_name(ident);
let name = self let name = self
.local_search(ident.inspect(), Name) .local_search(&escaped, Name)
.unwrap_or_else(|| self.register_name(ident)); .unwrap_or_else(|| self.register_name(escaped));
self.write_instr(IMPORT_FROM); self.write_instr(IMPORT_FROM);
self.write_arg(name.idx as u8); self.write_arg(name.idx as u8);
// self.stack_inc(); (module object) -> attribute // self.stack_inc(); (module object) -> attribute
@ -584,11 +601,13 @@ impl CodeGenerator {
&mut self, &mut self,
class: &str, class: &str,
uniq_obj_name: Option<&str>, uniq_obj_name: Option<&str>,
name: Str, ident: Identifier,
) -> CompileResult<()> { ) -> CompileResult<()> {
log!(info "entered {} ({class}{ident})", fn_name!());
let escaped = escape_attr(class, uniq_obj_name, ident);
let name = self let name = self
.local_search(&name, Attr) .local_search(&escaped, Attr)
.unwrap_or_else(|| self.register_attr(class, uniq_obj_name, name)); .unwrap_or_else(|| self.register_attr(escaped));
let instr = match name.kind { let instr = match name.kind {
StoreLoadKind::Fast | StoreLoadKind::FastConst => Opcode::LOAD_FAST, StoreLoadKind::Fast | StoreLoadKind::FastConst => Opcode::LOAD_FAST,
StoreLoadKind::Global | StoreLoadKind::GlobalConst => Opcode::LOAD_GLOBAL, StoreLoadKind::Global | StoreLoadKind::GlobalConst => Opcode::LOAD_GLOBAL,
@ -604,11 +623,13 @@ impl CodeGenerator {
&mut self, &mut self,
class: &str, class: &str,
uniq_obj_name: Option<&str>, uniq_obj_name: Option<&str>,
name: Str, ident: Identifier,
) -> CompileResult<()> { ) -> CompileResult<()> {
log!(info "entered {} ({class}{ident})", fn_name!());
let escaped = escape_attr(class, uniq_obj_name, ident);
let name = self let name = self
.local_search(&name, Method) .local_search(&escaped, Method)
.unwrap_or_else(|| self.register_method(class, uniq_obj_name, name)); .unwrap_or_else(|| self.register_method(escaped));
let instr = match name.kind { let instr = match name.kind {
StoreLoadKind::Fast | StoreLoadKind::FastConst => Opcode::LOAD_FAST, StoreLoadKind::Fast | StoreLoadKind::FastConst => Opcode::LOAD_FAST,
StoreLoadKind::Global | StoreLoadKind::GlobalConst => Opcode::LOAD_GLOBAL, StoreLoadKind::Global | StoreLoadKind::GlobalConst => Opcode::LOAD_GLOBAL,
@ -621,13 +642,21 @@ impl CodeGenerator {
} }
fn emit_store_instr(&mut self, ident: Identifier, acc_kind: AccessKind) { fn emit_store_instr(&mut self, ident: Identifier, acc_kind: AccessKind) {
let name = self log!(info "entered {} ({ident})", fn_name!());
.local_search(ident.inspect(), acc_kind) let escaped = escape_name(ident);
.unwrap_or_else(|| self.register_name(ident)); let name = self.local_search(&escaped, acc_kind).unwrap_or_else(|| {
if acc_kind.is_local() {
self.register_name(escaped)
} else {
self.register_attr(escaped)
}
});
let instr = match name.kind { let instr = match name.kind {
StoreLoadKind::Fast => Opcode::STORE_FAST, StoreLoadKind::Fast => Opcode::STORE_FAST,
StoreLoadKind::FastConst => Opcode::ERG_STORE_FAST_IMMUT, StoreLoadKind::FastConst => Opcode::ERG_STORE_FAST_IMMUT,
StoreLoadKind::Global | StoreLoadKind::GlobalConst => Opcode::STORE_GLOBAL, // NOTE: First-time variables are treated as GLOBAL, but they are always first-time variables when assigned, so they are just NAME
// NOTE: 初見の変数はGLOBAL扱いになるが、代入時は必ず初見であるので単なるNAME
StoreLoadKind::Global | StoreLoadKind::GlobalConst => Opcode::STORE_NAME,
StoreLoadKind::Deref | StoreLoadKind::DerefConst => Opcode::STORE_DEREF, StoreLoadKind::Deref | StoreLoadKind::DerefConst => Opcode::STORE_DEREF,
StoreLoadKind::Local | StoreLoadKind::LocalConst => { StoreLoadKind::Local | StoreLoadKind::LocalConst => {
match acc_kind { match acc_kind {
@ -641,6 +670,25 @@ impl CodeGenerator {
self.write_instr(instr); self.write_instr(instr);
self.write_arg(name.idx as u8); self.write_arg(name.idx as u8);
self.stack_dec(); self.stack_dec();
if instr == Opcode::STORE_ATTR {
self.stack_dec();
}
}
/// Ergの文法として、属性への代入は存在しない(必ずオブジェクトはすべての属性を初期化しなくてはならないため)
/// この関数はPythonへ落とし込むときに使う
fn store_acc(&mut self, acc: Accessor) {
log!(info "entered {} ({acc})", fn_name!());
match acc {
Accessor::Ident(ident) => {
self.emit_store_instr(ident, Name);
}
Accessor::Attr(attr) => {
self.codegen_expr(*attr.obj);
self.emit_store_instr(attr.ident, Attr);
}
acc => todo!("store: {acc}"),
}
} }
fn emit_pop_top(&mut self) { fn emit_pop_top(&mut self) {
@ -675,39 +723,68 @@ impl CodeGenerator {
.non_defaults .non_defaults
.iter() .iter()
.map(|p| p.inspect().map(|s| &s[..]).unwrap_or("_")) .map(|p| p.inspect().map(|s| &s[..]).unwrap_or("_"))
.chain(if let Some(var_args) = &params.var_args {
vec![var_args.inspect().map(|s| &s[..]).unwrap_or("_")]
} else {
vec![]
})
.chain( .chain(
params params
.defaults .defaults
.iter() .iter()
.map(|p| p.inspect().map(|s| &s[..]).unwrap_or("_")), .map(|p| p.inspect().map(|s| &s[..]).unwrap_or("_")),
) )
.map(|s| self.get_cached(s)) .map(|s| format!("::{s}"))
.map(|s| self.get_cached(&s))
.collect() .collect()
} }
fn emit_mono_type_def(&mut self, sig: VarSignature, body: DefBody) { fn emit_class_def(&mut self, class_def: ClassDef) {
log!(info "entered {} ({class_def})", fn_name!());
let ident = class_def.sig.ident().clone();
let kind = class_def.kind;
let require_or_sup = class_def.require_or_sup.clone();
self.write_instr(Opcode::LOAD_BUILD_CLASS); self.write_instr(Opcode::LOAD_BUILD_CLASS);
self.write_arg(0); self.write_arg(0);
self.stack_inc(); self.stack_inc();
let code = self.codegen_typedef_block(sig.inspect().clone(), body.block); let code = self.codegen_typedef_block(class_def);
self.emit_load_const(code); self.emit_load_const(code);
self.emit_load_const(sig.inspect().clone()); self.emit_load_const(ident.inspect().clone());
self.write_instr(Opcode::MAKE_FUNCTION); self.write_instr(Opcode::MAKE_FUNCTION);
self.write_arg(0); self.write_arg(0);
self.emit_load_const(sig.inspect().clone()); self.emit_load_const(ident.inspect().clone());
// LOAD subclasses
let subclasses_len = self.emit_require_type(kind, *require_or_sup);
self.write_instr(Opcode::CALL_FUNCTION); self.write_instr(Opcode::CALL_FUNCTION);
self.write_arg(2); self.write_arg(2 + subclasses_len as u8);
self.stack_dec_n((1 + 2) - 1); self.stack_dec_n((1 + 2 + subclasses_len) - 1);
self.emit_store_instr(sig.ident, Name); self.emit_store_instr(ident, Name);
self.stack_dec();
} }
// NOTE: use `TypeVar`, `Generic` in `typing` module // NOTE: use `TypeVar`, `Generic` in `typing` module
// fn emit_poly_type_def(&mut self, sig: SubrSignature, body: DefBody) {} // fn emit_poly_type_def(&mut self, sig: SubrSignature, body: DefBody) {}
fn emit_var_def(&mut self, sig: VarSignature, mut body: DefBody) { fn emit_require_type(&mut self, kind: TypeKind, require_or_sup: Expr) -> usize {
if body.is_type() { log!(info "entered {} ({kind:?}, {require_or_sup})", fn_name!());
return self.emit_mono_type_def(sig, body); match kind {
TypeKind::Class => 0,
TypeKind::Subclass => {
self.codegen_expr(require_or_sup);
1 // TODO: not always 1
}
_ => todo!(),
} }
}
fn emit_attr_def(&mut self, attr_def: AttrDef) {
log!(info "entered {} ({attr_def})", fn_name!());
self.codegen_frameless_block(attr_def.block, vec![]);
self.store_acc(attr_def.attr);
}
fn emit_var_def(&mut self, sig: VarSignature, mut body: DefBody) {
log!(info "entered {} ({sig} = {})", fn_name!(), body.block);
if body.block.len() == 1 { if body.block.len() == 1 {
self.codegen_expr(body.block.remove(0)); self.codegen_expr(body.block.remove(0));
} else { } else {
@ -716,7 +793,8 @@ impl CodeGenerator {
self.emit_store_instr(sig.ident, Name); self.emit_store_instr(sig.ident, Name);
} }
fn emit_subr_def(&mut self, sig: SubrSignature, body: DefBody) { fn emit_subr_def(&mut self, class_name: Option<&str>, sig: SubrSignature, body: DefBody) {
log!(info "entered {} ({sig} = {})", fn_name!(), body.block);
let name = sig.ident.inspect().clone(); let name = sig.ident.inspect().clone();
let mut opcode_flag = 0u8; let mut opcode_flag = 0u8;
let params = self.gen_param_names(&sig.params); let params = self.gen_param_names(&sig.params);
@ -732,7 +810,11 @@ impl CodeGenerator {
self.write_arg(cellvars_len); self.write_arg(cellvars_len);
opcode_flag += 8; opcode_flag += 8;
} }
self.emit_load_const(name.clone()); if let Some(class) = class_name {
self.emit_load_const(Str::from(format!("{class}.{name}")));
} else {
self.emit_load_const(name);
}
self.write_instr(MAKE_FUNCTION); self.write_instr(MAKE_FUNCTION);
self.write_arg(opcode_flag); self.write_arg(opcode_flag);
// stack_dec: <code obj> + <name> -> <function> // stack_dec: <code obj> + <name> -> <function>
@ -741,6 +823,7 @@ impl CodeGenerator {
} }
fn emit_discard_instr(&mut self, mut args: Args) -> CompileResult<()> { fn emit_discard_instr(&mut self, mut args: Args) -> CompileResult<()> {
log!(info "entered {}", fn_name!());
while let Some(arg) = args.try_remove(0) { while let Some(arg) = args.try_remove(0) {
self.codegen_expr(arg); self.codegen_expr(arg);
self.emit_pop_top(); self.emit_pop_top();
@ -749,6 +832,7 @@ impl CodeGenerator {
} }
fn emit_if_instr(&mut self, mut args: Args) -> CompileResult<()> { fn emit_if_instr(&mut self, mut args: Args) -> CompileResult<()> {
log!(info "entered {}", fn_name!());
let cond = args.remove(0); let cond = args.remove(0);
self.codegen_expr(cond); self.codegen_expr(cond);
let idx_pop_jump_if_false = self.cur_block().lasti; let idx_pop_jump_if_false = self.cur_block().lasti;
@ -797,6 +881,7 @@ impl CodeGenerator {
} }
fn emit_for_instr(&mut self, mut args: Args) -> CompileResult<()> { fn emit_for_instr(&mut self, mut args: Args) -> CompileResult<()> {
log!(info "entered {}", fn_name!());
let iterable = args.remove(0); let iterable = args.remove(0);
self.codegen_expr(iterable); self.codegen_expr(iterable);
self.write_instr(GET_ITER); self.write_instr(GET_ITER);
@ -819,6 +904,7 @@ impl CodeGenerator {
} }
fn emit_match_instr(&mut self, mut args: Args, _use_erg_specific: bool) -> CompileResult<()> { fn emit_match_instr(&mut self, mut args: Args, _use_erg_specific: bool) -> CompileResult<()> {
log!(info "entered {}", fn_name!());
let expr = args.remove(0); let expr = args.remove(0);
self.codegen_expr(expr); self.codegen_expr(expr);
let len = args.len(); let len = args.len();
@ -855,10 +941,11 @@ impl CodeGenerator {
} }
fn emit_match_pattern(&mut self, pat: ParamPattern) -> CompileResult<Vec<usize>> { fn emit_match_pattern(&mut self, pat: ParamPattern) -> CompileResult<Vec<usize>> {
log!(info "entered {}", fn_name!());
let mut pop_jump_points = vec![]; let mut pop_jump_points = vec![];
match pat { match pat {
ParamPattern::VarName(name) => { ParamPattern::VarName(name) => {
let ident = Identifier::new(None, name); let ident = Identifier::bare(None, name);
self.emit_store_instr(ident, AccessKind::Name); self.emit_store_instr(ident, AccessKind::Name);
} }
ParamPattern::Lit(lit) => { ParamPattern::Lit(lit) => {
@ -908,19 +995,24 @@ impl CodeGenerator {
} }
fn emit_call(&mut self, call: Call) { fn emit_call(&mut self, call: Call) {
log!(info "entered {} ({call})", fn_name!());
if let Some(method_name) = call.method_name { if let Some(method_name) = call.method_name {
self.emit_call_method(*call.obj, method_name, call.args); self.emit_call_method(*call.obj, method_name, call.args);
} else { } else {
match *call.obj { match *call.obj {
Expr::Accessor(Accessor::Local(local)) => { Expr::Accessor(Accessor::Ident(ident)) if ident.vis().is_private() => {
self.emit_call_local(local, call.args).unwrap() self.emit_call_local(ident, call.args).unwrap()
}
other => {
self.codegen_expr(other);
self.emit_args(call.args, Name);
} }
other => todo!("calling {other}"),
} }
} }
} }
fn emit_call_local(&mut self, local: Local, mut args: Args) -> CompileResult<()> { fn emit_call_local(&mut self, local: Identifier, args: Args) -> CompileResult<()> {
log!(info "entered {}", fn_name!());
match &local.inspect()[..] { match &local.inspect()[..] {
"assert" => self.emit_assert_instr(args), "assert" => self.emit_assert_instr(args),
"discard" => self.emit_discard_instr(args), "discard" => self.emit_discard_instr(args),
@ -928,54 +1020,50 @@ impl CodeGenerator {
"if" | "if!" => self.emit_if_instr(args), "if" | "if!" => self.emit_if_instr(args),
"match" | "match!" => self.emit_match_instr(args, true), "match" | "match!" => self.emit_match_instr(args, true),
_ => { _ => {
let name = VarName::new(local.name); self.emit_load_name_instr(local).unwrap_or_else(|e| {
let ident = Identifier::new(None, name);
self.emit_load_name_instr(ident).unwrap_or_else(|e| {
self.errs.push(e); self.errs.push(e);
}); });
let argc = args.len(); self.emit_args(args, Name);
let mut kws = Vec::with_capacity(args.kw_len());
while let Some(arg) = args.try_remove_pos(0) {
self.codegen_expr(arg.expr);
}
while let Some(arg) = args.try_remove_kw(0) {
kws.push(ValueObj::Str(arg.keyword.content.clone()));
self.codegen_expr(arg.expr);
}
let kwsc = if !kws.is_empty() {
let kws_tuple = ValueObj::from(kws);
self.emit_load_const(kws_tuple);
self.write_instr(CALL_FUNCTION_KW);
1
} else {
self.write_instr(CALL_FUNCTION);
0
};
self.write_arg(argc as u8);
// (1 (subroutine) + argc + kwsc) input objects -> 1 return object
self.stack_dec_n((1 + argc + kwsc) - 1);
Ok(()) Ok(())
} }
} }
} }
fn emit_call_method(&mut self, obj: Expr, method_name: Token, mut args: Args) { fn emit_call_method(&mut self, obj: Expr, method_name: Identifier, args: Args) {
log!(info "entered {}", fn_name!());
if &method_name.inspect()[..] == "update!" {
return self.emit_call_update(obj, args);
}
let class = obj.ref_t().name(); // これは必ずmethodのあるクラスになっている let class = obj.ref_t().name(); // これは必ずmethodのあるクラスになっている
let uniq_obj_name = obj.__name__().map(Str::rc); let uniq_obj_name = obj.__name__().map(Str::rc);
self.codegen_expr(obj); self.codegen_expr(obj);
self.emit_load_method_instr( self.emit_load_method_instr(&class, uniq_obj_name.as_ref().map(|s| &s[..]), method_name)
&class, .unwrap_or_else(|err| {
uniq_obj_name.as_ref().map(|s| &s[..]), self.errs.push(err);
method_name.content, });
) self.emit_args(args, Method);
.unwrap_or_else(|err| { }
self.errs.push(err);
}); fn emit_args(&mut self, mut args: Args, kind: AccessKind) {
let argc = args.len(); let argc = args.len();
let pos_len = args.pos_args.len();
let mut kws = Vec::with_capacity(args.kw_len()); let mut kws = Vec::with_capacity(args.kw_len());
while let Some(arg) = args.try_remove_pos(0) { while let Some(arg) = args.try_remove_pos(0) {
self.codegen_expr(arg.expr); self.codegen_expr(arg.expr);
} }
if let Some(var_args) = &args.var_args {
if pos_len > 0 {
self.write_instr(Opcode::BUILD_LIST);
self.write_arg(pos_len as u8);
}
self.codegen_expr(var_args.expr.clone());
if pos_len > 0 {
self.write_instr(Opcode::LIST_EXTEND);
self.write_arg(1);
self.write_instr(Opcode::LIST_TO_TUPLE);
self.write_arg(0);
}
}
while let Some(arg) = args.try_remove_kw(0) { while let Some(arg) = args.try_remove_kw(0) {
kws.push(ValueObj::Str(arg.keyword.content.clone())); kws.push(ValueObj::Str(arg.keyword.content.clone()));
self.codegen_expr(arg.expr); self.codegen_expr(arg.expr);
@ -984,18 +1072,49 @@ impl CodeGenerator {
let kws_tuple = ValueObj::from(kws); let kws_tuple = ValueObj::from(kws);
self.emit_load_const(kws_tuple); self.emit_load_const(kws_tuple);
self.write_instr(CALL_FUNCTION_KW); self.write_instr(CALL_FUNCTION_KW);
self.write_arg(argc as u8);
1 1
} else { } else {
self.write_instr(CALL_METHOD); if args.var_args.is_some() {
self.write_instr(CALL_FUNCTION_EX);
if kws.is_empty() {
self.write_arg(0);
} else {
self.write_arg(1);
}
} else {
if kind.is_method() {
self.write_instr(CALL_METHOD);
} else {
self.write_instr(CALL_FUNCTION);
}
self.write_arg(argc as u8);
}
0 0
}; };
self.write_arg(argc as u8); // (1 (subroutine) + argc + kwsc) input objects -> 1 return object
// (1 (method) + argc + kwsc) input objects -> 1 return object
self.stack_dec_n((1 + argc + kwsc) - 1); self.stack_dec_n((1 + argc + kwsc) - 1);
} }
/// X.update! x -> x + 1
/// X = (x -> x + 1)(X)
/// X = X + 1
fn emit_call_update(&mut self, obj: Expr, mut args: Args) {
log!(info "entered {}", fn_name!());
let acc = enum_unwrap!(obj, Expr::Accessor);
let func = args.remove_left_or_key("f").unwrap();
self.codegen_expr(func);
self.codegen_acc(acc.clone());
self.write_instr(CALL_FUNCTION);
self.write_arg(1 as u8);
// (1 (subroutine) + argc) input objects -> 1 return object
self.stack_dec_n((1 + 1) - 1);
self.store_acc(acc);
}
// assert takes 1 or 2 arguments (0: cond, 1: message) // assert takes 1 or 2 arguments (0: cond, 1: message)
fn emit_assert_instr(&mut self, mut args: Args) -> CompileResult<()> { fn emit_assert_instr(&mut self, mut args: Args) -> CompileResult<()> {
log!(info "entered {}", fn_name!());
self.codegen_expr(args.remove(0)); self.codegen_expr(args.remove(0));
let pop_jump_point = self.cur_block().lasti; let pop_jump_point = self.cur_block().lasti;
self.write_instr(Opcode::POP_JUMP_IF_TRUE); self.write_instr(Opcode::POP_JUMP_IF_TRUE);
@ -1016,6 +1135,7 @@ impl CodeGenerator {
} }
fn codegen_expr(&mut self, expr: Expr) { fn codegen_expr(&mut self, expr: Expr) {
log!(info "entered {} ({expr})", fn_name!());
if expr.ln_begin().unwrap_or_else(|| panic!("{expr}")) > self.cur_block().prev_lineno { if expr.ln_begin().unwrap_or_else(|| panic!("{expr}")) > self.cur_block().prev_lineno {
let sd = self.cur_block().lasti - self.cur_block().prev_lasti; let sd = self.cur_block().lasti - self.cur_block().prev_lasti;
let ld = expr.ln_begin().unwrap() - self.cur_block().prev_lineno; let ld = expr.ln_begin().unwrap() - self.cur_block().prev_lineno;
@ -1052,9 +1172,11 @@ impl CodeGenerator {
} }
Expr::Accessor(acc) => self.codegen_acc(acc), Expr::Accessor(acc) => self.codegen_acc(acc),
Expr::Def(def) => match def.sig { Expr::Def(def) => match def.sig {
Signature::Subr(sig) => self.emit_subr_def(sig, def.body), Signature::Subr(sig) => self.emit_subr_def(None, sig, def.body),
Signature::Var(sig) => self.emit_var_def(sig, def.body), Signature::Var(sig) => self.emit_var_def(sig, def.body),
}, },
Expr::ClassDef(class) => self.emit_class_def(class),
Expr::AttrDef(attr) => self.emit_attr_def(attr),
// TODO: // TODO:
Expr::Lambda(lambda) => { Expr::Lambda(lambda) => {
let params = self.gen_param_names(&lambda.params); let params = self.gen_param_names(&lambda.params);
@ -1193,20 +1315,6 @@ impl CodeGenerator {
}, },
Expr::Record(rec) => { Expr::Record(rec) => {
let attrs_len = rec.attrs.len(); let attrs_len = rec.attrs.len();
// importing namedtuple
if !self.namedtuple_loaded {
self.emit_load_const(0);
self.emit_load_const(ValueObj::Tuple(std::rc::Rc::from([ValueObj::Str(
Str::ever("namedtuple"),
)])));
let ident = Identifier::public("collections");
self.emit_import_name_instr(ident).unwrap();
let ident = Identifier::public("namedtuple");
self.emit_import_from_instr(ident).unwrap();
let ident = Identifier::private(Str::ever("#NamedTuple"));
self.emit_store_instr(ident, Name);
self.namedtuple_loaded = true;
}
// making record type // making record type
let ident = Identifier::private(Str::ever("#NamedTuple")); let ident = Identifier::private(Str::ever("#NamedTuple"));
self.emit_load_name_instr(ident).unwrap(); self.emit_load_name_instr(ident).unwrap();
@ -1252,15 +1360,9 @@ impl CodeGenerator {
} }
fn codegen_acc(&mut self, acc: Accessor) { fn codegen_acc(&mut self, acc: Accessor) {
log!(info "entered {} ({acc})", fn_name!());
match acc { match acc {
Accessor::Local(local) => { Accessor::Ident(ident) => {
self.emit_load_name_instr(Identifier::new(None, VarName::new(local.name)))
.unwrap_or_else(|err| {
self.errs.push(err);
});
}
Accessor::Public(public) => {
let ident = Identifier::new(Some(public.dot), VarName::new(public.name));
self.emit_load_name_instr(ident).unwrap_or_else(|err| { self.emit_load_name_instr(ident).unwrap_or_else(|err| {
self.errs.push(err); self.errs.push(err);
}); });
@ -1268,15 +1370,27 @@ impl CodeGenerator {
Accessor::Attr(a) => { Accessor::Attr(a) => {
let class = a.obj.ref_t().name(); let class = a.obj.ref_t().name();
let uniq_obj_name = a.obj.__name__().map(Str::rc); let uniq_obj_name = a.obj.__name__().map(Str::rc);
self.codegen_expr(*a.obj); // C = Class ...
self.emit_load_attr_instr( // C.
&class, // a = C.x
uniq_obj_name.as_ref().map(|s| &s[..]), // ↓
a.name.content.clone(), // class C:
) // a = x
.unwrap_or_else(|err| { if Some(&self.cur_block_codeobj().name[..]) != a.obj.__name__() {
self.errs.push(err); self.codegen_expr(*a.obj);
}); self.emit_load_attr_instr(
&class,
uniq_obj_name.as_ref().map(|s| &s[..]),
a.ident,
)
.unwrap_or_else(|err| {
self.errs.push(err);
});
} else {
self.emit_load_name_instr(a.ident).unwrap_or_else(|err| {
self.errs.push(err);
});
}
} }
Accessor::TupleAttr(t_attr) => { Accessor::TupleAttr(t_attr) => {
self.codegen_expr(*t_attr.obj); self.codegen_expr(*t_attr.obj);
@ -1297,6 +1411,7 @@ impl CodeGenerator {
/// forブロックなどで使う /// forブロックなどで使う
fn codegen_frameless_block(&mut self, block: Block, params: Vec<Str>) { fn codegen_frameless_block(&mut self, block: Block, params: Vec<Str>) {
log!(info "entered {}", fn_name!());
for param in params { for param in params {
self.emit_store_instr(Identifier::private(param), Name); self.emit_store_instr(Identifier::private(param), Name);
} }
@ -1311,23 +1426,50 @@ impl CodeGenerator {
self.cancel_pop_top(); self.cancel_pop_top();
} }
fn codegen_typedef_block(&mut self, name: Str, block: Block) -> CodeObj { fn codegen_typedef_block(&mut self, class: ClassDef) -> CodeObj {
log!(info "entered {}", fn_name!());
let name = class.sig.ident().inspect().clone();
self.unit_size += 1; self.unit_size += 1;
let firstlineno = match (
class.private_methods.get(0).and_then(|def| def.ln_begin()),
class.public_methods.get(0).and_then(|def| def.ln_begin()),
) {
(Some(l), Some(r)) => l.min(r),
(Some(line), None) | (None, Some(line)) => line,
(None, None) => class.sig.ln_begin().unwrap(),
};
self.units.push(CodeGenUnit::new( self.units.push(CodeGenUnit::new(
self.unit_size, self.unit_size,
vec![], vec![],
Str::rc(self.cfg.input.enclosed_name()), Str::rc(self.cfg.input.enclosed_name()),
&name, &name,
block[0].ln_begin().unwrap(), firstlineno,
)); ));
let mod_name = self.toplevel_block_codeobj().name.clone(); let mod_name = self.toplevel_block_codeobj().name.clone();
self.emit_load_const(mod_name); self.emit_load_const(mod_name);
self.emit_store_instr(Identifier::public("__module__"), Attr); self.emit_store_instr(Identifier::public("__module__"), Name);
self.emit_load_const(name); self.emit_load_const(name.clone());
self.emit_store_instr(Identifier::public("__qualname__"), Attr); self.emit_store_instr(Identifier::public("__qualname__"), Name);
// TODO: サブルーチンはT.subという書式でSTORE self.emit_init_method(&class.sig, class.__new__.clone());
for expr in block.into_iter() { if class.need_to_gen_new {
self.codegen_expr(expr); self.emit_new_func(&class.sig, class.__new__);
}
for def in class.private_methods.into_iter() {
match def.sig {
Signature::Subr(sig) => self.emit_subr_def(Some(&name[..]), sig, def.body),
Signature::Var(sig) => self.emit_var_def(sig, def.body),
}
// TODO: discard
if self.cur_block().stack_len == 1 {
self.emit_pop_top();
}
}
for mut def in class.public_methods.into_iter() {
def.sig.ident_mut().dot = Some(Token::dummy());
match def.sig {
Signature::Subr(sig) => self.emit_subr_def(Some(&name[..]), sig, def.body),
Signature::Var(sig) => self.emit_var_def(sig, def.body),
}
// TODO: discard // TODO: discard
if self.cur_block().stack_len == 1 { if self.cur_block().stack_len == 1 {
self.emit_pop_top(); self.emit_pop_top();
@ -1366,7 +1508,102 @@ impl CodeGenerator {
unit.codeobj unit.codeobj
} }
fn emit_init_method(&mut self, sig: &Signature, __new__: Type) {
log!(info "entered {}", fn_name!());
let line = sig.ln_begin().unwrap();
let class_name = sig.ident().inspect();
let ident = Identifier::public_with_line(Token::dummy(), Str::ever("__init__"), line);
let param_name = fresh_varname();
let param = VarName::from_str_and_line(Str::from(param_name.clone()), line);
let param = ParamSignature::new(ParamPattern::VarName(param), None, None);
let self_param = VarName::from_str_and_line(Str::ever("self"), line);
let self_param = ParamSignature::new(ParamPattern::VarName(self_param), None, None);
let params = Params::new(vec![self_param, param], None, vec![], None);
let subr_sig = SubrSignature::new(ident, params.clone(), __new__.clone());
let mut attrs = vec![];
match __new__.non_default_params().unwrap()[0].typ() {
// namedtupleは仕様上::xなどの名前を使えない
// {x = Int; y = Int}
// => self::x = %x.x; self::y = %x.y
// {.x = Int; .y = Int}
// => self.x = %x.x; self.y = %x.y
Type::Record(rec) => {
for field in rec.keys() {
let obj =
Expr::Accessor(Accessor::private_with_line(Str::from(&param_name), line));
let expr = Expr::Accessor(Accessor::Attr(Attribute::new(
obj,
Identifier::bare(
Some(Token::dummy()),
VarName::from_str(field.symbol.clone()),
),
Type::Failure,
)));
let obj = Expr::Accessor(Accessor::private_with_line(Str::ever("self"), line));
let dot = if field.vis.is_private() {
None
} else {
Some(Token::dummy())
};
let attr = Accessor::Attr(Attribute::new(
obj,
Identifier::bare(dot, VarName::from_str(field.symbol.clone())),
Type::Failure,
));
let attr_def = AttrDef::new(attr, Block::new(vec![expr]));
attrs.push(Expr::AttrDef(attr_def));
}
let none = Token::new(TokenKind::NoneLit, "None", line, 0);
attrs.push(Expr::Lit(Literal::from(none)));
}
other => todo!("{other}"),
}
let block = Block::new(attrs);
let body = DefBody::new(Token::dummy(), block, DefId(0));
self.emit_subr_def(Some(class_name), subr_sig, body);
}
/// ```python
/// class C:
/// # __new__ => __call__
/// def new(x): return C.__call__(x)
/// ```
fn emit_new_func(&mut self, sig: &Signature, __new__: Type) {
log!(info "entered {}", fn_name!());
let class_name = sig.ident().inspect();
let line = sig.ln_begin().unwrap();
let ident = Identifier::public_with_line(Token::dummy(), Str::ever("new"), line);
let param_name = fresh_varname();
let param = VarName::from_str_and_line(Str::from(param_name.clone()), line);
let param = ParamSignature::new(ParamPattern::VarName(param), None, None);
let sig = SubrSignature::new(
ident,
Params::new(vec![param], None, vec![], None),
__new__.clone(),
);
let arg = PosArg::new(Expr::Accessor(Accessor::private_with_line(
Str::from(param_name),
line,
)));
let class = Expr::Accessor(Accessor::private_with_line(class_name.clone(), line));
let class_new = Expr::Accessor(Accessor::attr(
class,
Identifier::bare(None, VarName::from_str_and_line(Str::ever("__new__"), line)),
Type::Failure,
));
let call = Expr::Call(Call::new(
class_new,
None,
Args::new(vec![arg], None, vec![], None),
Type::Failure,
));
let block = Block::new(vec![call]);
let body = DefBody::new(Token::dummy(), block, DefId(0));
self.emit_subr_def(Some(&class_name[..]), sig, body);
}
fn codegen_block(&mut self, block: Block, opt_name: Option<Str>, params: Vec<Str>) -> CodeObj { fn codegen_block(&mut self, block: Block, opt_name: Option<Str>, params: Vec<Str>) -> CodeObj {
log!(info "entered {}", fn_name!());
self.unit_size += 1; self.unit_size += 1;
let name = if let Some(name) = opt_name { let name = if let Some(name) = opt_name {
name name
@ -1414,7 +1651,10 @@ impl CodeGenerator {
// end of flagging // end of flagging
let unit = self.units.pop().unwrap(); let unit = self.units.pop().unwrap();
if !self.units.is_empty() { if !self.units.is_empty() {
let ld = unit.prev_lineno - self.cur_block().prev_lineno; let ld = unit
.prev_lineno
.checked_sub(self.cur_block().prev_lineno)
.unwrap_or(0);
if ld != 0 { if ld != 0 {
if let Some(l) = self.mut_cur_block_codeobj().lnotab.last_mut() { if let Some(l) = self.mut_cur_block_codeobj().lnotab.last_mut() {
*l += ld as u8; *l += ld as u8;
@ -1425,6 +1665,25 @@ impl CodeGenerator {
unit.codeobj unit.codeobj
} }
fn load_prelude(&mut self) {
self.init_record();
}
fn init_record(&mut self) {
// importing namedtuple
self.emit_load_const(0);
self.emit_load_const(ValueObj::Tuple(std::rc::Rc::from([ValueObj::Str(
Str::ever("namedtuple"),
)])));
let ident = Identifier::public("collections");
self.emit_import_name_instr(ident).unwrap();
let ident = Identifier::public("namedtuple");
self.emit_import_from_instr(ident).unwrap();
let ident = Identifier::private(Str::ever("#NamedTuple"));
self.emit_store_instr(ident, Name);
// self.namedtuple_loaded = true;
}
pub fn codegen(&mut self, hir: HIR) -> CodeObj { pub fn codegen(&mut self, hir: HIR) -> CodeObj {
log!(info "the code-generating process has started.{RESET}"); log!(info "the code-generating process has started.{RESET}");
self.unit_size += 1; self.unit_size += 1;
@ -1435,6 +1694,10 @@ impl CodeGenerator {
"<module>", "<module>",
1, 1,
)); ));
if !self.prelude_loaded {
self.load_prelude();
self.prelude_loaded = true;
}
let mut print_point = 0; let mut print_point = 0;
if self.input().is_repl() { if self.input().is_repl() {
print_point = self.cur_block().lasti; print_point = self.cur_block().lasti;

View file

@ -15,6 +15,7 @@ use erg_parser::ParserRunner;
use crate::codegen::CodeGenerator; use crate::codegen::CodeGenerator;
use crate::effectcheck::SideEffectChecker; use crate::effectcheck::SideEffectChecker;
use crate::error::{CompileError, CompileErrors, TyCheckErrors}; use crate::error::{CompileError, CompileErrors, TyCheckErrors};
use crate::link::Linker;
use crate::lower::ASTLowerer; use crate::lower::ASTLowerer;
use crate::ownercheck::OwnershipChecker; use crate::ownercheck::OwnershipChecker;
@ -158,11 +159,13 @@ impl Compiler {
} }
pub fn compile(&mut self, src: Str, mode: &str) -> Result<CodeObj, CompileErrors> { pub fn compile(&mut self, src: Str, mode: &str) -> Result<CodeObj, CompileErrors> {
log!(info "the compiling process has started"); log!(info "the compiling process has started.");
let mut cfg = self.cfg.copy(); let mut cfg = self.cfg.copy();
cfg.input = Input::Str(src); cfg.input = Input::Str(src);
let mut parser = ParserRunner::new(cfg); let mut parser = ParserRunner::new(cfg);
let ast = parser.parse()?; let ast = parser.parse()?;
let linker = Linker::new();
let ast = linker.link(ast).map_err(|errs| self.convert(errs))?;
let (hir, warns) = self let (hir, warns) = self
.lowerer .lowerer
.lower(ast, mode) .lower(ast, mode)
@ -182,8 +185,7 @@ impl Compiler {
let codeobj = self.code_generator.codegen(hir); let codeobj = self.code_generator.codegen(hir);
log!(info "code object:\n{}", codeobj.code_info()); log!(info "code object:\n{}", codeobj.code_info());
log!( log!(
c GREEN, info "the compiling process has completed, found errors: {}",
"the compiling process has completed, found errors: {}",
self.code_generator.errs.len() self.code_generator.errs.len()
); );
if self.code_generator.errs.is_empty() { if self.code_generator.errs.is_empty() {

View file

@ -1,7 +1,7 @@
//! provides type-comparison //! provides type-comparison
use std::option::Option; // conflicting to Type::Option use std::option::Option; // conflicting to Type::Option
use erg_type::constructors::or; use erg_type::constructors::{and, or};
use erg_type::free::fresh_varname; use erg_type::free::fresh_varname;
use erg_type::free::{Constraint, Cyclicity, FreeKind, FreeTyVar}; use erg_type::free::{Constraint, Cyclicity, FreeKind, FreeTyVar};
use erg_type::typaram::{TyParam, TyParamOrdering}; use erg_type::typaram::{TyParam, TyParamOrdering};
@ -50,9 +50,7 @@ impl Context {
pub(crate) fn eq_tp(&self, lhs: &TyParam, rhs: &TyParam) -> bool { pub(crate) fn eq_tp(&self, lhs: &TyParam, rhs: &TyParam) -> bool {
match (lhs, rhs) { match (lhs, rhs) {
(TyParam::Type(lhs), TyParam::Type(rhs)) => { (TyParam::Type(lhs), TyParam::Type(rhs)) => return self.same_type_of(lhs, rhs),
return self.structural_same_type_of(lhs, rhs)
}
(TyParam::Mono(l), TyParam::Mono(r)) => { (TyParam::Mono(l), TyParam::Mono(r)) => {
if let (Some(l), Some(r)) = (self.rec_get_const_obj(l), self.rec_get_const_obj(r)) { if let (Some(l), Some(r)) = (self.rec_get_const_obj(l), self.rec_get_const_obj(r)) {
return l == r; return l == r;
@ -61,6 +59,23 @@ impl Context {
(TyParam::MonoQVar(name), _other) | (_other, TyParam::MonoQVar(name)) => { (TyParam::MonoQVar(name), _other) | (_other, TyParam::MonoQVar(name)) => {
panic!("Not instantiated type parameter: {name}") panic!("Not instantiated type parameter: {name}")
} }
(TyParam::UnaryOp { op: lop, val: lval }, TyParam::UnaryOp { op: rop, val: rval }) => {
return lop == rop && self.eq_tp(lval, rval);
}
(
TyParam::BinOp {
op: lop,
lhs: ll,
rhs: lr,
},
TyParam::BinOp {
op: rop,
lhs: rl,
rhs: rr,
},
) => {
return lop == rop && self.eq_tp(ll, rl) && self.eq_tp(lr, rr);
}
( (
TyParam::App { TyParam::App {
name: ln, name: ln,
@ -80,19 +95,21 @@ impl Context {
} }
(TyParam::FreeVar(fv), other) | (other, TyParam::FreeVar(fv)) => match &*fv.borrow() { (TyParam::FreeVar(fv), other) | (other, TyParam::FreeVar(fv)) => match &*fv.borrow() {
FreeKind::Linked(t) | FreeKind::UndoableLinked { t, .. } => { FreeKind::Linked(t) | FreeKind::UndoableLinked { t, .. } => {
return self.eq_tp(t, other) return self.eq_tp(t, other);
} }
FreeKind::Unbound { constraint, .. } FreeKind::Unbound { constraint, .. }
| FreeKind::NamedUnbound { constraint, .. } => { | FreeKind::NamedUnbound { constraint, .. } => {
let t = constraint.get_type().unwrap(); let t = constraint.get_type().unwrap();
let other_t = self.type_of(other); let other_t = self.type_of(other);
return self.structural_supertype_of(t, &other_t); return self.same_type_of(t, &other_t);
} }
}, },
(l, r) if l == r => return true, (l, r) if l == r => {
return true;
}
_ => {} _ => {}
} }
self.eval.shallow_eq_tp(lhs, rhs, self) self.shallow_eq_tp(lhs, rhs)
} }
/// e.g. /// e.g.
@ -144,14 +161,18 @@ impl Context {
} }
} }
pub(crate) fn same_type_of(&self, lhs: &Type, rhs: &Type) -> bool {
self.supertype_of(lhs, rhs) && self.subtype_of(lhs, rhs)
}
pub(crate) fn cheap_supertype_of(&self, lhs: &Type, rhs: &Type) -> (Credibility, bool) { pub(crate) fn cheap_supertype_of(&self, lhs: &Type, rhs: &Type) -> (Credibility, bool) {
if lhs == rhs { if lhs == rhs {
return (Absolutely, true); return (Absolutely, true);
} }
match (lhs, rhs) { match (lhs, rhs) {
// FIXME: Obj/Neverはクラス、Top/Bottomは構造型
(Obj, _) | (_, Never) => (Absolutely, true), (Obj, _) | (_, Never) => (Absolutely, true),
(_, Obj) | (Never, _) => (Absolutely, false), // (_, Obj) if !lhs.is_unbound_var() => (Absolutely, false),
// (Never, _) if !rhs.is_unbound_var() => (Absolutely, false),
(Float | Ratio | Int | Nat | Bool, Bool) (Float | Ratio | Int | Nat | Bool, Bool)
| (Float | Ratio | Int | Nat, Nat) | (Float | Ratio | Int | Nat, Nat)
| (Float | Ratio | Int, Int) | (Float | Ratio | Int, Int)
@ -164,14 +185,9 @@ impl Context {
), ),
(Type, Subr(subr)) => ( (Type, Subr(subr)) => (
Absolutely, Absolutely,
subr.kind subr.non_default_params
.self_t() .iter()
.map(|t| self.supertype_of(&Type, t)) .all(|pt| self.supertype_of(&Type, &pt.typ()))
.unwrap_or(true)
&& subr
.non_default_params
.iter()
.all(|pt| self.supertype_of(&Type, &pt.typ()))
&& subr && subr
.default_params .default_params
.iter() .iter()
@ -184,44 +200,30 @@ impl Context {
&& self.supertype_of(&Type, &subr.return_t), && self.supertype_of(&Type, &subr.return_t),
), ),
( (
Type::MonoClass(n), Type::Mono(n),
Subr(SubrType { Subr(SubrType {
kind: SubrKind::Func, kind: SubrKind::Func,
.. ..
}), }),
) if &n[..] == "GenericFunc" => (Absolutely, true), ) if &n[..] == "GenericFunc" => (Absolutely, true),
( (
Type::MonoClass(n), Type::Mono(n),
Subr(SubrType { Subr(SubrType {
kind: SubrKind::Proc, kind: SubrKind::Proc,
.. ..
}), }),
) if &n[..] == "GenericProc" => (Absolutely, true), ) if &n[..] == "GenericProc" => (Absolutely, true),
( (Type::Mono(l), Type::Poly { name: r, .. })
Type::MonoClass(n),
Subr(SubrType {
kind: SubrKind::FuncMethod(_),
..
}),
) if &n[..] == "GenericFuncMethod" => (Absolutely, true),
(
Type::MonoClass(n),
Subr(SubrType {
kind: SubrKind::ProcMethod { .. },
..
}),
) if &n[..] == "GenericProcMethod" => (Absolutely, true),
(Type::MonoClass(l), Type::PolyClass { name: r, .. })
if &l[..] == "GenericArray" && &r[..] == "Array" => if &l[..] == "GenericArray" && &r[..] == "Array" =>
{ {
(Absolutely, true) (Absolutely, true)
} }
(Type::MonoClass(l), Type::PolyClass { name: r, .. }) (Type::Mono(l), Type::Poly { name: r, .. })
if &l[..] == "GenericDict" && &r[..] == "Dict" => if &l[..] == "GenericDict" && &r[..] == "Dict" =>
{ {
(Absolutely, true) (Absolutely, true)
} }
(Type::MonoClass(l), Type::MonoClass(r)) (Type::Mono(l), Type::Mono(r))
if &l[..] == "GenericCallable" if &l[..] == "GenericCallable"
&& (&r[..] == "GenericFunc" && (&r[..] == "GenericFunc"
|| &r[..] == "GenericProc" || &r[..] == "GenericProc"
@ -230,11 +232,11 @@ impl Context {
{ {
(Absolutely, true) (Absolutely, true)
} }
(_, Type::FreeVar(fv)) | (Type::FreeVar(fv), _) => match fv.crack_bound_types() { (_, Type::FreeVar(fv)) | (Type::FreeVar(fv), _) => match fv.get_bound_types() {
Some((Type::Never, Type::Obj)) => (Absolutely, true), Some((Type::Never, Type::Obj)) => (Absolutely, true),
_ => (Maybe, false), _ => (Maybe, false),
}, },
(Type::MonoClass(n), Subr(_)) if &n[..] == "GenericCallable" => (Absolutely, true), (Type::Mono(n), Subr(_)) if &n[..] == "GenericCallable" => (Absolutely, true),
(lhs, rhs) if lhs.is_simple_class() && rhs.is_simple_class() => (Absolutely, false), (lhs, rhs) if lhs.is_simple_class() && rhs.is_simple_class() => (Absolutely, false),
_ => (Maybe, false), _ => (Maybe, false),
} }
@ -258,7 +260,7 @@ impl Context {
} }
_ => {} _ => {}
} }
match self.trait_supertype_of(lhs, rhs) { match self.traits_supertype_of(lhs, rhs) {
(Absolutely, judge) => { (Absolutely, judge) => {
self.register_cache(rhs, lhs, judge); self.register_cache(rhs, lhs, judge);
return judge; return judge;
@ -292,20 +294,19 @@ impl Context {
} }
fn classes_supertype_of(&self, lhs: &Type, rhs: &Type) -> (Credibility, bool) { fn classes_supertype_of(&self, lhs: &Type, rhs: &Type) -> (Credibility, bool) {
if !lhs.is_class() || !rhs.is_class() { if let Some(sup_classes) = self.rec_get_nominal_super_class_ctxs(rhs) {
return (Maybe, false); for (rhs_sup, _) in sup_classes {
} match self.cheap_supertype_of(lhs, rhs_sup) {
for (rhs_sup, _) in self.rec_get_nominal_super_class_ctxs(rhs) { (Absolutely, true) => {
match self.cheap_supertype_of(lhs, rhs_sup) {
(Absolutely, true) => {
return (Absolutely, true);
}
(Maybe, _) => {
if self.structural_supertype_of(lhs, rhs_sup) {
return (Absolutely, true); return (Absolutely, true);
} }
(Maybe, _) => {
if self.structural_supertype_of(lhs, rhs_sup) {
return (Absolutely, true);
}
}
_ => {}
} }
_ => {}
} }
} }
(Maybe, false) (Maybe, false)
@ -313,22 +314,21 @@ impl Context {
// e.g. Eq(Nat) :> Nat // e.g. Eq(Nat) :> Nat
// Nat.super_traits = [Add(Nat), Eq(Nat), ...] // Nat.super_traits = [Add(Nat), Eq(Nat), ...]
fn trait_supertype_of(&self, lhs: &Type, rhs: &Type) -> (Credibility, bool) { fn traits_supertype_of(&self, lhs: &Type, rhs: &Type) -> (Credibility, bool) {
if !lhs.is_trait() { if let Some(sup_traits) = self.rec_get_nominal_super_trait_ctxs(rhs) {
return (Maybe, false); for (rhs_sup, _) in sup_traits {
} match self.cheap_supertype_of(lhs, rhs_sup) {
for (rhs_sup, _) in self.rec_get_nominal_super_trait_ctxs(rhs) { (Absolutely, true) => {
match self.cheap_supertype_of(lhs, rhs_sup) {
(Absolutely, true) => {
return (Absolutely, true);
}
(Maybe, _) => {
// nominal type同士の比較なので、nominal_supertype_ofは使わない
if self.structural_supertype_of(lhs, rhs_sup) {
return (Absolutely, true); return (Absolutely, true);
} }
(Maybe, _) => {
// nominal type同士の比較なので、nominal_supertype_ofは使わない
if self.structural_supertype_of(lhs, rhs_sup) {
return (Absolutely, true);
}
}
_ => {}
} }
_ => {}
} }
} }
(Maybe, false) (Maybe, false)
@ -339,7 +339,7 @@ impl Context {
/// assert sup_conforms(?E(<: Eq(?R)), base: T, sup_trait: Eq(U)) /// assert sup_conforms(?E(<: Eq(?R)), base: T, sup_trait: Eq(U))
/// ``` /// ```
fn sup_conforms(&self, free: &FreeTyVar, base: &Type, sup_trait: &Type) -> bool { fn sup_conforms(&self, free: &FreeTyVar, base: &Type, sup_trait: &Type) -> bool {
let (_sub, sup) = free.crack_bound_types().unwrap(); let (_sub, sup) = free.get_bound_types().unwrap();
free.forced_undoable_link(base); free.forced_undoable_link(base);
let judge = self.supertype_of(&sup, sup_trait); let judge = self.supertype_of(&sup, sup_trait);
free.undo(); free.undo();
@ -349,7 +349,7 @@ impl Context {
/// assert!(sup_conforms(?E(<: Eq(?E)), {Nat, Eq(Nat)})) /// assert!(sup_conforms(?E(<: Eq(?E)), {Nat, Eq(Nat)}))
/// assert!(sup_conforms(?E(<: Eq(?R)), {Nat, Eq(T)})) /// assert!(sup_conforms(?E(<: Eq(?R)), {Nat, Eq(T)}))
fn _sub_conforms(&self, free: &FreeTyVar, inst_pair: &TraitInstance) -> bool { fn _sub_conforms(&self, free: &FreeTyVar, inst_pair: &TraitInstance) -> bool {
let (_sub, sup) = free.crack_bound_types().unwrap(); let (_sub, sup) = free.get_bound_types().unwrap();
log!(info "{free}"); log!(info "{free}");
free.forced_undoable_link(&inst_pair.sub_type); free.forced_undoable_link(&inst_pair.sub_type);
log!(info "{free}"); log!(info "{free}");
@ -371,7 +371,7 @@ impl Context {
pub(crate) fn structural_supertype_of(&self, lhs: &Type, rhs: &Type) -> bool { pub(crate) fn structural_supertype_of(&self, lhs: &Type, rhs: &Type) -> bool {
log!(info "structural_supertype_of:\nlhs: {lhs}\nrhs: {rhs}"); log!(info "structural_supertype_of:\nlhs: {lhs}\nrhs: {rhs}");
match (lhs, rhs) { match (lhs, rhs) {
(Subr(ls), Subr(rs)) if ls.kind.same_kind_as(&rs.kind) => { (Subr(ls), Subr(rs)) if ls.kind == rs.kind => {
let kw_check = || { let kw_check = || {
for lpt in ls.default_params.iter() { for lpt in ls.default_params.iter() {
if let Some(rpt) = rs if let Some(rpt) = rs
@ -388,9 +388,6 @@ impl Context {
} }
true true
}; };
if ls.kind.self_t().is_some() {
todo!("method type is not supported yet")
}
// () -> Never <: () -> Int <: () -> Object // () -> Never <: () -> Int <: () -> Object
// (Object) -> Int <: (Int) -> Int <: (Never) -> Int // (Object) -> Int <: (Int) -> Int <: (Never) -> Int
ls.non_default_params.len() == rs.non_default_params.len() ls.non_default_params.len() == rs.non_default_params.len()
@ -405,24 +402,20 @@ impl Context {
&& kw_check() && kw_check()
// contravariant // contravariant
} }
// RefMut, OptionMut are invariant
(Ref(lhs), Ref(rhs)) => self.supertype_of(lhs, rhs),
// ?T(<: Nat) !:> ?U(:> Int) // ?T(<: Nat) !:> ?U(:> Int)
// ?T(<: Nat) :> ?U(<: Int) (?U can be smaller than ?T) // ?T(<: Nat) :> ?U(<: Int) (?U can be smaller than ?T)
(FreeVar(lfv), FreeVar(rfv)) => { (FreeVar(lfv), FreeVar(rfv)) => match (lfv.get_bound_types(), rfv.get_bound_types()) {
match (lfv.crack_bound_types(), rfv.crack_bound_types()) { (Some((_, l_sup)), Some((r_sub, _))) => self.supertype_of(&l_sup, &r_sub),
(Some((_, l_sup)), Some((r_sub, _))) => self.supertype_of(&l_sup, &r_sub), _ => {
_ => { if lfv.is_linked() {
if lfv.is_linked() { self.supertype_of(&lfv.crack(), rhs)
self.supertype_of(&lfv.crack(), rhs) } else if rfv.is_linked() {
} else if rfv.is_linked() { self.supertype_of(lhs, &rfv.crack())
self.supertype_of(lhs, &rfv.crack()) } else {
} else { false
false
}
} }
} }
} },
// true if it can be a supertype, false if it cannot (due to type constraints) // true if it can be a supertype, false if it cannot (due to type constraints)
// No type constraints are imposed here, as subsequent type decisions are made according to the possibilities // No type constraints are imposed here, as subsequent type decisions are made according to the possibilities
(FreeVar(lfv), rhs) => { (FreeVar(lfv), rhs) => {
@ -496,7 +489,18 @@ impl Context {
} }
true true
} }
// (MonoQuantVar(_), _) | (_, MonoQuantVar(_)) => true, (Type::Record(lhs), Type::Record(rhs)) => {
for (k, l) in lhs.iter() {
if let Some(r) = rhs.get(k) {
if !self.supertype_of(l, r) {
return false;
}
} else {
return false;
}
}
true
}
// REVIEW: maybe this is incomplete // REVIEW: maybe this is incomplete
// ({I: Int | I >= 0} :> {N: Int | N >= 0}) == true, // ({I: Int | I >= 0} :> {N: Int | N >= 0}) == true,
// ({I: Int | I >= 0} :> {I: Int | I >= 1}) == true, // ({I: Int | I >= 0} :> {I: Int | I >= 1}) == true,
@ -571,30 +575,18 @@ impl Context {
} }
(_lhs, Not(_, _)) => todo!(), (_lhs, Not(_, _)) => todo!(),
(Not(_, _), _rhs) => todo!(), (Not(_, _), _rhs) => todo!(),
// RefMut are invariant
(Ref(l), Ref(r)) => self.supertype_of(l, r),
// TはすべてのRef(T)のメソッドを持つので、Ref(T)のサブタイプ // TはすべてのRef(T)のメソッドを持つので、Ref(T)のサブタイプ
// REVIEW: RefMut is invariant, maybe // REVIEW: RefMut is invariant, maybe
(Ref(lhs), rhs) | (RefMut(lhs), rhs) => self.supertype_of(lhs, rhs), (Ref(l), r) => self.supertype_of(l, r),
(RefMut { before: l, .. }, r) => self.supertype_of(l, r),
( (
PolyClass { Poly {
name: ln, name: ln,
params: lparams, params: lparams,
}, },
PolyClass { Poly {
name: rn,
params: rparams,
},
) => {
if ln != rn || lparams.len() != rparams.len() {
return false;
}
self.poly_supertype_of(lhs, lparams, rparams)
}
(
PolyTrait {
name: ln,
params: lparams,
},
PolyTrait {
name: rn, name: rn,
params: rparams, params: rparams,
}, },
@ -619,15 +611,18 @@ 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 {
// if `rhs` is {S: Str | ... }, `defined_rhs` will be Str // if `rhs` is {S: Str | ... }, `defined_rhs` will be Str
let (defined_rhs, _) = self.rec_get_nominal_type_ctx(rhs).unwrap(); let (defined_rhs, _) = self.rec_get_nominal_type_ctx(rhs).unwrap();
let super_traits = self.rec_get_nominal_super_trait_ctxs(rhs); if let Some(super_traits) = self.rec_get_nominal_super_trait_ctxs(rhs) {
for (sup_trait, _) in super_traits.into_iter() { for (sup_trait, _) in super_traits {
if self.sup_conforms(lhs, defined_rhs, sup_trait) { if self.sup_conforms(lhs, defined_rhs, sup_trait) {
return true; return true;
}
} }
} }
for (sup_class, _) in self.rec_get_nominal_super_class_ctxs(rhs) { if let Some(sup_classes) = self.rec_get_nominal_super_class_ctxs(rhs) {
if self.cyclic_supertype_of(lhs, sup_class) { for (sup_class, _) in sup_classes {
return true; if self.cyclic_supertype_of(lhs, sup_class) {
return true;
}
} }
} }
false false
@ -666,7 +661,7 @@ impl Context {
self.structural_supertype_of(rhs, lhs) self.structural_supertype_of(rhs, lhs)
} }
pub(crate) fn structural_same_type_of(&self, lhs: &Type, rhs: &Type) -> bool { pub(crate) fn _structural_same_type_of(&self, lhs: &Type, rhs: &Type) -> bool {
self.structural_supertype_of(lhs, rhs) && self.structural_subtype_of(lhs, rhs) self.structural_supertype_of(lhs, rhs) && self.structural_subtype_of(lhs, rhs)
} }
@ -676,7 +671,7 @@ impl Context {
l.try_cmp(r).map(Into::into), l.try_cmp(r).map(Into::into),
// TODO: 型を見て判断する // TODO: 型を見て判断する
(TyParam::BinOp{ op, lhs, rhs }, r) => { (TyParam::BinOp{ op, lhs, rhs }, r) => {
if let Ok(l) = self.eval.eval_bin_tp(*op, lhs, rhs) { if let Ok(l) = self.eval_bin_tp(*op, lhs, rhs) {
self.rec_try_cmp(&l, r) self.rec_try_cmp(&l, r)
} else { Some(Any) } } else { Some(Any) }
}, },
@ -690,8 +685,8 @@ impl Context {
l @ (TyParam::FreeVar(_) | TyParam::Erased(_) | TyParam::MonoQVar(_)), l @ (TyParam::FreeVar(_) | TyParam::Erased(_) | TyParam::MonoQVar(_)),
r @ (TyParam::FreeVar(_) | TyParam::Erased(_) | TyParam::MonoQVar(_)), r @ (TyParam::FreeVar(_) | TyParam::Erased(_) | TyParam::MonoQVar(_)),
) /* if v.is_unbound() */ => { ) /* if v.is_unbound() */ => {
let l_t = self.eval.get_tp_t(l, self).unwrap(); let l_t = self.get_tp_t(l).unwrap();
let r_t = self.eval.get_tp_t(r, self).unwrap(); let r_t = self.get_tp_t(r).unwrap();
if self.rec_supertype_of(&l_t, &r_t) || self.rec_subtype_of(&l_t, &r_t) { if self.rec_supertype_of(&l_t, &r_t) || self.rec_subtype_of(&l_t, &r_t) {
Some(Any) Some(Any)
} else { Some(NotEqual) } } else { Some(NotEqual) }
@ -702,7 +697,7 @@ impl Context {
// try_cmp((n: 2.._), 1) -> Some(Greater) // try_cmp((n: 2.._), 1) -> Some(Greater)
// try_cmp((n: -1.._), 1) -> Some(Any) // try_cmp((n: -1.._), 1) -> Some(Any)
(l @ (TyParam::Erased(_) | TyParam::FreeVar(_) | TyParam::MonoQVar(_)), p) => { (l @ (TyParam::Erased(_) | TyParam::FreeVar(_) | TyParam::MonoQVar(_)), p) => {
let t = self.eval.get_tp_t(l, self).unwrap(); let t = self.get_tp_t(l).unwrap();
let inf = self.rec_inf(&t); let inf = self.rec_inf(&t);
let sup = self.rec_sup(&t); let sup = self.rec_sup(&t);
if let (Some(inf), Some(sup)) = (inf, sup) { if let (Some(inf), Some(sup)) = (inf, sup) {
@ -772,7 +767,7 @@ impl Context {
} }
} }
/// 和集合(A or B)を返す /// returns union of two types (A or B)
pub(crate) fn rec_union(&self, lhs: &Type, rhs: &Type) -> Type { pub(crate) fn rec_union(&self, lhs: &Type, rhs: &Type) -> Type {
match ( match (
self.rec_supertype_of(lhs, rhs), self.rec_supertype_of(lhs, rhs),
@ -814,6 +809,28 @@ impl Context {
} }
} }
/// returns intersection of two types (A and B)
pub(crate) fn rec_intersection(&self, lhs: &Type, rhs: &Type) -> Type {
match (
self.rec_supertype_of(lhs, rhs),
self.rec_subtype_of(lhs, rhs),
) {
(true, true) => return lhs.clone(), // lhs = rhs
(true, false) => return rhs.clone(), // lhs :> rhs
(false, true) => return lhs.clone(),
(false, false) => {}
}
match (lhs, rhs) {
/*(Type::FreeVar(_), _) | (_, Type::FreeVar(_)) => {
todo!()
}*/
// {.i = Int} and {.s = Str} == {.i = Int; .s = Str}
(Type::Record(l), Type::Record(r)) => Type::Record(l.clone().concat(r.clone())),
(l, r) if self.is_trait(l) && self.is_trait(r) => and(l.clone(), r.clone()),
(_l, _r) => Type::Never,
}
}
/// see doc/LANG/compiler/refinement_subtyping.md /// see doc/LANG/compiler/refinement_subtyping.md
/// ```python /// ```python
/// assert is_super_pred({I >= 0}, {I == 0}) /// assert is_super_pred({I >= 0}, {I == 0})
@ -888,7 +905,7 @@ impl Context {
#[inline] #[inline]
fn type_of(&self, p: &TyParam) -> Type { fn type_of(&self, p: &TyParam) -> Type {
self.eval.get_tp_t(p, self).unwrap() self.get_tp_t(p).unwrap()
} }
// sup/inf({±∞}) = ±∞ではあるが、Inf/NegInfにはOrdを実装しない // sup/inf({±∞}) = ±∞ではあるが、Inf/NegInfにはOrdを実装しない

View file

@ -3,21 +3,19 @@ use std::mem;
use erg_common::dict::Dict; use erg_common::dict::Dict;
use erg_common::rccell::RcCell; use erg_common::rccell::RcCell;
use erg_common::set::Set; use erg_common::set::Set;
use erg_common::traits::Stream; use erg_common::traits::{Locational, Stream};
use erg_common::vis::Field; use erg_common::vis::Field;
use erg_common::{fn_name, set}; use erg_common::{dict, fn_name, option_enum_unwrap, set};
use erg_common::{RcArray, Str}; use erg_common::{RcArray, Str};
use OpKind::*; use OpKind::*;
use erg_parser::ast::*; use erg_parser::ast::*;
use erg_parser::token::{Token, TokenKind}; use erg_parser::token::{Token, TokenKind};
use erg_type::constructors::{ use erg_type::constructors::{enum_t, mono, mono_proj, poly, ref_, ref_mut, refinement, subr_t};
enum_t, mono_proj, poly_class, poly_trait, ref_, ref_mut, refinement, subr_t,
};
use erg_type::typaram::{OpKind, TyParam}; use erg_type::typaram::{OpKind, TyParam};
use erg_type::value::ValueObj; use erg_type::value::ValueObj;
use erg_type::{Predicate, SubrKind, TyBound, Type}; use erg_type::{HasType, Predicate, TyBound, Type, ValueArgs};
use crate::context::instantiate::TyVarContext; use crate::context::instantiate::TyVarContext;
use crate::context::Context; use crate::context::Context;
@ -41,7 +39,7 @@ pub fn type_from_token_kind(kind: TokenKind) -> Type {
} }
} }
fn try_get_op_kind_from_token(kind: TokenKind) -> Result<OpKind, ()> { fn try_get_op_kind_from_token(kind: TokenKind) -> EvalResult<OpKind> {
match kind { match kind {
TokenKind::Plus => Ok(OpKind::Add), TokenKind::Plus => Ok(OpKind::Add),
TokenKind::Minus => Ok(OpKind::Sub), TokenKind::Minus => Ok(OpKind::Sub),
@ -63,7 +61,7 @@ fn try_get_op_kind_from_token(kind: TokenKind) -> Result<OpKind, ()> {
TokenKind::Shl => Ok(OpKind::Shl), TokenKind::Shl => Ok(OpKind::Shl),
TokenKind::Shr => Ok(OpKind::Shr), TokenKind::Shr => Ok(OpKind::Shr),
TokenKind::Mutate => Ok(OpKind::Mutate), TokenKind::Mutate => Ok(OpKind::Mutate),
_other => Err(()), _other => todo!("{_other}"),
} }
} }
@ -165,150 +163,243 @@ impl SubstContext {
} }
} }
#[derive(Debug, Default)] impl Context {
pub struct Evaluator {} fn eval_const_acc(&self, acc: &Accessor) -> EvalResult<ValueObj> {
match acc {
impl Evaluator { Accessor::Ident(ident) => {
#[inline] if let Some(val) = self.rec_get_const_obj(ident.inspect()) {
pub fn new() -> Self { Ok(val.clone())
Self::default()
}
fn eval_const_acc(&self, _acc: &Accessor, ctx: &Context) -> Option<ValueObj> {
match _acc {
Accessor::Local(local) => {
if let Some(val) = ctx.rec_get_const_obj(local.inspect()) {
Some(val.clone())
} else { } else {
None if ident.is_const() {
Err(EvalError::no_var_error(
line!() as usize,
ident.loc(),
self.caused_by(),
ident.inspect(),
self.get_similar_name(ident.inspect()),
))
} else {
Err(EvalError::not_const_expr(
line!() as usize,
acc.loc(),
self.caused_by(),
))
}
} }
} }
Accessor::Attr(attr) => { Accessor::Attr(attr) => {
let _obj = self.eval_const_expr(&attr.obj, ctx)?; let obj = self.eval_const_expr(&attr.obj, None)?;
todo!() self.eval_attr(obj, &attr.ident)
} }
_ => todo!(), _ => todo!(),
} }
} }
fn eval_const_bin(&self, bin: &BinOp) -> Option<ValueObj> { fn eval_attr(&self, obj: ValueObj, ident: &Identifier) -> EvalResult<ValueObj> {
match (bin.args[0].as_ref(), bin.args[1].as_ref()) { match obj.try_get_attr(&Field::from(ident)) {
(Expr::Lit(l), Expr::Lit(r)) => { Some(val) => {
let op = try_get_op_kind_from_token(bin.op.kind).ok()?; return Ok(val);
self.eval_bin_lit(op, eval_lit(l), eval_lit(r)).ok()
} }
_ => None, _ => {}
} }
} match &obj {
ValueObj::Type(t) => {
fn eval_const_unary(&self, unary: &UnaryOp) -> Option<ValueObj> { if let Some(sups) = self.rec_get_nominal_super_type_ctxs(t.typ()) {
match unary.args[0].as_ref() { for (_, ctx) in sups {
Expr::Lit(lit) => { if let Some(val) = ctx.consts.get(ident.inspect()) {
let op = try_get_op_kind_from_token(unary.op.kind).ok()?; return Ok(val.clone());
self.eval_unary_lit(op, eval_lit(lit)).ok() }
} for (_, methods) in ctx.methods_list.iter() {
_ => None, if let Some(v) = methods.consts.get(ident.inspect()) {
} return Ok(v.clone());
} }
}
// TODO: kw args
fn eval_args(&self, _args: &Args) -> Option<Vec<ValueObj>> {
todo!()
}
fn eval_const_call(&self, call: &Call, ctx: &Context) -> Option<ValueObj> {
if let Expr::Accessor(acc) = call.obj.as_ref() {
match acc {
Accessor::Local(name) if name.is_const() => {
if let Some(ValueObj::Subr(subr)) = ctx.rec_get_const_obj(&name.inspect()) {
let args = self.eval_args(&call.args)?;
Some(subr.call(args))
} else {
None
} }
} }
Accessor::Local(_) => None, }
_ => {}
}
Err(EvalError::no_attr_error(
line!() as usize,
ident.loc(),
self.caused_by(),
&obj.t(),
ident.inspect(),
None,
))
}
fn eval_const_bin(&self, bin: &BinOp) -> EvalResult<ValueObj> {
let lhs = self.eval_const_expr(&bin.args[0], None)?;
let rhs = self.eval_const_expr(&bin.args[1], None)?;
let op = try_get_op_kind_from_token(bin.op.kind)?;
self.eval_bin(op, lhs, rhs)
}
fn eval_const_unary(&self, unary: &UnaryOp) -> EvalResult<ValueObj> {
let val = self.eval_const_expr(&unary.args[0], None)?;
let op = try_get_op_kind_from_token(unary.op.kind)?;
self.eval_unary(op, val)
}
fn eval_args(&self, args: &Args, __name__: Option<&Str>) -> EvalResult<ValueArgs> {
let mut evaluated_pos_args = vec![];
for arg in args.pos_args().iter() {
let val = self.eval_const_expr(&arg.expr, __name__)?;
evaluated_pos_args.push(val);
}
let mut evaluated_kw_args = dict! {};
for arg in args.kw_args().iter() {
let val = self.eval_const_expr(&arg.expr, __name__)?;
evaluated_kw_args.insert(arg.keyword.inspect().clone(), val);
}
Ok(ValueArgs::new(evaluated_pos_args, evaluated_kw_args))
}
fn eval_const_call(&self, call: &Call, __name__: Option<&Str>) -> EvalResult<ValueObj> {
if let Expr::Accessor(acc) = call.obj.as_ref() {
match acc {
Accessor::Ident(ident) => {
let obj =
self.rec_get_const_obj(&ident.inspect())
.ok_or(EvalError::no_var_error(
line!() as usize,
ident.loc(),
self.caused_by(),
ident.inspect(),
self.get_similar_name(ident.inspect()),
))?;
let subr = option_enum_unwrap!(obj, ValueObj::Subr)
.ok_or(EvalError::type_mismatch_error(
line!() as usize,
ident.loc(),
self.caused_by(),
ident.inspect(),
&mono("Subroutine"),
&obj.t(),
None,
))?
.clone();
let args = self.eval_args(&call.args, __name__)?;
Ok(subr.call(args, __name__.map(|n| n.clone())))
}
Accessor::Attr(_attr) => todo!(), Accessor::Attr(_attr) => todo!(),
Accessor::TupleAttr(_attr) => todo!(), Accessor::TupleAttr(_attr) => todo!(),
Accessor::Public(_name) => todo!(),
Accessor::Subscr(_subscr) => todo!(), Accessor::Subscr(_subscr) => todo!(),
} }
} else { } else {
None
}
}
fn eval_const_def(&self, def: &Def) -> Option<ValueObj> {
if def.is_const() {
todo!() todo!()
} }
None
} }
fn eval_const_array(&self, arr: &Array, ctx: &Context) -> Option<ValueObj> { fn eval_const_def(&mut self, def: &Def) -> EvalResult<ValueObj> {
if def.is_const() {
let __name__ = def.sig.ident().map(|i| i.inspect()).unwrap();
let obj = self.eval_const_block(&def.body.block, Some(__name__))?;
self.register_gen_const(def.sig.ident().unwrap(), obj);
Ok(ValueObj::None)
} else {
Err(EvalError::not_const_expr(
line!() as usize,
def.body.block.loc(),
self.caused_by(),
))
}
}
fn eval_const_array(&self, arr: &Array) -> EvalResult<ValueObj> {
let mut elems = vec![]; let mut elems = vec![];
match arr { match arr {
Array::Normal(arr) => { Array::Normal(arr) => {
for elem in arr.elems.pos_args().iter() { for elem in arr.elems.pos_args().iter() {
if let Some(elem) = self.eval_const_expr(&elem.expr, ctx) { let elem = self.eval_const_expr(&elem.expr, None)?;
elems.push(elem); elems.push(elem);
} else {
return None;
}
} }
} }
_ => { _ => {
return None; todo!()
} }
} }
Some(ValueObj::Array(RcArray::from(elems))) Ok(ValueObj::Array(RcArray::from(elems)))
} }
fn eval_const_record(&self, record: &NormalRecord, ctx: &Context) -> Option<ValueObj> { fn eval_const_record(&self, record: &Record) -> EvalResult<ValueObj> {
match record {
Record::Normal(rec) => self.eval_const_normal_record(rec),
Record::Shortened(_rec) => unreachable!(), // should be desugared
}
}
fn eval_const_normal_record(&self, record: &NormalRecord) -> EvalResult<ValueObj> {
let mut attrs = vec![]; let mut attrs = vec![];
// HACK: should avoid cloning
let mut record_ctx = Context::instant(Str::ever("<unnamed record>"), 2, self.clone());
for attr in record.attrs.iter() { for attr in record.attrs.iter() {
if let Some(elem) = self.eval_const_block(&attr.body.block, ctx) { let name = attr.sig.ident().map(|i| i.inspect());
let ident = match &attr.sig { let elem = record_ctx.eval_const_block(&attr.body.block, name)?;
Signature::Var(var) => match &var.pat { let ident = match &attr.sig {
VarPattern::Ident(ident) => { Signature::Var(var) => match &var.pat {
Field::new(ident.vis(), ident.inspect().clone()) VarPattern::Ident(ident) => Field::new(ident.vis(), ident.inspect().clone()),
}
_ => todo!(),
},
_ => todo!(), _ => todo!(),
}; },
attrs.push((ident, elem)); _ => todo!(),
} else { };
return None; attrs.push((ident, elem));
}
} }
Some(ValueObj::Record(attrs.into_iter().collect())) Ok(ValueObj::Record(attrs.into_iter().collect()))
} }
// ConstExprを評価するのではなく、コンパイル時関数の式(AST上ではただのExpr)を評価する pub(crate) fn eval_const_expr(
// コンパイル時評価できないならNoneを返す &self,
pub(crate) fn eval_const_expr(&self, expr: &Expr, ctx: &Context) -> Option<ValueObj> { expr: &Expr,
__name__: Option<&Str>,
) -> EvalResult<ValueObj> {
match expr { match expr {
Expr::Lit(lit) => Some(eval_lit(lit)), Expr::Lit(lit) => Ok(eval_lit(lit)),
Expr::Accessor(acc) => self.eval_const_acc(acc, ctx), 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),
Expr::Call(call) => self.eval_const_call(call, ctx), Expr::Call(call) => self.eval_const_call(call, __name__),
Expr::Def(def) => self.eval_const_def(def), Expr::Array(arr) => self.eval_const_array(arr),
Expr::Array(arr) => self.eval_const_array(arr, ctx), Expr::Record(rec) => self.eval_const_record(rec),
Expr::Record(rec) => self.eval_const_record(rec, ctx), Expr::Lambda(lambda) => todo!("{lambda}"),
other => todo!("{other}"), other => todo!("{other}"),
} }
} }
pub(crate) fn eval_const_block(&self, block: &Block, ctx: &Context) -> Option<ValueObj> { // ConstExprを評価するのではなく、コンパイル時関数の式(AST上ではただのExpr)を評価する
for chunk in block.iter().rev().skip(1).rev() { // コンパイル時評価できないならNoneを返す
self.eval_const_expr(chunk, ctx)?; pub(crate) fn eval_const_chunk(
&mut self,
expr: &Expr,
__name__: Option<&Str>,
) -> EvalResult<ValueObj> {
match expr {
Expr::Lit(lit) => Ok(eval_lit(lit)),
Expr::Accessor(acc) => self.eval_const_acc(acc),
Expr::BinOp(bin) => self.eval_const_bin(bin),
Expr::UnaryOp(unary) => self.eval_const_unary(unary),
Expr::Call(call) => self.eval_const_call(call, __name__),
Expr::Def(def) => self.eval_const_def(def),
Expr::Array(arr) => self.eval_const_array(arr),
Expr::Record(rec) => self.eval_const_record(rec),
Expr::Lambda(lambda) => todo!("{lambda}"),
other => todo!("{other}"),
} }
self.eval_const_expr(block.last().unwrap(), ctx)
} }
fn eval_bin_lit(&self, op: OpKind, lhs: ValueObj, rhs: ValueObj) -> EvalResult<ValueObj> { pub(crate) fn eval_const_block(
&mut self,
block: &Block,
__name__: Option<&Str>,
) -> EvalResult<ValueObj> {
for chunk in block.iter().rev().skip(1).rev() {
self.eval_const_chunk(chunk, __name__)?;
}
self.eval_const_chunk(block.last().unwrap(), __name__)
}
fn eval_bin(&self, op: OpKind, lhs: ValueObj, rhs: ValueObj) -> EvalResult<ValueObj> {
match op { match op {
Add => lhs Add => lhs
.try_add(rhs) .try_add(rhs)
@ -346,10 +437,10 @@ impl Evaluator {
) -> EvalResult<TyParam> { ) -> EvalResult<TyParam> {
match (lhs, rhs) { match (lhs, rhs) {
(TyParam::Value(ValueObj::Mut(lhs)), TyParam::Value(rhs)) => self (TyParam::Value(ValueObj::Mut(lhs)), TyParam::Value(rhs)) => self
.eval_bin_lit(op, lhs.borrow().clone(), rhs.clone()) .eval_bin(op, lhs.borrow().clone(), rhs.clone())
.map(|v| TyParam::Value(ValueObj::Mut(RcCell::new(v)))), .map(|v| TyParam::Value(ValueObj::Mut(RcCell::new(v)))),
(TyParam::Value(lhs), TyParam::Value(rhs)) => self (TyParam::Value(lhs), TyParam::Value(rhs)) => self
.eval_bin_lit(op, lhs.clone(), rhs.clone()) .eval_bin(op, lhs.clone(), rhs.clone())
.map(TyParam::value), .map(TyParam::value),
(TyParam::FreeVar(fv), r) => { (TyParam::FreeVar(fv), r) => {
if fv.is_linked() { if fv.is_linked() {
@ -370,7 +461,7 @@ impl Evaluator {
} }
} }
fn eval_unary_lit(&self, op: OpKind, val: ValueObj) -> EvalResult<ValueObj> { fn eval_unary(&self, op: OpKind, val: ValueObj) -> EvalResult<ValueObj> {
match op { match op {
Pos => todo!(), Pos => todo!(),
Neg => todo!(), Neg => todo!(),
@ -382,9 +473,7 @@ impl Evaluator {
fn eval_unary_tp(&self, op: OpKind, val: &TyParam) -> EvalResult<TyParam> { fn eval_unary_tp(&self, op: OpKind, val: &TyParam) -> EvalResult<TyParam> {
match val { match val {
TyParam::Value(c) => self TyParam::Value(c) => self.eval_unary(op, c.clone()).map(|v| TyParam::Value(v)),
.eval_unary_lit(op, c.clone())
.map(|v| TyParam::Value(v)),
TyParam::FreeVar(fv) if fv.is_linked() => self.eval_unary_tp(op, &*fv.crack()), TyParam::FreeVar(fv) if fv.is_linked() => self.eval_unary_tp(op, &*fv.crack()),
e @ TyParam::Erased(_) => Ok(e.clone()), e @ TyParam::Erased(_) => Ok(e.clone()),
other => todo!("{op} {other}"), other => todo!("{op} {other}"),
@ -396,10 +485,10 @@ impl Evaluator {
} }
/// 量化変数などはそのまま返す /// 量化変数などはそのまま返す
pub(crate) fn eval_tp(&self, p: &TyParam, ctx: &Context) -> EvalResult<TyParam> { pub(crate) fn eval_tp(&self, p: &TyParam) -> EvalResult<TyParam> {
match p { match p {
TyParam::FreeVar(fv) if fv.is_linked() => self.eval_tp(&fv.crack(), ctx), TyParam::FreeVar(fv) if fv.is_linked() => self.eval_tp(&fv.crack()),
TyParam::Mono(name) => ctx TyParam::Mono(name) => self
.rec_get_const_obj(name) .rec_get_const_obj(name)
.map(|v| TyParam::value(v.clone())) .map(|v| TyParam::value(v.clone()))
.ok_or_else(|| EvalError::unreachable(fn_name!(), line!())), .ok_or_else(|| EvalError::unreachable(fn_name!(), line!())),
@ -415,45 +504,23 @@ impl Evaluator {
} }
} }
pub(crate) fn eval_t_params( pub(crate) fn eval_t_params(&self, substituted: Type, level: usize) -> EvalResult<Type> {
&self,
substituted: Type,
ctx: &Context,
level: usize,
) -> EvalResult<Type> {
match substituted { match substituted {
Type::FreeVar(fv) if fv.is_linked() => { Type::FreeVar(fv) if fv.is_linked() => self.eval_t_params(fv.crack().clone(), level),
self.eval_t_params(fv.crack().clone(), ctx, level)
}
Type::Subr(mut subr) => { Type::Subr(mut subr) => {
let kind = match subr.kind {
SubrKind::FuncMethod(self_t) => {
SubrKind::fn_met(self.eval_t_params(*self_t, ctx, level)?)
}
SubrKind::ProcMethod { before, after } => {
let before = self.eval_t_params(*before, ctx, level)?;
if let Some(after) = after {
let after = self.eval_t_params(*after, ctx, level)?;
SubrKind::pr_met(before, Some(after))
} else {
SubrKind::pr_met(before, None)
}
}
other => other,
};
for pt in subr.non_default_params.iter_mut() { for pt in subr.non_default_params.iter_mut() {
*pt.typ_mut() = self.eval_t_params(mem::take(pt.typ_mut()), ctx, level)?; *pt.typ_mut() = self.eval_t_params(mem::take(pt.typ_mut()), level)?;
} }
if let Some(var_args) = subr.var_params.as_mut() { if let Some(var_args) = subr.var_params.as_mut() {
*var_args.typ_mut() = *var_args.typ_mut() =
self.eval_t_params(mem::take(var_args.typ_mut()), ctx, level)?; self.eval_t_params(mem::take(var_args.typ_mut()), level)?;
} }
for pt in subr.default_params.iter_mut() { for pt in subr.default_params.iter_mut() {
*pt.typ_mut() = self.eval_t_params(mem::take(pt.typ_mut()), ctx, level)?; *pt.typ_mut() = self.eval_t_params(mem::take(pt.typ_mut()), level)?;
} }
let return_t = self.eval_t_params(*subr.return_t, ctx, level)?; let return_t = self.eval_t_params(*subr.return_t, level)?;
Ok(subr_t( Ok(subr_t(
kind, subr.kind,
subr.non_default_params, subr.non_default_params,
subr.var_params.map(|v| *v), subr.var_params.map(|v| *v),
subr.default_params, subr.default_params,
@ -463,7 +530,7 @@ impl Evaluator {
Type::Refinement(refine) => { Type::Refinement(refine) => {
let mut preds = Set::with_capacity(refine.preds.len()); let mut preds = Set::with_capacity(refine.preds.len());
for pred in refine.preds.into_iter() { for pred in refine.preds.into_iter() {
preds.insert(self.eval_pred(pred, ctx)?); preds.insert(self.eval_pred(pred)?);
} }
Ok(refinement(refine.var, *refine.t, preds)) Ok(refinement(refine.var, *refine.t, preds))
} }
@ -472,144 +539,137 @@ impl Evaluator {
// Currently Erg does not allow projection-types to be evaluated with type variables included. // Currently Erg does not allow projection-types to be evaluated with type variables included.
// All type variables will be dereferenced or fail. // All type variables will be dereferenced or fail.
let lhs = match *lhs { let lhs = match *lhs {
Type::FreeVar(fv) if fv.is_linked() => {
self.eval_t_params(mono_proj(fv.crack().clone(), rhs.clone()), level)?
}
Type::FreeVar(fv) if fv.is_unbound() => { Type::FreeVar(fv) if fv.is_unbound() => {
fv.lift(); fv.lift();
ctx.deref_tyvar(Type::FreeVar(fv))? self.deref_tyvar(Type::FreeVar(fv))?
} }
_ => *lhs, other => other,
}; };
for (_ty, ty_ctx) in ctx.rec_get_nominal_super_type_ctxs(&lhs) { for (_ty, ty_ctx) in self
if let Ok(obj) = ty_ctx.get_const_local(&Token::symbol(&rhs), &ctx.name) { .rec_get_nominal_super_type_ctxs(&lhs)
.ok_or_else(|| todo!("{lhs}"))?
{
if let Ok(obj) = ty_ctx.get_const_local(&Token::symbol(&rhs), &self.name) {
if let ValueObj::Type(quant_t) = obj { if let ValueObj::Type(quant_t) = obj {
let subst_ctx = SubstContext::new(&lhs, ty_ctx); let subst_ctx = SubstContext::new(&lhs, ty_ctx);
let t = subst_ctx.substitute(*quant_t, ty_ctx, level, ctx)?; let t =
let t = self.eval_t_params(t, ctx, level)?; subst_ctx.substitute(quant_t.typ().clone(), ty_ctx, level, self)?;
let t = self.eval_t_params(t, level)?;
return Ok(t); return Ok(t);
} else { } else {
todo!() todo!()
} }
} }
} }
if let Some(outer) = &ctx.outer { if let Some(outer) = self.outer.as_ref() {
self.eval_t_params(mono_proj(lhs, rhs), outer, level) outer.eval_t_params(mono_proj(lhs, rhs), level)
} else { } else {
todo!( todo!(
"{lhs}.{rhs} not found in [{}]", "{lhs}.{rhs} not found in [{}]",
erg_common::fmt_iter( erg_common::fmt_iter(
ctx.rec_get_nominal_super_type_ctxs(&lhs) self.rec_get_nominal_super_type_ctxs(&lhs)
.unwrap()
.map(|(_, ctx)| &ctx.name) .map(|(_, ctx)| &ctx.name)
) )
) )
} }
} }
Type::Ref(l) => Ok(ref_(self.eval_t_params(*l, ctx, level)?)), Type::Ref(l) => Ok(ref_(self.eval_t_params(*l, level)?)),
Type::RefMut(l) => Ok(ref_mut(self.eval_t_params(*l, ctx, level)?)), Type::RefMut { before, after } => {
Type::PolyClass { name, mut params } => { let before = self.eval_t_params(*before, level)?;
for p in params.iter_mut() { let after = if let Some(after) = after {
*p = self.eval_tp(&mem::take(p), ctx)?; Some(self.eval_t_params(*after, level)?)
} } else {
Ok(poly_class(name, params)) None
};
Ok(ref_mut(before, after))
} }
Type::PolyTrait { name, mut params } => { Type::Poly { name, mut params } => {
for p in params.iter_mut() { for p in params.iter_mut() {
*p = self.eval_tp(&mem::take(p), ctx)?; *p = self.eval_tp(&mem::take(p))?;
} }
Ok(poly_trait(name, params)) Ok(poly(name, params))
} }
other if other.is_monomorphic() => Ok(other), other if other.is_monomorphic() => Ok(other),
other => todo!("{other}"), other => todo!("{other}"),
} }
} }
pub(crate) fn _eval_bound( pub(crate) fn _eval_bound(&self, bound: TyBound, level: usize) -> EvalResult<TyBound> {
&self,
bound: TyBound,
ctx: &Context,
level: usize,
) -> EvalResult<TyBound> {
match bound { match bound {
TyBound::Sandwiched { sub, mid, sup } => { TyBound::Sandwiched { sub, mid, sup } => {
let sub = self.eval_t_params(sub, ctx, level)?; let sub = self.eval_t_params(sub, level)?;
let mid = self.eval_t_params(mid, ctx, level)?; let mid = self.eval_t_params(mid, level)?;
let sup = self.eval_t_params(sup, ctx, level)?; let sup = self.eval_t_params(sup, level)?;
Ok(TyBound::sandwiched(sub, mid, sup)) Ok(TyBound::sandwiched(sub, mid, sup))
} }
TyBound::Instance { name: inst, t } => { TyBound::Instance { name: inst, t } => {
Ok(TyBound::instance(inst, self.eval_t_params(t, ctx, level)?)) Ok(TyBound::instance(inst, self.eval_t_params(t, level)?))
} }
} }
} }
pub(crate) fn eval_pred(&self, p: Predicate, ctx: &Context) -> EvalResult<Predicate> { pub(crate) fn eval_pred(&self, p: Predicate) -> EvalResult<Predicate> {
match p { match p {
Predicate::Value(_) | Predicate::Const(_) => Ok(p), Predicate::Value(_) | Predicate::Const(_) => Ok(p),
Predicate::Equal { lhs, rhs } => Ok(Predicate::eq(lhs, self.eval_tp(&rhs, ctx)?)), Predicate::Equal { lhs, rhs } => Ok(Predicate::eq(lhs, self.eval_tp(&rhs)?)),
Predicate::NotEqual { lhs, rhs } => Ok(Predicate::ne(lhs, self.eval_tp(&rhs, ctx)?)), Predicate::NotEqual { lhs, rhs } => Ok(Predicate::ne(lhs, self.eval_tp(&rhs)?)),
Predicate::LessEqual { lhs, rhs } => Ok(Predicate::le(lhs, self.eval_tp(&rhs, ctx)?)), Predicate::LessEqual { lhs, rhs } => Ok(Predicate::le(lhs, self.eval_tp(&rhs)?)),
Predicate::GreaterEqual { lhs, rhs } => { Predicate::GreaterEqual { lhs, rhs } => Ok(Predicate::ge(lhs, self.eval_tp(&rhs)?)),
Ok(Predicate::ge(lhs, self.eval_tp(&rhs, ctx)?)) Predicate::And(l, r) => Ok(Predicate::and(self.eval_pred(*l)?, self.eval_pred(*r)?)),
} Predicate::Or(l, r) => Ok(Predicate::or(self.eval_pred(*l)?, self.eval_pred(*r)?)),
Predicate::And(l, r) => Ok(Predicate::and( Predicate::Not(l, r) => Ok(Predicate::not(self.eval_pred(*l)?, self.eval_pred(*r)?)),
self.eval_pred(*l, ctx)?,
self.eval_pred(*r, ctx)?,
)),
Predicate::Or(l, r) => Ok(Predicate::or(
self.eval_pred(*l, ctx)?,
self.eval_pred(*r, ctx)?,
)),
Predicate::Not(l, r) => Ok(Predicate::not(
self.eval_pred(*l, ctx)?,
self.eval_pred(*r, ctx)?,
)),
} }
} }
pub(crate) fn get_tp_t(&self, p: &TyParam, ctx: &Context) -> EvalResult<Type> { pub(crate) fn get_tp_t(&self, p: &TyParam) -> EvalResult<Type> {
let p = self.eval_tp(p, ctx)?; let p = self.eval_tp(p)?;
match p { match p {
TyParam::Value(ValueObj::Mut(v)) => Ok(v.borrow().class().mutate()), TyParam::Value(ValueObj::Mut(v)) => Ok(v.borrow().class().mutate()),
TyParam::Value(v) => Ok(enum_t(set![v])), TyParam::Value(v) => Ok(enum_t(set![v])),
TyParam::Erased(t) => Ok((*t).clone()), TyParam::Erased(t) => Ok((*t).clone()),
TyParam::FreeVar(fv) => { TyParam::FreeVar(fv) => {
if let Some(t) = fv.type_of() { if let Some(t) = fv.get_type() {
Ok(t) Ok(t)
} else { } else {
todo!() todo!()
} }
} }
// TODO: Class, Trait
TyParam::Type(_) => Ok(Type::Type), TyParam::Type(_) => Ok(Type::Type),
TyParam::Mono(name) => ctx TyParam::Mono(name) => self
.consts .rec_get_const_obj(&name)
.get(&name)
.map(|v| enum_t(set![v.clone()])) .map(|v| enum_t(set![v.clone()]))
.ok_or_else(|| EvalError::unreachable(fn_name!(), line!())), .ok_or_else(|| EvalError::unreachable(fn_name!(), line!())),
TyParam::MonoQVar(name) => { TyParam::MonoQVar(name) => {
panic!("Not instantiated type variable: {name}") panic!("Not instantiated type variable: {name}")
} }
TyParam::UnaryOp { op, val } => match op { TyParam::UnaryOp { op, val } => match op {
OpKind::Mutate => Ok(self.get_tp_t(&val, ctx)?.mutate()), OpKind::Mutate => Ok(self.get_tp_t(&val)?.mutate()),
_ => todo!(), _ => todo!(),
}, },
other => todo!("{other}"), other => todo!("{other}"),
} }
} }
pub(crate) fn _get_tp_class(&self, p: &TyParam, ctx: &Context) -> EvalResult<Type> { pub(crate) fn _get_tp_class(&self, p: &TyParam) -> EvalResult<Type> {
let p = self.eval_tp(p, ctx)?; let p = self.eval_tp(p)?;
match p { match p {
TyParam::Value(v) => Ok(v.class()), TyParam::Value(v) => Ok(v.class()),
TyParam::Erased(t) => Ok((*t).clone()), TyParam::Erased(t) => Ok((*t).clone()),
TyParam::FreeVar(fv) => { TyParam::FreeVar(fv) => {
if let Some(t) = fv.type_of() { if let Some(t) = fv.get_type() {
Ok(t) Ok(t)
} else { } else {
todo!() todo!()
} }
} }
TyParam::Type(_) => Ok(Type::Type), TyParam::Type(_) => Ok(Type::Type),
TyParam::Mono(name) => ctx TyParam::Mono(name) => self
.consts .rec_get_const_obj(&name)
.get(&name)
.map(|v| v.class()) .map(|v| v.class())
.ok_or_else(|| EvalError::unreachable(fn_name!(), line!())), .ok_or_else(|| EvalError::unreachable(fn_name!(), line!())),
other => todo!("{other}"), other => todo!("{other}"),
@ -617,7 +677,7 @@ impl Evaluator {
} }
/// NOTE: lとrが型の場合はContextの方で判定する /// NOTE: lとrが型の場合はContextの方で判定する
pub(crate) fn shallow_eq_tp(&self, lhs: &TyParam, rhs: &TyParam, ctx: &Context) -> bool { pub(crate) fn shallow_eq_tp(&self, lhs: &TyParam, rhs: &TyParam) -> bool {
match (lhs, rhs) { match (lhs, rhs) {
(TyParam::Type(l), TyParam::Type(r)) => l == r, (TyParam::Type(l), TyParam::Type(r)) => l == r,
(TyParam::Value(l), TyParam::Value(r)) => l == r, (TyParam::Value(l), TyParam::Value(r)) => l == r,
@ -626,7 +686,9 @@ impl Evaluator {
(TyParam::Mono(l), TyParam::Mono(r)) => { (TyParam::Mono(l), TyParam::Mono(r)) => {
if l == r { if l == r {
true true
} else if let (Some(l), Some(r)) = (ctx.consts.get(l), ctx.consts.get(r)) { } else if let (Some(l), Some(r)) =
(self.rec_get_const_obj(l), self.rec_get_const_obj(r))
{
l == r l == r
} else { } else {
// lとrが型の場合は... // lとrが型の場合は...
@ -637,7 +699,7 @@ impl Evaluator {
(TyParam::UnaryOp { .. }, TyParam::UnaryOp { .. }) => todo!(), (TyParam::UnaryOp { .. }, TyParam::UnaryOp { .. }) => todo!(),
(TyParam::App { .. }, TyParam::App { .. }) => todo!(), (TyParam::App { .. }, TyParam::App { .. }) => todo!(),
(TyParam::Mono(m), TyParam::Value(l)) | (TyParam::Value(l), TyParam::Mono(m)) => { (TyParam::Mono(m), TyParam::Value(l)) | (TyParam::Value(l), TyParam::Mono(m)) => {
if let Some(o) = ctx.consts.get(m) { if let Some(o) = self.rec_get_const_obj(m) {
o == l o == l
} else { } else {
true true

View file

@ -10,7 +10,7 @@ impl Context {
if fv.is_linked() { if fv.is_linked() {
fv.crack().clone() fv.crack().clone()
} else { } else {
let (_sub, sup) = fv.crack_bound_types().unwrap(); let (_sub, sup) = fv.get_bound_types().unwrap();
sup sup
} }
} else { } else {

View file

@ -0,0 +1,66 @@
use std::mem;
use erg_common::Str;
use erg_type::constructors::{and, mono};
use erg_type::value::{TypeKind, TypeObj, ValueObj};
use erg_type::Type;
use erg_type::ValueArgs;
fn value_obj_to_t(value: ValueObj) -> TypeObj {
match value {
ValueObj::Type(t) => t,
ValueObj::Record(rec) => TypeObj::Builtin(Type::Record(
rec.into_iter()
.map(|(k, v)| (k, value_obj_to_t(v).typ().clone()))
.collect(),
)),
other => todo!("{other}"),
}
}
/// Requirement: Type, Impl := Type -> ClassType
pub fn class_func(mut args: ValueArgs, __name__: Option<Str>) -> ValueObj {
let require = args.remove_left_or_key("Requirement").unwrap();
let require = value_obj_to_t(require);
let impls = args.remove_left_or_key("Impl");
let impls = impls.map(|v| value_obj_to_t(v));
let t = mono(__name__.unwrap_or(Str::ever("<Lambda>")));
ValueObj::gen_t(TypeKind::Class, t, require, impls, None)
}
/// Super: Type, Impl := Type, Additional := Type -> ClassType
pub fn inherit_func(mut args: ValueArgs, __name__: Option<Str>) -> ValueObj {
let sup = args.remove_left_or_key("Super").unwrap();
let sup = value_obj_to_t(sup);
let impls = args.remove_left_or_key("Impl");
let impls = impls.map(|v| value_obj_to_t(v));
let additional = args.remove_left_or_key("Additional");
let additional = additional.map(|v| value_obj_to_t(v));
let t = mono(__name__.unwrap_or(Str::ever("<Lambda>")));
ValueObj::gen_t(TypeKind::Subclass, t, sup, impls, additional)
}
/// Class: ClassType -> ClassType (with `InheritableType`)
/// This function is used by the compiler to mark a class as inheritable and does nothing in terms of actual operation.
pub fn inheritable_func(mut args: ValueArgs, __name__: Option<Str>) -> ValueObj {
let class = args.remove_left_or_key("Class").unwrap();
match class {
ValueObj::Type(TypeObj::Generated(mut gen)) => {
if let Some(typ) = &mut gen.impls {
match typ.as_mut() {
TypeObj::Generated(gen) => {
gen.t = and(mem::take(&mut gen.t), mono("InheritableType"));
}
TypeObj::Builtin(t) => {
*t = and(mem::take(t), mono("InheritableType"));
}
}
} else {
gen.impls = Some(Box::new(TypeObj::Builtin(mono("InheritableType"))));
}
ValueObj::Type(TypeObj::Generated(gen))
}
_ => todo!(),
}
}

View file

@ -1,23 +0,0 @@
use erg_common::vis::Visibility;
use erg_type::constructors::func1;
use erg_type::Type;
use Type::*;
use crate::context::Context;
use crate::varinfo::Mutability;
use Mutability::*;
use Visibility::*;
impl Context {
pub(crate) fn init_py_math_mod() -> Self {
let mut math = Context::module("math".into(), 10);
math.register_impl("pi", Float, Immutable, Public);
math.register_impl("tau", Float, Immutable, Public);
math.register_impl("e", Float, Immutable, Public);
math.register_impl("sin", func1(Float, Float), Immutable, Public);
math.register_impl("cos", func1(Float, Float), Immutable, Public);
math.register_impl("tan", func1(Float, Float), Immutable, Public);
math
}
}

File diff suppressed because it is too large Load diff

View file

@ -12,7 +12,7 @@ use Visibility::*;
impl Context { impl Context {
pub(crate) fn init_py_importlib_mod() -> Self { pub(crate) fn init_py_importlib_mod() -> Self {
let mut importlib = Context::module("importlib".into(), 15); let mut importlib = Context::module("importlib".into(), 15);
importlib.register_impl("reload!", proc1(Module, NoneType), Immutable, Public); importlib.register_builtin_impl("reload!", proc1(Module, NoneType), Immutable, Public);
importlib importlib
} }
} }

View file

@ -1,7 +1,7 @@
use erg_common::vis::Visibility; use erg_common::vis::Visibility;
use erg_common::Str; use erg_common::Str;
use erg_type::constructors::{class, pr0_met}; use erg_type::constructors::{mono, pr0_met, ref_};
use erg_type::Type; use erg_type::Type;
use Type::*; use Type::*;
@ -14,13 +14,13 @@ impl Context {
pub(crate) fn init_py_io_mod() -> Self { pub(crate) fn init_py_io_mod() -> Self {
let mut io = Context::module("io".into(), 15); let mut io = Context::module("io".into(), 15);
let mut string_io = Context::mono_class(Str::ever("StringIO!"), vec![Obj], vec![], 0); let mut string_io = Context::mono_class(Str::ever("StringIO!"), vec![Obj], vec![], 0);
string_io.register_impl( string_io.register_builtin_impl(
"getvalue!", "getvalue!",
pr0_met(class("StringIO!"), None, Str), pr0_met(ref_(mono("StringIO!")), Str),
Immutable, Immutable,
Public, Public,
); );
io.register_type(class("StringIO!"), string_io, Const); io.register_builtin_type(mono("StringIO!"), string_io, Const);
io io
} }
} }

View file

@ -0,0 +1,23 @@
use erg_common::vis::Visibility;
use erg_type::constructors::func1;
use erg_type::Type;
use Type::*;
use crate::context::Context;
use crate::varinfo::Mutability;
use Mutability::*;
use Visibility::*;
impl Context {
pub(crate) fn init_py_math_mod() -> Self {
let mut math = Context::module("math".into(), 10);
math.register_builtin_impl("pi", Float, Immutable, Public);
math.register_builtin_impl("tau", Float, Immutable, Public);
math.register_builtin_impl("e", Float, Immutable, Public);
math.register_builtin_impl("sin", func1(Float, Float), Immutable, Public);
math.register_builtin_impl("cos", func1(Float, Float), Immutable, Public);
math.register_builtin_impl("tan", func1(Float, Float), Immutable, Public);
math
}
}

View file

@ -0,0 +1,7 @@
pub mod importlib;
pub mod io;
pub mod math;
pub mod random;
pub mod socket;
pub mod sys;
pub mod time;

View file

@ -2,7 +2,7 @@ use erg_common::set;
use erg_common::vis::Visibility; use erg_common::vis::Visibility;
use erg_type::constructors::{ use erg_type::constructors::{
mono_q, nd_proc, param_t, poly_trait, proc, quant, static_instance, trait_, ty_tp, mono, mono_q, nd_proc, param_t, poly, proc, quant, static_instance, ty_tp,
}; };
use erg_type::Type; use erg_type::Type;
use Type::*; use Type::*;
@ -15,13 +15,13 @@ use Visibility::*;
impl Context { impl Context {
pub(crate) fn init_py_random_mod() -> Self { pub(crate) fn init_py_random_mod() -> Self {
let mut random = Context::module("random".into(), 10); let mut random = Context::module("random".into(), 10);
random.register_impl( random.register_builtin_impl(
"seed!", "seed!",
proc( proc(
vec![], vec![],
None, None,
vec![ vec![
param_t("a", trait_("Num")), // TODO: NoneType, int, float, str, bytes, bytearray param_t("a", mono("Num")), // TODO: NoneType, int, float, str, bytes, bytearray
param_t("version", Int), param_t("version", Int),
], ],
NoneType, NoneType,
@ -29,19 +29,19 @@ impl Context {
Immutable, Immutable,
Public, Public,
); );
random.register_impl( random.register_builtin_impl(
"randint!", "randint!",
nd_proc(vec![param_t("a", Int), param_t("b", Int)], None, Int), nd_proc(vec![param_t("a", Int), param_t("b", Int)], None, Int),
Immutable, Immutable,
Public, Public,
); );
let t = nd_proc( let t = nd_proc(
vec![param_t("seq", poly_trait("Seq", vec![ty_tp(mono_q("T"))]))], vec![param_t("seq", poly("Seq", vec![ty_tp(mono_q("T"))]))],
None, None,
mono_q("T"), mono_q("T"),
); );
let t = quant(t, set! {static_instance("T", Type)}); let t = quant(t, set! {static_instance("T", Type)});
random.register_impl("choice!", t, Immutable, Public); random.register_builtin_impl("choice!", t, Immutable, Public);
random random
} }
} }

View file

@ -1,7 +1,7 @@
use erg_common::vis::Visibility; use erg_common::vis::Visibility;
use erg_common::Str; use erg_common::Str;
use erg_type::constructors::{class, func, option, param_t}; use erg_type::constructors::{func, mono, option, param_t};
use erg_type::Type; use erg_type::Type;
use Type::*; use Type::*;
@ -14,7 +14,7 @@ impl Context {
pub(crate) fn init_py_socket_mod() -> Self { pub(crate) fn init_py_socket_mod() -> Self {
let mut socket = Context::module("socket".into(), 15); let mut socket = Context::module("socket".into(), 15);
let mut sock = Context::mono_class(Str::ever("Socket!"), vec![Obj], vec![], 0); let mut sock = Context::mono_class(Str::ever("Socket!"), vec![Obj], vec![], 0);
sock.register_impl( sock.register_builtin_impl(
"new", "new",
func( func(
vec![], vec![],
@ -25,12 +25,12 @@ impl Context {
param_t("proto", Int), param_t("proto", Int),
param_t("fileno", option(Int)), param_t("fileno", option(Int)),
], ],
class("Socket!"), mono("Socket!"),
), ),
Immutable, Immutable,
Public, Public,
); );
socket.register_type(class("Socket!"), sock, Const); socket.register_builtin_type(mono("Socket!"), sock, Const);
socket socket
} }
} }

View file

@ -0,0 +1,50 @@
use erg_common::vis::Visibility;
use erg_type::constructors::{array, array_mut, func0, func1, mono, proc1};
use erg_type::typaram::TyParam;
use erg_type::Type;
use Type::*;
use crate::context::Context;
use crate::varinfo::Mutability;
use Mutability::*;
use Visibility::*;
impl Context {
pub(crate) fn init_py_sys_mod() -> Self {
let mut sys = Context::module("sys".into(), 15);
sys.register_builtin_impl("argv", array(Str, TyParam::erased(Nat)), Immutable, Public);
sys.register_builtin_impl("byteorder", Str, Immutable, Public);
sys.register_builtin_impl(
"builtin_module_names",
array(Str, TyParam::erased(Nat)),
Immutable,
Public,
);
sys.register_builtin_impl("copyright", Str, Immutable, Public);
sys.register_builtin_impl("executable", Str, Immutable, Public);
sys.register_builtin_impl("exit", func1(Int, Never), Immutable, Public);
sys.register_builtin_impl("getdefaultencoding", func0(Str), Immutable, Public);
sys.register_builtin_impl(
"path",
array_mut(Str, TyParam::erased(Nat)),
Immutable,
Public,
);
sys.register_builtin_impl("platform", Str, Immutable, Public);
sys.register_builtin_impl("prefix", Str, Immutable, Public);
sys.register_builtin_impl("ps1", mono("Str!"), Immutable, Public);
sys.register_builtin_impl("ps2", mono("Str!"), Immutable, Public);
sys.register_builtin_impl(
"setrecursionlimit!",
proc1(Int, NoneType),
Immutable,
Public,
);
sys.register_builtin_impl("stderr", mono("TextIOWrapper!"), Immutable, Public);
sys.register_builtin_impl("stdin", mono("TextIOWrapper!"), Immutable, Public);
sys.register_builtin_impl("stdout", mono("TextIOWrapper!"), Immutable, Public);
sys.register_builtin_impl("version", Str, Immutable, Public);
sys
}
}

View file

@ -12,8 +12,8 @@ use Visibility::*;
impl Context { impl Context {
pub(crate) fn init_py_time_mod() -> Self { pub(crate) fn init_py_time_mod() -> Self {
let mut time = Context::module("time".into(), 15); let mut time = Context::module("time".into(), 15);
time.register_impl("sleep!", proc1(Float, NoneType), Immutable, Public); time.register_builtin_impl("sleep!", proc1(Float, NoneType), Immutable, Public);
time.register_impl("time!", proc0(Float), Immutable, Public); time.register_builtin_impl("time!", proc0(Float), Immutable, Public);
time time
} }
} }

View file

@ -1,50 +0,0 @@
use erg_common::vis::Visibility;
use erg_type::constructors::{array, array_mut, class, func0, func1, proc1};
use erg_type::typaram::TyParam;
use erg_type::Type;
use Type::*;
use crate::context::Context;
use crate::varinfo::Mutability;
use Mutability::*;
use Visibility::*;
impl Context {
pub(crate) fn init_py_sys_mod() -> Self {
let mut sys = Context::module("sys".into(), 15);
sys.register_impl("argv", array(Str, TyParam::erased(Nat)), Immutable, Public);
sys.register_impl("byteorder", Str, Immutable, Public);
sys.register_impl(
"builtin_module_names",
array(Str, TyParam::erased(Nat)),
Immutable,
Public,
);
sys.register_impl("copyright", Str, Immutable, Public);
sys.register_impl("executable", Str, Immutable, Public);
sys.register_impl("exit", func1(Int, Never), Immutable, Public);
sys.register_impl("getdefaultencoding", func0(Str), Immutable, Public);
sys.register_impl(
"path",
array_mut(Str, TyParam::erased(Nat)),
Immutable,
Public,
);
sys.register_impl("platform", Str, Immutable, Public);
sys.register_impl("prefix", Str, Immutable, Public);
sys.register_impl("ps1", class("Str!"), Immutable, Public);
sys.register_impl("ps2", class("Str!"), Immutable, Public);
sys.register_impl(
"setrecursionlimit!",
proc1(Int, NoneType),
Immutable,
Public,
);
sys.register_impl("stderr", class("TextIOWrapper!"), Immutable, Public);
sys.register_impl("stdin", class("TextIOWrapper!"), Immutable, Public);
sys.register_impl("stdout", class("TextIOWrapper!"), Immutable, Public);
sys.register_impl("version", Str, Immutable, Public);
sys
}
}

View file

@ -1,7 +1,7 @@
// (type) getters & validators // (type) getters & validators
use std::option::Option; // conflicting to Type::Option use std::option::Option; // conflicting to Type::Option
use erg_common::error::ErrorCore; use erg_common::error::{ErrorCore, ErrorKind};
use erg_common::levenshtein::levenshtein; use erg_common::levenshtein::levenshtein;
use erg_common::set::Set; use erg_common::set::Set;
use erg_common::traits::Locational; use erg_common::traits::Locational;
@ -11,16 +11,14 @@ use erg_common::{enum_unwrap, fmt_option, fmt_slice, log, set};
use Type::*; use Type::*;
use ast::VarName; use ast::VarName;
use erg_parser::ast; use erg_parser::ast::{self, Identifier};
use erg_parser::token::Token; use erg_parser::token::Token;
use erg_type::constructors::{ use erg_type::constructors::{func, mono, mono_proj, poly, ref_, ref_mut, refinement, subr_t};
class, func, mono_proj, poly_class, ref_, ref_mut, refinement, subr_t,
};
use erg_type::free::Constraint; use erg_type::free::Constraint;
use erg_type::typaram::TyParam; use erg_type::typaram::TyParam;
use erg_type::value::ValueObj; use erg_type::value::{GenTypeObj, TypeObj, ValueObj};
use erg_type::{HasType, ParamTy, SubrKind, SubrType, TyBound, Type}; use erg_type::{HasType, ParamTy, TyBound, Type};
use crate::context::instantiate::ConstTemplate; use crate::context::instantiate::ConstTemplate;
use crate::context::{Context, ContextKind, RegistrationMode, TraitInstance, Variance}; use crate::context::{Context, ContextKind, RegistrationMode, TraitInstance, Variance};
@ -72,6 +70,18 @@ impl Context {
}) })
.map(|(_, vi)| vi) .map(|(_, vi)| vi)
}) })
.or_else(|| {
for (_, methods) in self.methods_list.iter() {
if let Some(vi) = methods.get_current_scope_var(name) {
return Some(vi);
}
}
None
})
}
pub(crate) fn get_local_kv(&self, name: &str) -> Option<(&VarName, &VarInfo)> {
self.locals.get_key_value(name)
} }
fn get_context( fn get_context(
@ -81,17 +91,17 @@ impl Context {
namespace: &Str, namespace: &Str,
) -> TyCheckResult<&Context> { ) -> TyCheckResult<&Context> {
match obj { match obj {
hir::Expr::Accessor(hir::Accessor::Local(name)) => { hir::Expr::Accessor(hir::Accessor::Ident(ident)) => {
if kind == Some(ContextKind::Module) { if kind == Some(ContextKind::Module) {
if let Some(ctx) = self.rec_get_mod(name.inspect()) { if let Some(ctx) = self.rec_get_mod(ident.inspect()) {
Ok(ctx) Ok(ctx)
} else { } else {
Err(TyCheckError::no_var_error( Err(TyCheckError::no_var_error(
line!() as usize, line!() as usize,
obj.loc(), obj.loc(),
namespace.clone(), namespace.clone(),
name.inspect(), ident.inspect(),
self.get_similar_name(name.inspect()), self.get_similar_name(ident.inspect()),
)) ))
} }
} else { } else {
@ -119,9 +129,9 @@ impl Context {
pos_arg.loc(), pos_arg.loc(),
self.caused_by(), self.caused_by(),
"match", "match",
&class("LambdaFunc"), &mono("LambdaFunc"),
t, t,
self.get_type_mismatch_hint(&class("LambdaFunc"), t), self.get_type_mismatch_hint(&mono("LambdaFunc"), t),
)); ));
} }
} }
@ -184,37 +194,26 @@ impl Context {
if let Some(ctx) = self.rec_get_mod(name.inspect()) { if let Some(ctx) = self.rec_get_mod(name.inspect()) {
return Some(ctx.name.clone()); return Some(ctx.name.clone());
} }
if let Some((_, ctx)) = self.rec_get_type(name.inspect()) {
return Some(ctx.name.clone());
}
None None
} }
pub(crate) fn rec_get_var_t( pub(crate) fn rec_get_var_t(&self, ident: &Identifier, namespace: &Str) -> TyCheckResult<Type> {
&self, if let Some(vi) = self.get_current_scope_var(&ident.inspect()[..]) {
name: &Token, self.validate_visibility(ident, vi, namespace)?;
vis: Visibility, Ok(vi.t())
namespace: &Str,
) -> TyCheckResult<Type> {
if let Some(vi) = self.get_current_scope_var(&name.inspect()[..]) {
if vi.vis == vis {
Ok(vi.t())
} else {
Err(TyCheckError::visibility_error(
line!() as usize,
name.loc(),
namespace.clone(),
name.inspect(),
vi.vis,
))
}
} else { } else {
if let Some(parent) = self.outer.as_ref() { if let Some(parent) = self.outer.as_ref() {
return parent.rec_get_var_t(name, vis, namespace); return parent.rec_get_var_t(ident, namespace);
} }
Err(TyCheckError::no_var_error( Err(TyCheckError::no_var_error(
line!() as usize, line!() as usize,
name.loc(), ident.loc(),
namespace.clone(), namespace.clone(),
name.inspect(), ident.inspect(),
self.get_similar_name(name.inspect()), self.get_similar_name(ident.inspect()),
)) ))
} }
} }
@ -222,43 +221,48 @@ impl Context {
pub(crate) fn rec_get_attr_t( pub(crate) fn rec_get_attr_t(
&self, &self,
obj: &hir::Expr, obj: &hir::Expr,
name: &Token, ident: &Identifier,
namespace: &Str, namespace: &Str,
) -> TyCheckResult<Type> { ) -> TyCheckResult<Type> {
let self_t = obj.t(); let self_t = obj.t();
match self_t { let name = ident.name.token();
Type => todo!(), match self.get_attr_t_from_attributive_t(obj, &self_t, ident, namespace) {
Type::Record(rec) => { Ok(t) => {
// REVIEW: `rec.get(name.inspect())` returns None (Borrow<Str> is implemented for Field). Why? return Ok(t);
if let Some(attr) = rec.get(&Field::new(Public, name.inspect().clone())) { }
return Ok(attr.clone()); Err(e) if e.core.kind == ErrorKind::DummyError => {}
} else { Err(e) => {
let t = Type::Record(rec); return Err(e);
return Err(TyCheckError::no_attr_error( }
line!() as usize, }
name.loc(), if let Some(singular_ctx) = self.rec_get_singular_ctx(obj) {
namespace.clone(), match singular_ctx.rec_get_var_t(ident, namespace) {
&t, Ok(t) => {
name.inspect(), return Ok(t);
self.get_similar_attr(&t, name.inspect()), }
)); Err(e) if e.core.kind == ErrorKind::NameError => {}
Err(e) => {
return Err(e);
} }
} }
Module => {
let mod_ctx = self.get_context(obj, Some(ContextKind::Module), namespace)?;
let t = mod_ctx.rec_get_var_t(name, Public, namespace)?;
return Ok(t);
}
_ => {}
} }
for (_, ctx) in self.rec_get_nominal_super_type_ctxs(&self_t) { for (_, ctx) in self
if let Ok(t) = ctx.rec_get_var_t(name, Public, namespace) { .rec_get_nominal_super_type_ctxs(&self_t)
return Ok(t); .ok_or_else(|| todo!())?
{
match ctx.rec_get_var_t(ident, namespace) {
Ok(t) => {
return Ok(t);
}
Err(e) if e.core.kind == ErrorKind::NameError => {}
Err(e) => {
return Err(e);
}
} }
} }
// TODO: dependent type widening // TODO: dependent type widening
if let Some(parent) = self.outer.as_ref() { if let Some(parent) = self.outer.as_ref() {
parent.rec_get_attr_t(obj, name, namespace) parent.rec_get_attr_t(obj, ident, namespace)
} else { } else {
Err(TyCheckError::no_attr_error( Err(TyCheckError::no_attr_error(
line!() as usize, line!() as usize,
@ -271,27 +275,119 @@ impl Context {
} }
} }
fn get_attr_t_from_attributive_t(
&self,
obj: &hir::Expr,
t: &Type,
ident: &Identifier,
namespace: &Str,
) -> TyCheckResult<Type> {
match t {
Type::FreeVar(fv) if fv.is_linked() => {
self.get_attr_t_from_attributive_t(obj, &fv.crack(), ident, namespace)
}
Type::FreeVar(fv) => {
let sup = fv.get_sup().unwrap();
self.get_attr_t_from_attributive_t(obj, &sup, ident, namespace)
}
Type::Ref(t) => self.get_attr_t_from_attributive_t(obj, t, ident, namespace),
Type::RefMut { before, .. } => {
self.get_attr_t_from_attributive_t(obj, before, ident, namespace)
}
Type::Refinement(refine) => {
self.get_attr_t_from_attributive_t(obj, &refine.t, ident, namespace)
}
Type::Record(record) => {
// REVIEW: `rec.get(name.inspect())` returns None (Borrow<Str> is implemented for Field). Why?
if let Some(attr) = record.get(&Field::new(Public, ident.inspect().clone())) {
Ok(attr.clone())
} else {
let t = Type::Record(record.clone());
Err(TyCheckError::no_attr_error(
line!() as usize,
ident.loc(),
namespace.clone(),
&t,
ident.inspect(),
self.get_similar_attr(&t, ident.inspect()),
))
}
}
Module => {
let mod_ctx = self.get_context(obj, Some(ContextKind::Module), namespace)?;
let t = mod_ctx.rec_get_var_t(ident, namespace)?;
Ok(t)
}
other => {
if let Some(v) = self.rec_get_const_obj(&other.name()) {
match v {
ValueObj::Type(TypeObj::Generated(gen)) => self
.get_gen_t_require_attr_t(gen, &ident.inspect()[..])
.map(|t| t.clone())
.ok_or(TyCheckError::dummy(line!() as usize)),
ValueObj::Type(TypeObj::Builtin(_t)) => {
// FIXME:
Err(TyCheckError::dummy(line!() as usize))
}
other => todo!("{other}"),
}
} else {
Err(TyCheckError::dummy(line!() as usize))
}
}
}
}
/// 戻り値ではなく、call全体の型を返す /// 戻り値ではなく、call全体の型を返す
fn search_callee_t( fn search_callee_t(
&self, &self,
obj: &hir::Expr, obj: &hir::Expr,
method_name: &Option<Token>, method_name: &Option<Identifier>,
namespace: &Str, namespace: &Str,
) -> TyCheckResult<Type> { ) -> TyCheckResult<Type> {
if let Some(method_name) = method_name.as_ref() { if let Some(method_name) = method_name.as_ref() {
for (_, ctx) in self.rec_get_nominal_super_type_ctxs(obj.ref_t()) { for (_, ctx) in self
if let Some(vi) = ctx.locals.get(method_name.inspect()) { .rec_get_nominal_super_type_ctxs(obj.ref_t())
return Ok(vi.t()); .ok_or_else(|| todo!())?
} else if let Some(vi) = ctx.decls.get(method_name.inspect()) { {
if let Some(vi) = ctx
.locals
.get(method_name.inspect())
.or_else(|| ctx.decls.get(method_name.inspect()))
{
self.validate_visibility(method_name, vi, namespace)?;
return Ok(vi.t()); return Ok(vi.t());
} }
for (_, methods_ctx) in ctx.methods_list.iter() {
if let Some(vi) = methods_ctx
.locals
.get(method_name.inspect())
.or_else(|| methods_ctx.decls.get(method_name.inspect()))
{
self.validate_visibility(method_name, vi, namespace)?;
return Ok(vi.t());
}
}
} }
if let Some(ctx) = self.rec_get_singular_ctx(obj) { if let Some(singular_ctx) = self.rec_get_singular_ctx(obj) {
if let Some(vi) = ctx.locals.get(method_name.inspect()) { if let Some(vi) = singular_ctx
return Ok(vi.t()); .locals
} else if let Some(vi) = ctx.decls.get(method_name.inspect()) { .get(method_name.inspect())
.or_else(|| singular_ctx.decls.get(method_name.inspect()))
{
self.validate_visibility(method_name, vi, namespace)?;
return Ok(vi.t()); return Ok(vi.t());
} }
for (_, method_ctx) in singular_ctx.methods_list.iter() {
if let Some(vi) = method_ctx
.locals
.get(method_name.inspect())
.or_else(|| method_ctx.decls.get(method_name.inspect()))
{
self.validate_visibility(method_name, vi, namespace)?;
return Ok(vi.t());
}
}
return Err(TyCheckError::singular_no_attr_error( return Err(TyCheckError::singular_no_attr_error(
line!() as usize, line!() as usize,
method_name.loc(), method_name.loc(),
@ -316,6 +412,38 @@ impl Context {
} }
} }
fn validate_visibility(
&self,
ident: &Identifier,
vi: &VarInfo,
namespace: &str,
) -> TyCheckResult<()> {
if ident.vis() != vi.vis {
Err(TyCheckError::visibility_error(
line!() as usize,
ident.loc(),
self.caused_by(),
ident.inspect(),
vi.vis,
))
// check if the private variable is loaded from the other scope
} else if vi.vis.is_private()
&& &self.name[..] != "<builtins>"
&& &self.name[..] != namespace
&& !namespace.contains(&self.name[..])
{
Err(TyCheckError::visibility_error(
line!() as usize,
ident.loc(),
self.caused_by(),
ident.inspect(),
Private,
))
} else {
Ok(())
}
}
pub(crate) fn get_binop_t( pub(crate) fn get_binop_t(
&self, &self,
op: &Token, op: &Token,
@ -325,14 +453,17 @@ impl Context {
erg_common::debug_power_assert!(args.len() == 2); erg_common::debug_power_assert!(args.len() == 2);
let cont = binop_to_dname(op.inspect()); let cont = binop_to_dname(op.inspect());
let symbol = Token::new(op.kind, Str::rc(cont), op.lineno, op.col_begin); let symbol = Token::new(op.kind, Str::rc(cont), op.lineno, op.col_begin);
let t = self.rec_get_var_t(&symbol, Private, namespace)?; let t = self.rec_get_var_t(
let op = hir::Expr::Accessor(hir::Accessor::local(symbol, t)); &Identifier::new(None, VarName::new(symbol.clone())),
namespace,
)?;
let op = hir::Expr::Accessor(hir::Accessor::private(symbol, t));
self.get_call_t(&op, &None, args, &[], namespace) self.get_call_t(&op, &None, args, &[], namespace)
.map_err(|e| { .map_err(|e| {
let op = enum_unwrap!(op, hir::Expr::Accessor:(hir::Accessor::Local:(_))); let op = enum_unwrap!(op, hir::Expr::Accessor:(hir::Accessor::Ident:(_)));
let lhs = args[0].expr.clone(); let lhs = args[0].expr.clone();
let rhs = args[1].expr.clone(); let rhs = args[1].expr.clone();
let bin = hir::BinOp::new(op.name, lhs, rhs, op.t); let bin = hir::BinOp::new(op.name.into_token(), lhs, rhs, op.t.clone());
// HACK: dname.loc()はダミーLocationしか返さないので、エラーならop.loc()で上書きする // HACK: dname.loc()はダミーLocationしか返さないので、エラーならop.loc()で上書きする
let core = ErrorCore::new( let core = ErrorCore::new(
e.core.errno, e.core.errno,
@ -354,13 +485,16 @@ impl Context {
erg_common::debug_power_assert!(args.len() == 1); erg_common::debug_power_assert!(args.len() == 1);
let cont = unaryop_to_dname(op.inspect()); let cont = unaryop_to_dname(op.inspect());
let symbol = Token::new(op.kind, Str::rc(cont), op.lineno, op.col_begin); let symbol = Token::new(op.kind, Str::rc(cont), op.lineno, op.col_begin);
let t = self.rec_get_var_t(&symbol, Private, namespace)?; let t = self.rec_get_var_t(
let op = hir::Expr::Accessor(hir::Accessor::local(symbol, t)); &Identifier::new(None, VarName::new(symbol.clone())),
namespace,
)?;
let op = hir::Expr::Accessor(hir::Accessor::private(symbol, t));
self.get_call_t(&op, &None, args, &[], namespace) self.get_call_t(&op, &None, args, &[], namespace)
.map_err(|e| { .map_err(|e| {
let op = enum_unwrap!(op, hir::Expr::Accessor:(hir::Accessor::Local:(_))); let op = enum_unwrap!(op, hir::Expr::Accessor:(hir::Accessor::Ident:(_)));
let expr = args[0].expr.clone(); let expr = args[0].expr.clone();
let unary = hir::UnaryOp::new(op.name, expr, op.t); let unary = hir::UnaryOp::new(op.name.into_token(), expr, op.t.clone());
let core = ErrorCore::new( let core = ErrorCore::new(
e.core.errno, e.core.errno,
e.core.kind, e.core.kind,
@ -374,15 +508,17 @@ impl Context {
/// 可変依存型の変更を伝搬させる /// 可変依存型の変更を伝搬させる
fn propagate(&self, t: &Type, callee: &hir::Expr) -> TyCheckResult<()> { fn propagate(&self, t: &Type, callee: &hir::Expr) -> TyCheckResult<()> {
if let Type::Subr(SubrType { if let Type::Subr(subr) = t {
kind: SubrKind::ProcMethod { if let Some(after) = subr.self_t().and_then(|self_t| {
after: Some(after), .. if let RefMut { after, .. } = self_t {
}, after.as_ref()
.. } else {
}) = t None
{ }
log!(info "{}, {}", callee.ref_t(), after); }) {
self.reunify(callee.ref_t(), after, Some(callee.loc()), None)?; log!(info "{}, {}", callee.ref_t(), after);
self.reunify(callee.ref_t(), after, Some(callee.loc()), None)?;
}
} }
Ok(()) Ok(())
} }
@ -415,14 +551,14 @@ impl Context {
} }
); );
let (new_sub, new_sup) = (self.resolve_trait(sub)?, self.resolve_trait(sup)?); let (new_sub, new_sup) = (self.resolve_trait(sub)?, self.resolve_trait(sup)?);
let new_constraint = Constraint::sandwiched(new_sub, new_sup, cyclic); let new_constraint = Constraint::new_sandwiched(new_sub, new_sup, cyclic);
fv.update_constraint(new_constraint); fv.update_constraint(new_constraint);
Ok(Type::FreeVar(fv)) Ok(Type::FreeVar(fv))
} }
Type::PolyTrait { name, params } if params.iter().all(|tp| tp.has_no_unbound_var()) => { Type::Poly { name, params } if params.iter().all(|tp| tp.has_no_unbound_var()) => {
let t_name = name.clone(); let t_name = name.clone();
let t_params = params.clone(); let t_params = params.clone();
let maybe_trait = Type::PolyTrait { name, params }; let maybe_trait = Type::Poly { name, params };
let mut min = Type::Obj; let mut min = Type::Obj;
for pair in self.rec_get_trait_impls(&t_name) { for pair in self.rec_get_trait_impls(&t_name) {
if self.rec_supertype_of(&pair.sup_trait, &maybe_trait) { if self.rec_supertype_of(&pair.sup_trait, &maybe_trait) {
@ -444,7 +580,7 @@ impl Context {
} }
} }
} }
Ok(poly_class(t_name, new_params)) Ok(poly(t_name, new_params))
} else { } else {
Ok(min) Ok(min)
} }
@ -491,9 +627,14 @@ impl Context {
let new_t = self.resolve_trait(*t)?; let new_t = self.resolve_trait(*t)?;
Ok(ref_(new_t)) Ok(ref_(new_t))
} }
Type::RefMut(t) => { Type::RefMut { before, after } => {
let new_t = self.resolve_trait(*t)?; let new_before = self.resolve_trait(*before)?;
Ok(ref_mut(new_t)) let new_after = if let Some(after) = after {
Some(self.resolve_trait(*after)?)
} else {
None
};
Ok(ref_mut(new_before, new_after))
} }
Type::Callable { .. } => todo!(), Type::Callable { .. } => todo!(),
Type::And(_, _) | Type::Or(_, _) | Type::Not(_, _) => todo!(), Type::And(_, _) | Type::Or(_, _) | Type::Not(_, _) => todo!(),
@ -511,15 +652,25 @@ impl Context {
fn substitute_call( fn substitute_call(
&self, &self,
obj: &hir::Expr, obj: &hir::Expr,
method_name: &Option<Token>, method_name: &Option<Identifier>,
instance: &Type, instance: &Type,
pos_args: &[hir::PosArg], pos_args: &[hir::PosArg],
kw_args: &[hir::KwArg], kw_args: &[hir::KwArg],
) -> TyCheckResult<()> { ) -> TyCheckResult<()> {
match instance { match instance {
Type::FreeVar(fv) if fv.is_linked() => {
self.substitute_call(obj, method_name, &fv.crack(), pos_args, kw_args)
}
Type::Refinement(refine) => {
self.substitute_call(obj, method_name, &refine.t, pos_args, kw_args)
}
Type::Subr(subr) => { Type::Subr(subr) => {
let callee = if let Some(name) = method_name { let callee = if let Some(ident) = method_name {
let attr = hir::Attribute::new(obj.clone(), name.clone(), Type::Ellipsis); let attr = hir::Attribute::new(
obj.clone(),
hir::Identifier::bare(ident.dot.clone(), ident.name.clone()),
Type::Uninited,
);
let acc = hir::Expr::Accessor(hir::Accessor::Attr(attr)); let acc = hir::Expr::Accessor(hir::Accessor::Attr(attr));
acc acc
} else { } else {
@ -540,12 +691,34 @@ impl Context {
)); ));
} }
let mut passed_params = set! {}; let mut passed_params = set! {};
if pos_args.len() >= subr.non_default_params.len() { let non_default_params_len = if method_name.is_some() {
let (non_default_args, var_args) = subr.non_default_params.len() - 1
pos_args.split_at(subr.non_default_params.len()); } else {
for (nd_arg, nd_param) in subr.non_default_params.len()
non_default_args.iter().zip(subr.non_default_params.iter()) };
if pos_args.len() >= non_default_params_len {
let (non_default_args, var_args) = pos_args.split_at(non_default_params_len);
let non_default_params = if subr
.non_default_params
.iter()
.next()
.map(|p| p.name().map(|s| &s[..]) == Some("self"))
.unwrap_or(false)
{ {
let mut non_default_params = subr.non_default_params.iter();
let self_pt = non_default_params.next().unwrap();
self.sub_unify(
obj.ref_t(),
self_pt.typ(),
Some(obj.loc()),
None,
self_pt.name(),
)?;
non_default_params
} else {
subr.non_default_params.iter()
};
for (nd_arg, nd_param) in non_default_args.iter().zip(non_default_params) {
self.substitute_pos_arg( self.substitute_pos_arg(
&callee, &callee,
&nd_arg.expr, &nd_arg.expr,
@ -609,7 +782,7 @@ impl Context {
log!(err "semi-unification failed with {callee}\n{arg_t} !<: {param_t}"); log!(err "semi-unification failed with {callee}\n{arg_t} !<: {param_t}");
log!(err "errno: {}", e.core.errno); log!(err "errno: {}", e.core.errno);
// REVIEW: // REVIEW:
let name = callee.var_full_name().unwrap_or_else(|| "".to_string()); let name = callee.show_acc().unwrap_or_else(|| "".to_string());
let name = name + "::" + param.name().map(|s| readable_name(&s[..])).unwrap_or(""); let name = name + "::" + param.name().map(|s| readable_name(&s[..])).unwrap_or("");
TyCheckError::type_mismatch_error( TyCheckError::type_mismatch_error(
line!() as usize, line!() as usize,
@ -650,7 +823,7 @@ impl Context {
log!(err "semi-unification failed with {callee}\n{arg_t} !<: {param_t}"); log!(err "semi-unification failed with {callee}\n{arg_t} !<: {param_t}");
log!(err "errno: {}", e.core.errno); log!(err "errno: {}", e.core.errno);
// REVIEW: // REVIEW:
let name = callee.var_full_name().unwrap_or_else(|| "".to_string()); let name = callee.show_acc().unwrap_or_else(|| "".to_string());
let name = name + "::" + param.name().map(|s| readable_name(&s[..])).unwrap_or(""); let name = name + "::" + param.name().map(|s| readable_name(&s[..])).unwrap_or("");
TyCheckError::type_mismatch_error( TyCheckError::type_mismatch_error(
line!() as usize, line!() as usize,
@ -693,7 +866,7 @@ impl Context {
log!(err "semi-unification failed with {callee}\n{arg_t} !<: {}", pt.typ()); log!(err "semi-unification failed with {callee}\n{arg_t} !<: {}", pt.typ());
log!(err "errno: {}", e.core.errno); log!(err "errno: {}", e.core.errno);
// REVIEW: // REVIEW:
let name = callee.var_full_name().unwrap_or_else(|| "".to_string()); let name = callee.show_acc().unwrap_or_else(|| "".to_string());
let name = name + "::" + readable_name(kw_name); let name = name + "::" + readable_name(kw_name);
TyCheckError::type_mismatch_error( TyCheckError::type_mismatch_error(
line!() as usize, line!() as usize,
@ -720,21 +893,23 @@ impl Context {
pub(crate) fn get_call_t( pub(crate) fn get_call_t(
&self, &self,
obj: &hir::Expr, obj: &hir::Expr,
method_name: &Option<Token>, method_name: &Option<Identifier>,
pos_args: &[hir::PosArg], pos_args: &[hir::PosArg],
kw_args: &[hir::KwArg], kw_args: &[hir::KwArg],
namespace: &Str, namespace: &Str,
) -> TyCheckResult<Type> { ) -> TyCheckResult<Type> {
match obj { match obj {
hir::Expr::Accessor(hir::Accessor::Local(local)) if &local.inspect()[..] == "match" => { hir::Expr::Accessor(hir::Accessor::Ident(local))
return self.get_match_call_t(pos_args, kw_args) if local.vis().is_private() && &local.inspect()[..] == "match" =>
{
return self.get_match_call_t(pos_args, kw_args);
} }
_ => {} _ => {}
} }
let found = self.search_callee_t(obj, method_name, namespace)?; let found = self.search_callee_t(obj, method_name, namespace)?;
log!( log!(
"Found:\ncallee: {obj}{}\nfound: {found}", "Found:\ncallee: {obj}{}\nfound: {found}",
fmt_option!(pre ".", method_name.as_ref().map(|t| &t.content)) fmt_option!(pre ".", method_name.as_ref().map(|ident| &ident.name))
); );
let instance = self.instantiate(found, obj)?; let instance = self.instantiate(found, obj)?;
log!( log!(
@ -744,7 +919,8 @@ impl Context {
); );
self.substitute_call(obj, method_name, &instance, pos_args, kw_args)?; self.substitute_call(obj, method_name, &instance, pos_args, kw_args)?;
log!(info "Substituted:\ninstance: {instance}"); log!(info "Substituted:\ninstance: {instance}");
let res = self.eval.eval_t_params(instance, &self, self.level)?; let level = self.level;
let res = self.eval_t_params(instance, level)?;
log!(info "Params evaluated:\nres: {res}\n"); log!(info "Params evaluated:\nres: {res}\n");
self.propagate(&res, obj)?; self.propagate(&res, obj)?;
log!(info "Propagated:\nres: {res}\n"); log!(info "Propagated:\nres: {res}\n");
@ -777,7 +953,10 @@ impl Context {
namespace: &Str, namespace: &Str,
) -> TyCheckResult<ValueObj> { ) -> TyCheckResult<ValueObj> {
let self_t = obj.ref_t(); let self_t = obj.ref_t();
for (_, ctx) in self.rec_get_nominal_super_type_ctxs(self_t) { for (_, ctx) in self
.rec_get_nominal_super_type_ctxs(self_t)
.ok_or_else(|| todo!())?
{
if let Ok(t) = ctx.get_const_local(name, namespace) { if let Ok(t) = ctx.get_const_local(name, namespace) {
return Ok(t); return Ok(t);
} }
@ -833,7 +1012,7 @@ impl Context {
} }
pub(crate) fn get_similar_attr<'a>(&'a self, self_t: &'a Type, name: &str) -> Option<&'a Str> { pub(crate) fn get_similar_attr<'a>(&'a self, self_t: &'a Type, name: &str) -> Option<&'a Str> {
for (_, ctx) in self.rec_get_nominal_super_type_ctxs(self_t) { for (_, ctx) in self.rec_get_nominal_super_type_ctxs(self_t)? {
if let Some(name) = ctx.get_similar_name(name) { if let Some(name) = ctx.get_similar_name(name) {
return Some(name); return Some(name);
} }
@ -943,49 +1122,40 @@ impl Context {
pub(crate) fn rec_get_nominal_super_trait_ctxs<'a>( pub(crate) fn rec_get_nominal_super_trait_ctxs<'a>(
&'a self, &'a self,
t: &Type, t: &Type,
) -> impl Iterator<Item = (&'a Type, &'a Context)> { ) -> Option<impl Iterator<Item = (&'a Type, &'a Context)>> {
if let Some((_ctx_t, ctx)) = self.rec_get_nominal_type_ctx(t) { let (_ctx_t, ctx) = self.rec_get_nominal_type_ctx(t)?;
ctx.super_traits.iter().map(|sup| { Some(ctx.super_traits.iter().map(|sup| {
let (_t, sup_ctx) = self.rec_get_nominal_type_ctx(sup).unwrap(); let (_t, sup_ctx) = self.rec_get_nominal_type_ctx(sup).unwrap();
(sup, sup_ctx) (sup, sup_ctx)
}) }))
} else {
todo!("{t} has no trait, or not a nominal type")
}
} }
pub(crate) fn rec_get_nominal_super_class_ctxs<'a>( pub(crate) fn rec_get_nominal_super_class_ctxs<'a>(
&'a self, &'a self,
t: &Type, t: &Type,
) -> impl Iterator<Item = (&'a Type, &'a Context)> { ) -> Option<impl Iterator<Item = (&'a Type, &'a Context)>> {
// if `t` is {S: Str | ...}, `ctx_t` will be Str // 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) // else if `t` is Array(Int, 10), `ctx_t` will be Array(T, N) (if Array(Int, 10) is not specialized)
if let Some((_ctx_t, ctx)) = self.rec_get_nominal_type_ctx(t) { let (_ctx_t, ctx) = self.rec_get_nominal_type_ctx(t)?;
// t: {S: Str | ...} => ctx.super_traits: [Eq(Str), Mul(Nat), ...] // 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 | ...}) // => return: [(Str, Eq(Str)), (Str, Mul(Nat)), ...] (the content of &'a Type isn't {S: Str | ...})
ctx.super_classes.iter().map(|sup| { Some(ctx.super_classes.iter().map(|sup| {
let (_t, sup_ctx) = self.rec_get_nominal_type_ctx(sup).unwrap(); let (_t, sup_ctx) = self.rec_get_nominal_type_ctx(sup).unwrap();
(sup, sup_ctx) (sup, sup_ctx)
}) }))
} else {
todo!("{t} has no class, or not a nominal type")
}
} }
pub(crate) fn rec_get_nominal_super_type_ctxs<'a>( pub(crate) fn rec_get_nominal_super_type_ctxs<'a>(
&'a self, &'a self,
t: &Type, t: &Type,
) -> impl Iterator<Item = (&'a Type, &'a Context)> { ) -> Option<impl Iterator<Item = (&'a Type, &'a Context)>> {
if let Some((t, ctx)) = self.rec_get_nominal_type_ctx(t) { let (t, ctx) = self.rec_get_nominal_type_ctx(t)?;
vec![(t, ctx)].into_iter().chain( let sups = ctx
ctx.super_classes .super_classes
.iter() .iter()
.chain(ctx.super_traits.iter()) .chain(ctx.super_traits.iter())
.map(|sup| self.rec_get_nominal_type_ctx(&sup).unwrap()), .map(|sup| self.rec_get_nominal_type_ctx(&sup).unwrap());
) Some(vec![(t, ctx)].into_iter().chain(sups))
} else {
todo!("{t} not found")
}
} }
pub(crate) fn rec_get_nominal_type_ctx<'a>( pub(crate) fn rec_get_nominal_type_ctx<'a>(
@ -993,32 +1163,52 @@ impl Context {
typ: &Type, typ: &Type,
) -> Option<(&'a Type, &'a Context)> { ) -> Option<(&'a Type, &'a Context)> {
match typ { match typ {
Type::FreeVar(fv) if fv.is_linked() => {
if let Some(res) = self.rec_get_nominal_type_ctx(&fv.crack()) {
return Some(res);
}
}
Type::FreeVar(fv) => {
let sup = fv.get_sup().unwrap();
if let Some(res) = self.rec_get_nominal_type_ctx(&sup) {
return Some(res);
}
}
Type::Refinement(refine) => { Type::Refinement(refine) => {
return self.rec_get_nominal_type_ctx(&refine.t); if let Some(res) = self.rec_get_nominal_type_ctx(&refine.t) {
return Some(res);
}
} }
Type::Quantified(_) => { Type::Quantified(_) => {
return self.rec_get_nominal_type_ctx(&class("QuantifiedFunction")); if let Some(res) = self.rec_get_nominal_type_ctx(&mono("QuantifiedFunction")) {
return Some(res);
}
} }
Type::PolyClass { name, params: _ } => { Type::Poly { name, params: _ } => {
if let Some((t, ctx)) = self.poly_classes.get(name) { if let Some((t, ctx)) = self.rec_get_poly_type(name) {
return Some((t, ctx)); return Some((t, ctx));
} }
} }
Type::PolyTrait { name, params: _ } => { /*Type::Record(rec) if rec.values().all(|attr| self.supertype_of(&Type, attr)) => {
if let Some((t, ctx)) = self.poly_traits.get(name) { // TODO: reference RecordType (inherits Type)
return Some((t, ctx)); if let Some(res) = self.rec_get_nominal_type_ctx(&Type) {
return Some(res);
} }
} }*/
Type::Record(rec) if rec.values().all(|attr| self.supertype_of(&Type, attr)) => {
return self.rec_get_nominal_type_ctx(&Type)
}
// FIXME: `F()`などの場合、実際は引数が省略されていてもmonomorphicになる // FIXME: `F()`などの場合、実際は引数が省略されていてもmonomorphicになる
other if other.is_monomorphic() => { other if other.is_monomorphic() => {
if let Some((t, ctx)) = self.mono_types.get(&typ.name()) { if let Some((t, ctx)) = self.rec_get_mono_type(&other.name()) {
return Some((t, ctx)); return Some((t, ctx));
} }
} }
other => todo!("{other}"), Type::Ref(t) | Type::RefMut { before: t, .. } => {
if let Some(res) = self.rec_get_nominal_type_ctx(t) {
return Some(res);
}
}
other => {
log!("{other} has no nominal definition");
}
} }
if let Some(outer) = &self.outer { if let Some(outer) = &self.outer {
outer.rec_get_nominal_type_ctx(typ) outer.rec_get_nominal_type_ctx(typ)
@ -1027,12 +1217,83 @@ impl Context {
} }
} }
pub(crate) fn rec_get_mut_nominal_type_ctx<'a>(
&'a mut self,
typ: &Type,
) -> Option<(&'a Type, &'a mut Context)> {
// SAFETY: `rec_get_nominal_type_ctx` is called only when `self` is not borrowed
let outer = unsafe {
(&mut self.outer as *mut Option<Box<Context>>)
.as_mut()
.unwrap()
};
match typ {
Type::FreeVar(fv) if fv.is_linked() => {
if let Some(res) = self.rec_get_mut_nominal_type_ctx(&fv.crack()) {
return Some(res);
}
}
Type::FreeVar(fv) => {
let sup = fv.get_sup().unwrap();
if let Some(res) = self.rec_get_mut_nominal_type_ctx(&sup) {
return Some(res);
}
}
Type::Refinement(refine) => {
if let Some(res) = self.rec_get_mut_nominal_type_ctx(&refine.t) {
return Some(res);
}
}
Type::Quantified(_) => {
if let Some(res) = self.rec_get_mut_nominal_type_ctx(&mono("QuantifiedFunction")) {
return Some(res);
}
}
Type::Poly { name, params: _ } => {
if let Some((t, ctx)) = self.rec_get_mut_poly_type(name) {
return Some((t, ctx));
}
}
/*Type::Record(rec) if rec.values().all(|attr| self.supertype_of(&Type, attr)) => {
// TODO: reference RecordType (inherits Type)
if let Some(res) = self.rec_get_nominal_type_ctx(&Type) {
return Some(res);
}
}*/
// FIXME: `F()`などの場合、実際は引数が省略されていてもmonomorphicになる
other if other.is_monomorphic() => {
if let Some((t, ctx)) = self.rec_get_mut_mono_type(&other.name()) {
return Some((t, ctx));
}
}
Type::Ref(t) | Type::RefMut { before: t, .. } => {
if let Some(res) = self.rec_get_mut_nominal_type_ctx(t) {
return Some(res);
}
}
other => {
log!("{other} has no nominal definition");
}
}
if let Some(outer) = outer {
outer.rec_get_mut_nominal_type_ctx(typ)
} else {
None
}
}
fn rec_get_singular_ctx(&self, obj: &hir::Expr) -> Option<&Context> { fn rec_get_singular_ctx(&self, obj: &hir::Expr) -> Option<&Context> {
match obj.ref_t() { match obj.ref_t() {
// TODO: attr // TODO: attr
Type::Module => self.rec_get_mod(&obj.var_full_name()?), Type::Module => self.rec_get_mod(&obj.show_acc()?),
Type::Class => todo!(), Type::Type | Type::Class => {
let typ = Type::Mono(Str::from(obj.show_acc().unwrap()));
self.rec_get_nominal_type_ctx(&typ).map(|(_, ctx)| ctx)
}
Type::Trait => todo!(), Type::Trait => todo!(),
Type::Refinement(refine) => {
self.rec_get_nominal_type_ctx(&refine.t).map(|(_, ctx)| ctx)
}
_ => None, _ => None,
} }
} }
@ -1073,8 +1334,14 @@ impl Context {
// rec_get_const_localとは違い、位置情報を持たないしエラーとならない // rec_get_const_localとは違い、位置情報を持たないしエラーとならない
pub(crate) fn rec_get_const_obj(&self, name: &str) -> Option<&ValueObj> { pub(crate) fn rec_get_const_obj(&self, name: &str) -> Option<&ValueObj> {
if let Some(val) = self.consts.get(name) { if let Some(val) = self.consts.get(name) {
Some(val) return Some(val);
} else if let Some(outer) = &self.outer { }
for (_, ctx) in self.methods_list.iter() {
if let Some(val) = ctx.consts.get(name) {
return Some(val);
}
}
if let Some(outer) = &self.outer {
outer.rec_get_const_obj(name) outer.rec_get_const_obj(name)
} else { } else {
None None
@ -1083,12 +1350,123 @@ impl Context {
pub(crate) fn rec_get_const_param_defaults(&self, name: &str) -> Option<&Vec<ConstTemplate>> { pub(crate) fn rec_get_const_param_defaults(&self, name: &str) -> Option<&Vec<ConstTemplate>> {
if let Some(impls) = self.const_param_defaults.get(name) { if let Some(impls) = self.const_param_defaults.get(name) {
return Some(impls); Some(impls)
} } else if let Some(outer) = &self.outer {
if let Some(outer) = &self.outer {
outer.rec_get_const_param_defaults(name) outer.rec_get_const_param_defaults(name)
} else { } else {
None None
} }
} }
pub(crate) fn rec_get_self_t(&self) -> Option<Type> {
if self.kind.is_method_def() || self.kind.is_type() {
// TODO: poly type
let name = self.name.split(&[':', '.']).last().unwrap();
let mono_t = mono(Str::rc(name));
if let Some((t, _)) = self.rec_get_nominal_type_ctx(&mono_t) {
Some(t.clone())
} else {
None
}
} else {
if let Some(outer) = &self.outer {
outer.rec_get_self_t()
} else {
None
}
}
}
fn rec_get_mono_type(&self, name: &str) -> Option<(&Type, &Context)> {
if let Some((t, ctx)) = self.mono_types.get(name) {
Some((t, ctx))
} else if let Some(outer) = &self.outer {
outer.rec_get_mono_type(name)
} else {
None
}
}
fn rec_get_poly_type(&self, name: &str) -> Option<(&Type, &Context)> {
if let Some((t, ctx)) = self.poly_types.get(name) {
Some((t, ctx))
} else if let Some(outer) = &self.outer {
outer.rec_get_poly_type(name)
} else {
None
}
}
fn rec_get_mut_mono_type(&mut self, name: &str) -> Option<(&mut Type, &mut Context)> {
if let Some((t, ctx)) = self.mono_types.get_mut(name) {
Some((t, ctx))
} else if let Some(outer) = self.outer.as_mut() {
outer.rec_get_mut_mono_type(name)
} else {
None
}
}
fn rec_get_mut_poly_type(&mut self, name: &str) -> Option<(&mut Type, &mut Context)> {
if let Some((t, ctx)) = self.poly_types.get_mut(name) {
Some((t, ctx))
} else if let Some(outer) = self.outer.as_mut() {
outer.rec_get_mut_poly_type(name)
} else {
None
}
}
fn rec_get_type(&self, name: &str) -> Option<(&Type, &Context)> {
if let Some((t, ctx)) = self.mono_types.get(name) {
Some((t, ctx))
} else if let Some((t, ctx)) = self.poly_types.get(name) {
Some((t, ctx))
} else if let Some(outer) = &self.outer {
outer.rec_get_type(name)
} else {
None
}
}
fn get_gen_t_require_attr_t<'a>(&'a self, gen: &'a GenTypeObj, attr: &str) -> Option<&'a Type> {
match gen.require_or_sup.typ() {
Type::Record(rec) => {
if let Some(t) = rec.get(attr) {
return Some(t);
}
}
other => {
let obj = self.rec_get_const_obj(&other.name());
let obj = enum_unwrap!(obj, Some:(ValueObj::Type:(TypeObj::Generated:(_))));
if let Some(t) = self.get_gen_t_require_attr_t(obj, attr) {
return Some(t);
}
}
}
if let Some(additional) = &gen.additional {
if let Type::Record(gen) = additional.typ() {
if let Some(t) = gen.get(attr) {
return Some(t);
}
}
}
None
}
pub(crate) fn _is_class(&self, typ: &Type) -> bool {
if let Some((_, ctx)) = self.rec_get_nominal_type_ctx(typ) {
ctx.kind.is_class()
} else {
todo!()
}
}
pub(crate) fn is_trait(&self, typ: &Type) -> bool {
if let Some((_, ctx)) = self.rec_get_nominal_type_ctx(typ) {
ctx.kind.is_trait()
} else {
todo!()
}
}
} }

View file

@ -7,25 +7,25 @@ use erg_common::set::Set;
use erg_common::traits::{Locational, Stream}; use erg_common::traits::{Locational, Stream};
use erg_common::Str; use erg_common::Str;
use erg_common::{assume_unreachable, enum_unwrap, set, try_map}; use erg_common::{assume_unreachable, enum_unwrap, set, try_map};
use erg_type::free::{Constraint, Cyclicity, FreeTyVar};
use TyParamOrdering::*;
use Type::*;
use ast::{ use ast::{
ParamSignature, ParamTySpec, PreDeclTypeSpec, SimpleTypeSpec, SubrKindSpec, TypeBoundSpec, ParamSignature, ParamTySpec, PreDeclTypeSpec, SimpleTypeSpec, TypeBoundSpec, TypeBoundSpecs,
TypeBoundSpecs, TypeSpec, TypeSpec,
}; };
use erg_parser::ast; use erg_parser::ast;
use erg_parser::token::TokenKind; use erg_parser::token::TokenKind;
use erg_type::constructors::*; use erg_type::constructors::*;
use erg_type::free::{Constraint, Cyclicity, FreeTyVar};
use erg_type::typaram::{IntervalOp, TyParam, TyParamOrdering}; use erg_type::typaram::{IntervalOp, TyParam, TyParamOrdering};
use erg_type::value::ValueObj; use erg_type::value::ValueObj;
use erg_type::{HasType, ParamTy, Predicate, SubrKind, TyBound, Type}; use erg_type::{HasType, ParamTy, Predicate, SubrKind, TyBound, Type};
use TyParamOrdering::*;
use Type::*;
use crate::context::eval::eval_lit;
use crate::context::{Context, RegistrationMode}; use crate::context::{Context, RegistrationMode};
use crate::error::TyCheckResult; use crate::error::TyCheckResult;
use crate::eval::eval_lit;
use crate::hir; use crate::hir;
use RegistrationMode::*; use RegistrationMode::*;
@ -78,16 +78,16 @@ impl TyVarContext {
) -> TyParam { ) -> TyParam {
match ct { match ct {
ConstTemplate::Obj(o) => match o { ConstTemplate::Obj(o) => match o {
ValueObj::Type(t) if t.is_mono_q() => { ValueObj::Type(t) if t.typ().is_mono_q() => {
if &t.name()[..] == "Self" { if &t.typ().name()[..] == "Self" {
let constraint = Constraint::type_of(Type); let constraint = Constraint::new_type_of(Type);
let t = named_free_var(Str::rc(var_name), self.level, constraint); let t = named_free_var(Str::rc(var_name), self.level, constraint);
TyParam::t(t) TyParam::t(t)
} else { } else {
todo!() todo!()
} }
} }
ValueObj::Type(t) => TyParam::t(*t.clone()), ValueObj::Type(t) => TyParam::t(t.typ().clone()),
v => TyParam::Value(v.clone()), v => TyParam::Value(v.clone()),
}, },
ConstTemplate::App { .. } => { ConstTemplate::App { .. } => {
@ -105,7 +105,7 @@ impl TyVarContext {
) -> Type { ) -> Type {
if let Some(temp_defaults) = ctx.rec_get_const_param_defaults(&name) { if let Some(temp_defaults) = ctx.rec_get_const_param_defaults(&name) {
let (_, ctx) = ctx let (_, ctx) = ctx
.rec_get_nominal_type_ctx(&poly_trait(name.clone(), params.clone())) .rec_get_nominal_type_ctx(&poly(name.clone(), params.clone()))
.unwrap_or_else(|| panic!("{} not found", name)); .unwrap_or_else(|| panic!("{} not found", name));
let defined_params_len = ctx.params.len(); let defined_params_len = ctx.params.len();
let given_params_len = params.len(); let given_params_len = params.len();
@ -130,9 +130,9 @@ impl TyVarContext {
self.push_or_init_typaram(&tp.tvar_name().unwrap(), &tp); self.push_or_init_typaram(&tp.tvar_name().unwrap(), &tp);
inst_defaults.push(tp); inst_defaults.push(tp);
} }
poly_trait(name, [inst_non_defaults, inst_defaults].concat()) poly(name, [inst_non_defaults, inst_defaults].concat())
} else { } else {
poly_trait( poly(
name, name,
params params
.into_iter() .into_iter()
@ -154,23 +154,22 @@ impl TyVarContext {
match bound { match bound {
TyBound::Sandwiched { sub, mid, sup } => { TyBound::Sandwiched { sub, mid, sup } => {
let sub_instance = match sub { let sub_instance = match sub {
Type::PolyTrait { name, params } => { Type::Poly { name, params } => {
self.instantiate_poly(mid.name(), &name, params, ctx) self.instantiate_poly(mid.name(), &name, params, ctx)
} }
Type::PolyClass { .. } => todo!(),
Type::MonoProj { lhs, rhs } => mono_proj(self.instantiate_qvar(*lhs), rhs), Type::MonoProj { lhs, rhs } => mono_proj(self.instantiate_qvar(*lhs), rhs),
sub => sub, sub => sub,
}; };
let sup_instance = match sup { let sup_instance = match sup {
Type::PolyTrait { name, params } => { Type::Poly { name, params } => {
self.instantiate_poly(mid.name(), &name, params, ctx) self.instantiate_poly(mid.name(), &name, params, ctx)
} }
Type::PolyClass { .. } => todo!(),
Type::MonoProj { lhs, rhs } => mono_proj(self.instantiate_qvar(*lhs), rhs), Type::MonoProj { lhs, rhs } => mono_proj(self.instantiate_qvar(*lhs), rhs),
sup => sup, sup => sup,
}; };
let name = mid.name(); let name = mid.name();
let constraint = Constraint::sandwiched(sub_instance, sup_instance, Cyclicity::Not); let constraint =
Constraint::new_sandwiched(sub_instance, sup_instance, Cyclicity::Not);
self.push_or_init_tyvar( self.push_or_init_tyvar(
&name, &name,
&named_free_var(name.clone(), self.level, constraint), &named_free_var(name.clone(), self.level, constraint),
@ -178,13 +177,12 @@ impl TyVarContext {
} }
TyBound::Instance { name, t } => { TyBound::Instance { name, t } => {
let t = match t { let t = match t {
Type::PolyClass { .. } => todo!(), Type::Poly { name, params } => {
Type::PolyTrait { name, params } => {
self.instantiate_poly(name.clone(), &name, params, ctx) self.instantiate_poly(name.clone(), &name, params, ctx)
} }
t => t, t => t,
}; };
let constraint = Constraint::type_of(t.clone()); let constraint = Constraint::new_type_of(t.clone());
// TODO: type-like types // TODO: type-like types
if t == Type { if t == Type {
if let Some(tv) = self.tyvar_instances.get(&name) { if let Some(tv) = self.tyvar_instances.get(&name) {
@ -305,7 +303,7 @@ impl TyVarContext {
} }
fn check_cyclicity_and_link(&self, name: &str, fv_inst: &FreeTyVar, tv: &Type) { fn check_cyclicity_and_link(&self, name: &str, fv_inst: &FreeTyVar, tv: &Type) {
let (sub, sup) = enum_unwrap!(tv, Type::FreeVar).crack_bound_types().unwrap(); let (sub, sup) = enum_unwrap!(tv, Type::FreeVar).get_bound_types().unwrap();
let new_cyclicity = match (sup.contains_tvar(name), sub.contains_tvar(name)) { let new_cyclicity = match (sup.contains_tvar(name), sub.contains_tvar(name)) {
(true, true) => Cyclicity::Both, (true, true) => Cyclicity::Both,
// T <: Super // T <: Super
@ -377,7 +375,7 @@ impl Context {
let spec_t = if let Some(s) = t_spec { let spec_t = if let Some(s) = t_spec {
self.instantiate_typespec(s, mode)? self.instantiate_typespec(s, mode)?
} else { } else {
free_var(self.level, Constraint::type_of(Type)) free_var(self.level, Constraint::new_type_of(Type))
}; };
if let Some(eval_t) = opt_eval_t { if let Some(eval_t) = opt_eval_t {
self.sub_unify(&eval_t, &spec_t, None, t_spec.map(|s| s.loc()), None)?; self.sub_unify(&eval_t, &spec_t, None, t_spec.map(|s| s.loc()), None)?;
@ -428,7 +426,7 @@ impl Context {
} else { } else {
self.level + 1 self.level + 1
}; };
free_var(level, Constraint::type_of(Type)) free_var(level, Constraint::new_type_of(Type))
}; };
if let Some(eval_ret_t) = eval_ret_t { if let Some(eval_ret_t) = eval_ret_t {
self.sub_unify( self.sub_unify(
@ -465,7 +463,7 @@ impl Context {
} else { } else {
self.level + 1 self.level + 1
}; };
free_var(level, Constraint::type_of(Type)) free_var(level, Constraint::new_type_of(Type))
} }
} }
}; };
@ -510,10 +508,10 @@ impl Context {
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(class("GenericArray")) Ok(mono("GenericArray"))
} }
} }
other if simple.args.is_empty() => Ok(class(Str::rc(other))), other if simple.args.is_empty() => Ok(mono(Str::rc(other))),
other => { other => {
// FIXME: kw args // FIXME: kw args
let params = simple.args.pos_args().map(|arg| match &arg.expr { let params = simple.args.pos_args().map(|arg| match &arg.expr {
@ -523,7 +521,7 @@ impl Context {
} }
}); });
// FIXME: if type is a trait // FIXME: if type is a trait
Ok(poly_class(Str::rc(other), params.collect())) Ok(poly(Str::rc(other), params.collect()))
} }
} }
} }
@ -543,7 +541,7 @@ impl Context {
expr: &ast::ConstExpr, expr: &ast::ConstExpr,
) -> TyCheckResult<Type> { ) -> TyCheckResult<Type> {
match expr { match expr {
ast::ConstExpr::Accessor(ast::ConstAccessor::Local(name)) => Ok(class(name.inspect())), ast::ConstExpr::Accessor(ast::ConstAccessor::Local(name)) => Ok(mono(name.inspect())),
_ => todo!(), _ => todo!(),
} }
} }
@ -608,9 +606,9 @@ impl Context {
_ => assume_unreachable!(), _ => assume_unreachable!(),
}; };
let l = self.instantiate_const_expr(lhs); let l = self.instantiate_const_expr(lhs);
let l = self.eval.eval_tp(&l, self)?; let l = self.eval_tp(&l)?;
let r = self.instantiate_const_expr(rhs); let r = self.instantiate_const_expr(rhs);
let r = self.eval.eval_tp(&r, self)?; let r = self.eval_tp(&r)?;
if let Some(Greater) = self.rec_try_cmp(&l, &r) { if let Some(Greater) = self.rec_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)")
} }
@ -632,7 +630,11 @@ impl Context {
.collect(); .collect();
let return_t = self.instantiate_typespec(&subr.return_t, mode)?; let return_t = self.instantiate_typespec(&subr.return_t, mode)?;
Ok(subr_t( Ok(subr_t(
self.instantiate_subr_kind(&subr.kind)?, if subr.arrow.is(TokenKind::FuncArrow) {
SubrKind::Func
} else {
SubrKind::Proc
},
non_defaults, non_defaults,
var_args, var_args,
defaults, defaults,
@ -642,23 +644,6 @@ impl Context {
} }
} }
fn instantiate_subr_kind(&self, kind: &SubrKindSpec) -> TyCheckResult<SubrKind> {
match kind {
SubrKindSpec::Func => Ok(SubrKind::Func),
SubrKindSpec::Proc => Ok(SubrKind::Proc),
SubrKindSpec::FuncMethod(spec) => {
Ok(SubrKind::fn_met(self.instantiate_typespec(spec, Normal)?))
}
SubrKindSpec::ProcMethod { before, after } => Ok(SubrKind::pr_met(
self.instantiate_typespec(before, Normal)?,
after
.as_ref()
.map(|after| self.instantiate_typespec(after, Normal))
.transpose()?,
)),
}
}
pub(crate) fn instantiate_ty_bound( pub(crate) fn instantiate_ty_bound(
&self, &self,
bound: &TypeBoundSpec, bound: &TypeBoundSpec,
@ -759,23 +744,6 @@ impl Context {
Type::Refinement(refine) Type::Refinement(refine)
} }
Subr(mut subr) => { Subr(mut subr) => {
let kind = match subr.kind {
SubrKind::FuncMethod(self_t) => {
let res = Self::instantiate_t(*self_t, tv_ctx);
SubrKind::FuncMethod(Box::new(res))
}
SubrKind::ProcMethod { before, after } => {
let before = Self::instantiate_t(*before, tv_ctx);
let after = if let Some(after) = after {
let after = Self::instantiate_t(*after, tv_ctx);
Some(after)
} else {
None
};
SubrKind::pr_met(before, after)
}
other => other,
};
for pt in subr.non_default_params.iter_mut() { for pt in subr.non_default_params.iter_mut() {
*pt.typ_mut() = Self::instantiate_t(mem::take(pt.typ_mut()), tv_ctx); *pt.typ_mut() = Self::instantiate_t(mem::take(pt.typ_mut()), tv_ctx);
} }
@ -788,7 +756,7 @@ impl Context {
} }
let return_t = Self::instantiate_t(*subr.return_t, tv_ctx); let return_t = Self::instantiate_t(*subr.return_t, tv_ctx);
subr_t( subr_t(
kind, subr.kind,
subr.non_default_params, subr.non_default_params,
subr.var_params.map(|p| *p), subr.var_params.map(|p| *p),
subr.default_params, subr.default_params,
@ -805,25 +773,24 @@ impl Context {
let t = Self::instantiate_t(*t, tv_ctx); let t = Self::instantiate_t(*t, tv_ctx);
ref_(t) ref_(t)
} }
RefMut(t) => { RefMut { before, after } => {
let t = Self::instantiate_t(*t, tv_ctx); let before = Self::instantiate_t(*before, tv_ctx);
ref_mut(t) let after = if let Some(after) = after {
Some(Self::instantiate_t(*after, tv_ctx))
} else {
None
};
ref_mut(before, after)
} }
MonoProj { lhs, rhs } => { MonoProj { lhs, rhs } => {
let lhs = Self::instantiate_t(*lhs, tv_ctx); let lhs = Self::instantiate_t(*lhs, tv_ctx);
mono_proj(lhs, rhs) mono_proj(lhs, rhs)
} }
PolyClass { name, mut params } => { Poly { name, mut params } => {
for param in params.iter_mut() { for param in params.iter_mut() {
*param = Self::instantiate_tp(mem::take(param), tv_ctx); *param = Self::instantiate_tp(mem::take(param), tv_ctx);
} }
poly_class(name, params) poly(name, params)
}
PolyTrait { name, mut params } => {
for param in params.iter_mut() {
*param = Self::instantiate_tp(mem::take(param), tv_ctx);
}
poly_trait(name, params)
} }
Quantified(_) => { Quantified(_) => {
panic!("a quantified type should not be instantiated, instantiate the inner type") panic!("a quantified type should not be instantiated, instantiate the inner type")
@ -839,9 +806,15 @@ impl Context {
let mut tv_ctx = TyVarContext::new(self.level, quant.bounds, &self); let mut tv_ctx = TyVarContext::new(self.level, quant.bounds, &self);
let t = Self::instantiate_t(*quant.unbound_callable, &mut tv_ctx); let t = Self::instantiate_t(*quant.unbound_callable, &mut tv_ctx);
match &t { match &t {
Type::Subr(subr) => match subr.kind.self_t() { Type::Subr(subr) => match subr.self_t() {
Some(l) => { Some(self_t) => {
self.unify(l, callee.ref_t(), None, Some(callee.loc()))?; self.sub_unify(
callee.ref_t(),
self_t,
None,
Some(callee.loc()),
Some(&Str::ever("self")),
)?;
} }
_ => {} _ => {}
}, },

View file

@ -2,6 +2,7 @@
//! `Context` is used for type inference and type checking. //! `Context` is used for type inference and type checking.
pub mod cache; pub mod cache;
pub mod compare; pub mod compare;
pub mod eval;
pub mod hint; pub mod hint;
pub mod initialize; pub mod initialize;
pub mod inquire; pub mod inquire;
@ -33,7 +34,6 @@ use erg_parser::token::Token;
use crate::context::instantiate::ConstTemplate; use crate::context::instantiate::ConstTemplate;
use crate::error::{TyCheckError, TyCheckErrors, TyCheckResult}; use crate::error::{TyCheckError, TyCheckErrors, TyCheckResult};
use crate::eval::Evaluator;
use crate::varinfo::{Mutability, ParamIdx, VarInfo, VarKind}; use crate::varinfo::{Mutability, ParamIdx, VarInfo, VarKind};
use Mutability::*; use Mutability::*;
use Visibility::*; use Visibility::*;
@ -85,7 +85,7 @@ pub enum TyParamIdx {
impl TyParamIdx { impl TyParamIdx {
pub fn search(search_from: &Type, target: &Type) -> Option<Self> { pub fn search(search_from: &Type, target: &Type) -> Option<Self> {
match search_from { match search_from {
Type::PolyClass { params, .. } => { Type::Poly { params, .. } => {
for (i, tp) in params.iter().enumerate() { for (i, tp) in params.iter().enumerate() {
match tp { match tp {
TyParam::Type(t) if t.as_ref() == target => return Some(Self::Nth(i)), TyParam::Type(t) if t.as_ref() == target => return Some(Self::Nth(i)),
@ -193,6 +193,7 @@ pub enum ContextKind {
Func, Func,
Proc, Proc,
Class, Class,
MethodDefs,
Trait, Trait,
StructuralTrait, StructuralTrait,
Patch(Type), Patch(Type),
@ -203,6 +204,24 @@ pub enum ContextKind {
Dummy, Dummy,
} }
impl ContextKind {
pub const fn is_method_def(&self) -> bool {
matches!(self, Self::MethodDefs)
}
pub const fn is_type(&self) -> bool {
matches!(self, Self::Class | Self::Trait | Self::StructuralTrait)
}
pub fn is_class(&self) -> bool {
matches!(self, Self::Class)
}
pub fn is_trait(&self) -> bool {
matches!(self, Self::Trait | Self::StructuralTrait)
}
}
/// 記号表に登録されているモードを表す /// 記号表に登録されているモードを表す
/// Preregister: サブルーチンまたは定数式、前方参照できる /// Preregister: サブルーチンまたは定数式、前方参照できる
/// Normal: 前方参照できない /// Normal: 前方参照できない
@ -215,7 +234,7 @@ pub enum RegistrationMode {
/// Represents the context of the current scope /// Represents the context of the current scope
/// ///
/// Recursive functions/methods are highlighted with the prefix `rec_`, as performance may be significantly degraded. /// Recursive functions/methods are highlighted with the prefix `rec_`, as performance may be significantly degraded.
#[derive(Debug)] #[derive(Debug, Clone)]
pub struct Context { pub struct Context {
pub(crate) name: Str, pub(crate) name: Str,
pub(crate) kind: ContextKind, pub(crate) kind: ContextKind,
@ -231,8 +250,9 @@ pub struct Context {
// patchによってsuper class/traitになったものはここに含まれない // patchによってsuper class/traitになったものはここに含まれない
pub(crate) super_classes: Vec<Type>, // if self is a patch, means patch classes pub(crate) super_classes: Vec<Type>, // if self is a patch, means patch classes
pub(crate) super_traits: Vec<Type>, // if self is not a trait, means implemented traits pub(crate) super_traits: Vec<Type>, // if self is not a trait, means implemented traits
// specialized contexts, If self is a type // method definitions, if the context is a type
pub(crate) specializations: Vec<(Type, Context)>, // specializations are included and needs to be separated out
pub(crate) methods_list: Vec<(Type, Context)>,
/// K: method name, V: impl patch /// K: method name, V: impl patch
/// Provided methods can switch implementations on a scope-by-scope basis /// Provided methods can switch implementations on a scope-by-scope basis
/// K: メソッド名, V: それを実装するパッチたち /// K: メソッド名, V: それを実装するパッチたち
@ -254,15 +274,12 @@ pub struct Context {
pub(crate) params: Vec<(Option<VarName>, VarInfo)>, pub(crate) params: Vec<(Option<VarName>, VarInfo)>,
pub(crate) locals: Dict<VarName, VarInfo>, pub(crate) locals: Dict<VarName, VarInfo>,
pub(crate) consts: Dict<VarName, ValueObj>, pub(crate) consts: Dict<VarName, ValueObj>,
pub(crate) eval: Evaluator,
// {"Nat": ctx, "Int": ctx, ...} // {"Nat": ctx, "Int": ctx, ...}
pub(crate) mono_types: Dict<VarName, (Type, Context)>, pub(crate) mono_types: Dict<VarName, (Type, Context)>,
// Implementation Contexts for Polymorphic Types // Implementation Contexts for Polymorphic Types
// Vec<TyParam> are specialization parameters // Vec<TyParam> are specialization parameters
// e.g. {"Array": [(Array(Nat), ctx), (Array(Int), ctx), (Array(Str), ctx), (Array(Obj), ctx), (Array('T), ctx)], ...} // e.g. {"Array": [(Array(Nat), ctx), (Array(Int), ctx), (Array(Str), ctx), (Array(Obj), ctx), (Array('T), ctx)], ...}
pub(crate) poly_classes: Dict<VarName, (Type, Context)>, pub(crate) poly_types: Dict<VarName, (Type, Context)>,
// Traits cannot be specialized
pub(crate) poly_traits: Dict<VarName, (Type, Context)>,
// patches can be accessed like normal records // patches can be accessed like normal records
// but when used as a fallback to a type, values are traversed instead of accessing by keys // but when used as a fallback to a type, values are traversed instead of accessing by keys
pub(crate) patches: Dict<VarName, Context>, pub(crate) patches: Dict<VarName, Context>,
@ -296,9 +313,8 @@ impl fmt::Display for Context {
.field("decls", &self.decls) .field("decls", &self.decls)
.field("locals", &self.params) .field("locals", &self.params)
.field("consts", &self.consts) .field("consts", &self.consts)
.field("eval", &self.eval)
.field("mono_types", &self.mono_types) .field("mono_types", &self.mono_types)
.field("poly_types", &self.poly_classes) .field("poly_types", &self.poly_types)
.field("patches", &self.patches) .field("patches", &self.patches)
.field("mods", &self.mods) .field("mods", &self.mods)
.finish() .finish()
@ -345,12 +361,12 @@ impl Context {
let idx = ParamIdx::Nth(idx); let idx = ParamIdx::Nth(idx);
let kind = VarKind::parameter(id, idx, param.default_info); let kind = VarKind::parameter(id, idx, param.default_info);
// TODO: is_const { Const } else { Immutable } // TODO: is_const { Const } else { Immutable }
let vi = VarInfo::new(param.t, Immutable, Private, kind); let vi = VarInfo::new(param.t, Immutable, Private, kind, None);
params_.push((Some(VarName::new(Token::static_symbol(name))), vi)); params_.push((Some(VarName::new(Token::static_symbol(name))), vi));
} else { } else {
let idx = ParamIdx::Nth(idx); let idx = ParamIdx::Nth(idx);
let kind = VarKind::parameter(id, idx, param.default_info); let kind = VarKind::parameter(id, idx, param.default_info);
let vi = VarInfo::new(param.t, Immutable, Private, kind); let vi = VarInfo::new(param.t, Immutable, Private, kind, None);
params_.push((None, vi)); params_.push((None, vi));
} }
} }
@ -362,7 +378,7 @@ impl Context {
outer: outer.map(Box::new), outer: outer.map(Box::new),
super_classes, super_classes,
super_traits, super_traits,
specializations: vec![], methods_list: vec![],
const_param_defaults: Dict::default(), const_param_defaults: Dict::default(),
method_impl_patches: Dict::default(), method_impl_patches: Dict::default(),
trait_impls: Dict::default(), trait_impls: Dict::default(),
@ -370,10 +386,8 @@ impl Context {
decls: Dict::default(), decls: Dict::default(),
locals: Dict::with_capacity(capacity), locals: Dict::with_capacity(capacity),
consts: Dict::default(), consts: Dict::default(),
eval: Evaluator::default(),
mono_types: Dict::default(), mono_types: Dict::default(),
poly_classes: Dict::default(), poly_types: Dict::default(),
poly_traits: Dict::default(),
mods: Dict::default(), mods: Dict::default(),
patches: Dict::default(), patches: Dict::default(),
_nlocals: 0, _nlocals: 0,
@ -476,6 +490,20 @@ impl Context {
Self::poly_class(name, vec![], super_classes, super_traits, level) Self::poly_class(name, vec![], super_classes, super_traits, level)
} }
#[inline]
pub fn methods<S: Into<Str>>(name: S, level: usize) -> Self {
Self::with_capacity(
name.into(),
ContextKind::MethodDefs,
vec![],
None,
vec![],
vec![],
2,
level,
)
}
#[inline] #[inline]
pub fn poly_patch<S: Into<Str>>( pub fn poly_patch<S: Into<Str>>(
name: S, name: S,
@ -509,6 +537,20 @@ impl Context {
) )
} }
#[inline]
pub fn instant(name: Str, capacity: usize, outer: Context) -> Self {
Self::with_capacity(
name,
ContextKind::Instant,
vec![],
Some(outer),
vec![],
vec![],
capacity,
Self::TOP_LEVEL,
)
}
#[inline] #[inline]
pub fn caused_by(&self) -> Str { pub fn caused_by(&self) -> Str {
self.name.clone() self.name.clone()
@ -532,7 +574,7 @@ impl Context {
Ok(()) Ok(())
} }
pub(crate) fn pop(&mut self) -> Result<(), TyCheckErrors> { pub(crate) fn pop(&mut self) -> Result<Context, TyCheckErrors> {
let mut uninited_errs = TyCheckErrors::empty(); let mut uninited_errs = TyCheckErrors::empty();
for (name, vi) in self.decls.iter() { for (name, vi) in self.decls.iter() {
uninited_errs.push(TyCheckError::uninitialized_error( uninited_errs.push(TyCheckError::uninitialized_error(
@ -544,12 +586,14 @@ impl Context {
)); ));
} }
if let Some(parent) = &mut self.outer { if let Some(parent) = &mut self.outer {
*self = mem::take(parent); let parent = mem::take(parent);
let ctx = mem::take(self);
*self = *parent;
log!(info "{}: current namespace: {}", fn_name!(), self.name); log!(info "{}: current namespace: {}", fn_name!(), self.name);
if !uninited_errs.is_empty() { if !uninited_errs.is_empty() {
Err(uninited_errs) Err(uninited_errs)
} else { } else {
Ok(()) Ok(ctx)
} }
} else { } else {
Err(TyCheckErrors::from(TyCheckError::checker_bug( Err(TyCheckErrors::from(TyCheckError::checker_bug(

View file

@ -1,20 +1,20 @@
use std::option::Option; // conflicting to Type::Option use std::option::Option; // conflicting to Type::Option
use erg_common::traits::Locational; use erg_common::traits::{Locational, Stream};
use erg_common::vis::Visibility; use erg_common::vis::Visibility;
use erg_common::Str; use erg_common::Str;
use erg_common::{enum_unwrap, get_hash, log, set}; use erg_common::{enum_unwrap, get_hash, log, set};
use erg_type::free::HasLevel; use erg_type::free::HasLevel;
use ast::{DefId, VarName}; use ast::{DefId, Identifier, VarName};
use erg_parser::ast; use erg_parser::ast;
use erg_type::constructors::{enum_t, func, proc}; use erg_type::constructors::{enum_t, func, func1, proc, ref_, ref_mut};
use erg_type::value::ValueObj; use erg_type::value::{GenTypeObj, TypeKind, TypeObj, ValueObj};
use erg_type::{HasType, ParamTy, SubrType, TyBound, Type}; use erg_type::{HasType, ParamTy, SubrType, TyBound, Type};
use Type::*; use Type::*;
use crate::context::{Context, DefaultInfo, RegistrationMode}; use crate::context::{Context, DefaultInfo, RegistrationMode, TraitInstance};
use crate::error::readable_name; use crate::error::readable_name;
use crate::error::{TyCheckError, TyCheckResult}; use crate::error::{TyCheckError, TyCheckResult};
use crate::hir; use crate::hir;
@ -24,7 +24,8 @@ use RegistrationMode::*;
use Visibility::*; use Visibility::*;
impl Context { impl Context {
fn registered(&self, name: &Str, recursive: bool) -> bool { /// If it is a constant that is defined, there must be no variable of the same name defined across all scopes
fn registered(&self, name: &Str, is_const: bool) -> bool {
if self.params.iter().any(|(maybe_name, _)| { if self.params.iter().any(|(maybe_name, _)| {
maybe_name maybe_name
.as_ref() .as_ref()
@ -34,9 +35,9 @@ impl Context {
{ {
return true; return true;
} }
if recursive { if is_const {
if let Some(outer) = &self.outer { if let Some(outer) = &self.outer {
outer.registered(name, recursive) outer.registered(name, is_const)
} else { } else {
false false
} }
@ -45,7 +46,7 @@ impl Context {
} }
} }
fn declare_var( fn _declare_var(
&mut self, &mut self,
sig: &ast::VarSignature, sig: &ast::VarSignature,
opt_t: Option<Type>, opt_t: Option<Type>,
@ -54,30 +55,22 @@ impl Context {
let muty = Mutability::from(&sig.inspect().unwrap()[..]); let muty = Mutability::from(&sig.inspect().unwrap()[..]);
match &sig.pat { match &sig.pat {
ast::VarPattern::Ident(ident) => { ast::VarPattern::Ident(ident) => {
if sig.t_spec.is_none() && opt_t.is_none() { if self.registered(ident.inspect(), ident.is_const()) {
Err(TyCheckError::no_type_spec_error( return Err(TyCheckError::duplicate_decl_error(
line!() as usize, line!() as usize,
sig.loc(), sig.loc(),
self.caused_by(), self.caused_by(),
ident.inspect(), ident.inspect(),
)) ));
} else {
if self.registered(ident.inspect(), ident.is_const()) {
return Err(TyCheckError::duplicate_decl_error(
line!() as usize,
sig.loc(),
self.caused_by(),
ident.inspect(),
));
}
let vis = ident.vis();
let kind = id.map_or(VarKind::Declared, VarKind::Defined);
let sig_t =
self.instantiate_var_sig_t(sig.t_spec.as_ref(), opt_t, PreRegister)?;
self.decls
.insert(ident.name.clone(), VarInfo::new(sig_t, muty, vis, kind));
Ok(())
} }
let vis = ident.vis();
let kind = id.map_or(VarKind::Declared, VarKind::Defined);
let sig_t = self.instantiate_var_sig_t(sig.t_spec.as_ref(), opt_t, PreRegister)?;
self.decls.insert(
ident.name.clone(),
VarInfo::new(sig_t, muty, vis, kind, None),
);
Ok(())
} }
_ => todo!(), _ => todo!(),
} }
@ -102,7 +95,17 @@ impl Context {
)); ));
} }
let t = self.instantiate_sub_sig_t(sig, opt_ret_t, PreRegister)?; let t = self.instantiate_sub_sig_t(sig, opt_ret_t, PreRegister)?;
let vi = VarInfo::new(t, muty, vis, kind); let comptime_decos = sig
.decorators
.iter()
.filter_map(|deco| match &deco.0 {
ast::Expr::Accessor(ast::Accessor::Ident(local)) if local.is_const() => {
Some(local.inspect().clone())
}
_ => None,
})
.collect();
let vi = VarInfo::new(t, muty, vis, kind, Some(comptime_decos));
if let Some(_decl) = self.decls.remove(name) { if let Some(_decl) = self.decls.remove(name) {
return Err(TyCheckError::duplicate_decl_error( return Err(TyCheckError::duplicate_decl_error(
line!() as usize, line!() as usize,
@ -122,6 +125,10 @@ impl Context {
body_t: &Type, body_t: &Type,
id: DefId, id: DefId,
) -> TyCheckResult<()> { ) -> TyCheckResult<()> {
// already defined as const
if sig.is_const() {
return Ok(());
}
let ident = match &sig.pat { let ident = match &sig.pat {
ast::VarPattern::Ident(ident) => ident, ast::VarPattern::Ident(ident) => ident,
_ => todo!(), _ => todo!(),
@ -141,7 +148,7 @@ impl Context {
// something to do? // something to do?
} }
let vis = ident.vis(); let vis = ident.vis();
let vi = VarInfo::new(generalized, muty, vis, VarKind::Defined(id)); let vi = VarInfo::new(generalized, muty, vis, VarKind::Defined(id), None);
self.locals.insert(ident.name.clone(), vi); self.locals.insert(ident.name.clone(), vi);
Ok(()) Ok(())
} }
@ -156,18 +163,29 @@ impl Context {
opt_decl_t: Option<&ParamTy>, opt_decl_t: Option<&ParamTy>,
) -> TyCheckResult<()> { ) -> TyCheckResult<()> {
match &sig.pat { match &sig.pat {
ast::ParamPattern::Lit(_) => Ok(()),
ast::ParamPattern::Discard(_token) => Ok(()), ast::ParamPattern::Discard(_token) => Ok(()),
ast::ParamPattern::VarName(v) => { ast::ParamPattern::VarName(name) => {
if self.registered(v.inspect(), v.inspect().is_uppercase()) { if self.registered(name.inspect(), name.is_const()) {
Err(TyCheckError::reassign_error( Err(TyCheckError::reassign_error(
line!() as usize, line!() as usize,
v.loc(), name.loc(),
self.caused_by(), self.caused_by(),
v.inspect(), name.inspect(),
)) ))
} else { } else {
// ok, not defined // ok, not defined
let spec_t = self.instantiate_param_sig_t(sig, opt_decl_t, Normal)?; let spec_t = self.instantiate_param_sig_t(sig, opt_decl_t, Normal)?;
if &name.inspect()[..] == "self" {
let self_t = self.rec_get_self_t().unwrap();
self.sub_unify(
&spec_t,
&self_t,
Some(name.loc()),
None,
Some(name.inspect()),
)?;
}
let idx = if let Some(outer) = outer { let idx = if let Some(outer) = outer {
ParamIdx::nested(outer, nth) ParamIdx::nested(outer, nth)
} else { } else {
@ -178,16 +196,101 @@ impl Context {
} else { } else {
DefaultInfo::NonDefault DefaultInfo::NonDefault
}; };
let kind = VarKind::parameter(DefId(get_hash(&(&self.name, v))), idx, default); let kind =
VarKind::parameter(DefId(get_hash(&(&self.name, name))), idx, default);
self.params.push(( self.params.push((
Some(v.clone()), Some(name.clone()),
VarInfo::new(spec_t, Immutable, Private, kind), VarInfo::new(spec_t, Immutable, Private, kind, None),
)); ));
Ok(()) Ok(())
} }
} }
ast::ParamPattern::Lit(_) => Ok(()), ast::ParamPattern::Ref(name) => {
_ => unreachable!(), if self.registered(name.inspect(), name.is_const()) {
Err(TyCheckError::reassign_error(
line!() as usize,
name.loc(),
self.caused_by(),
name.inspect(),
))
} else {
// ok, not defined
let spec_t = self.instantiate_param_sig_t(sig, opt_decl_t, Normal)?;
if &name.inspect()[..] == "self" {
let self_t = self.rec_get_self_t().unwrap();
self.sub_unify(
&spec_t,
&self_t,
Some(name.loc()),
None,
Some(name.inspect()),
)?;
}
let spec_t = ref_(spec_t);
let idx = if let Some(outer) = outer {
ParamIdx::nested(outer, nth)
} else {
ParamIdx::Nth(nth)
};
let default = if sig.opt_default_val.is_some() {
DefaultInfo::WithDefault
} else {
DefaultInfo::NonDefault
};
let kind =
VarKind::parameter(DefId(get_hash(&(&self.name, name))), idx, default);
self.params.push((
Some(name.clone()),
VarInfo::new(spec_t, Immutable, Private, kind, None),
));
Ok(())
}
}
ast::ParamPattern::RefMut(name) => {
if self.registered(name.inspect(), name.is_const()) {
Err(TyCheckError::reassign_error(
line!() as usize,
name.loc(),
self.caused_by(),
name.inspect(),
))
} else {
// ok, not defined
let spec_t = self.instantiate_param_sig_t(sig, opt_decl_t, Normal)?;
if &name.inspect()[..] == "self" {
let self_t = self.rec_get_self_t().unwrap();
self.sub_unify(
&spec_t,
&self_t,
Some(name.loc()),
None,
Some(name.inspect()),
)?;
}
let spec_t = ref_mut(spec_t.clone(), Some(spec_t));
let idx = if let Some(outer) = outer {
ParamIdx::nested(outer, nth)
} else {
ParamIdx::Nth(nth)
};
let default = if sig.opt_default_val.is_some() {
DefaultInfo::WithDefault
} else {
DefaultInfo::NonDefault
};
let kind =
VarKind::parameter(DefId(get_hash(&(&self.name, name))), idx, default);
self.params.push((
Some(name.clone()),
VarInfo::new(spec_t, Immutable, Private, kind, None),
));
Ok(())
}
}
other => {
log!(err "{other}");
unreachable!()
}
} }
} }
@ -236,6 +339,10 @@ impl Context {
id: DefId, id: DefId,
body_t: &Type, body_t: &Type,
) -> TyCheckResult<()> { ) -> TyCheckResult<()> {
// already defined as const
if sig.is_const() {
return Ok(());
}
let muty = if sig.ident.is_const() { let muty = if sig.ident.is_const() {
Mutability::Const Mutability::Const
} else { } else {
@ -263,7 +370,7 @@ impl Context {
) )
})?; })?;
} }
if self.registered(name.inspect(), name.inspect().is_uppercase()) { if self.registered(name.inspect(), name.is_const()) {
Err(TyCheckError::reassign_error( Err(TyCheckError::reassign_error(
line!() as usize, line!() as usize,
name.loc(), name.loc(),
@ -307,48 +414,263 @@ impl Context {
)); ));
} }
} }
// TODO: visibility let comptime_decos = sig
let vi = VarInfo::new(found_t, muty, Private, VarKind::Defined(id)); .decorators
.iter()
.filter_map(|deco| match &deco.0 {
ast::Expr::Accessor(ast::Accessor::Ident(local)) if local.is_const() => {
Some(local.inspect().clone())
}
_ => None,
})
.collect();
let vi = VarInfo::new(
found_t,
muty,
sig.ident.vis(),
VarKind::Defined(id),
Some(comptime_decos),
);
log!(info "Registered {}::{name}: {}", self.name, &vi.t); log!(info "Registered {}::{name}: {}", self.name, &vi.t);
self.params.push((Some(name.clone()), vi)); self.locals.insert(name.clone(), vi);
Ok(()) Ok(())
} }
} }
// 再帰サブルーチン/型の推論を可能にするため、予め登録しておく // To allow forward references and recursive definitions
pub(crate) fn preregister(&mut self, block: &[ast::Expr]) -> TyCheckResult<()> { pub(crate) fn preregister(&mut self, block: &ast::Block) -> TyCheckResult<()> {
for expr in block.iter() { for expr in block.iter() {
if let ast::Expr::Def(def) = expr { match expr {
let id = Some(def.body.id); ast::Expr::Def(def) => {
let eval_body_t = || { self.preregister_def(def)?;
self.eval
.eval_const_block(&def.body.block, self)
.map(|c| enum_t(set![c]))
};
match &def.sig {
ast::Signature::Subr(sig) => {
let opt_ret_t = if let Some(spec) = sig.return_t_spec.as_ref() {
Some(self.instantiate_typespec(spec, PreRegister)?)
} else {
eval_body_t()
};
self.declare_sub(sig, opt_ret_t, id)?;
}
ast::Signature::Var(sig) if sig.is_const() => {
let t = if let Some(spec) = sig.t_spec.as_ref() {
Some(self.instantiate_typespec(spec, PreRegister)?)
} else {
eval_body_t()
};
self.declare_var(sig, t, id)?;
}
_ => {}
} }
ast::Expr::ClassDef(class_def) => {
self.preregister_def(&class_def.def)?;
}
_ => {}
} }
} }
Ok(()) Ok(())
} }
pub(crate) fn preregister_def(&mut self, def: &ast::Def) -> TyCheckResult<()> {
let id = Some(def.body.id);
let __name__ = def.sig.ident().map(|i| i.inspect());
match &def.sig {
ast::Signature::Subr(sig) => {
if sig.is_const() {
let (obj, const_t) = match self.eval_const_block(&def.body.block, __name__) {
Ok(obj) => (obj.clone(), enum_t(set! {obj})),
Err(e) => {
return Err(e);
}
};
if let Some(spec) = sig.return_t_spec.as_ref() {
let spec_t = self.instantiate_typespec(spec, PreRegister)?;
self.sub_unify(&const_t, &spec_t, Some(def.body.loc()), None, None)?;
}
self.register_gen_const(def.sig.ident().unwrap(), obj);
} else {
let opt_ret_t = if let Some(spec) = sig.return_t_spec.as_ref() {
let spec_t = self.instantiate_typespec(spec, PreRegister)?;
Some(spec_t)
} else {
None
};
self.declare_sub(sig, opt_ret_t, id)?;
}
}
ast::Signature::Var(sig) if sig.is_const() => {
let (obj, const_t) = match self.eval_const_block(&def.body.block, __name__) {
Ok(obj) => (obj.clone(), enum_t(set! {obj})),
Err(e) => {
return Err(e);
}
};
if let Some(spec) = sig.t_spec.as_ref() {
let spec_t = self.instantiate_typespec(spec, PreRegister)?;
self.sub_unify(&const_t, &spec_t, Some(def.body.loc()), None, None)?;
}
self.register_gen_const(sig.ident().unwrap(), obj);
}
_ => {}
}
Ok(())
}
/// e.g. .new
fn register_auto_impl(
&mut self,
name: &'static str,
t: Type,
muty: Mutability,
vis: Visibility,
) {
let name = VarName::from_static(name);
if self.locals.get(&name).is_some() {
panic!("already registered: {name}");
} else {
self.locals
.insert(name, VarInfo::new(t, muty, vis, VarKind::Auto, None));
}
}
/// e.g. ::__new__
fn register_fixed_auto_impl(
&mut self,
name: &'static str,
t: Type,
muty: Mutability,
vis: Visibility,
) {
let name = VarName::from_static(name);
if self.locals.get(&name).is_some() {
panic!("already registered: {name}");
} else {
self.locals
.insert(name, VarInfo::new(t, muty, vis, VarKind::FixedAuto, None));
}
}
fn _register_gen_decl(&mut self, name: VarName, t: Type, vis: Visibility) {
if self.decls.get(&name).is_some() {
panic!("already registered: {name}");
} else {
self.decls.insert(
name,
VarInfo::new(t, Immutable, vis, VarKind::Declared, None),
);
}
}
fn _register_gen_impl(&mut self, name: VarName, t: Type, muty: Mutability, vis: Visibility) {
if self.locals.get(&name).is_some() {
panic!("already registered: {name}");
} else {
let id = DefId(get_hash(&(&self.name, &name)));
self.locals
.insert(name, VarInfo::new(t, muty, vis, VarKind::Defined(id), None));
}
}
pub(crate) fn register_gen_const(&mut self, ident: &Identifier, obj: ValueObj) {
if self.rec_get_const_obj(ident.inspect()).is_some() {
panic!("already registered: {ident}");
} else {
match obj {
ValueObj::Type(t) => {
let gen = enum_unwrap!(t, TypeObj::Generated);
self.register_gen_type(gen);
}
// TODO: not all value objects are comparable
other => {
let id = DefId(get_hash(ident));
let vi = VarInfo::new(
enum_t(set! {other.clone()}),
Const,
ident.vis(),
VarKind::Defined(id),
None,
);
self.consts.insert(ident.name.clone(), other);
self.locals.insert(ident.name.clone(), vi);
}
}
}
}
fn register_gen_type(&mut self, gen: GenTypeObj) {
match gen.kind {
TypeKind::Class => {
if gen.t.is_monomorphic() {
let super_traits = gen.impls.iter().map(|to| to.typ().clone()).collect();
let mut ctx = Self::mono_class(gen.t.name(), vec![], super_traits, self.level);
let mut methods = Self::methods(gen.t.name(), self.level);
let require = gen.require_or_sup.typ().clone();
let new_t = func1(require, gen.t.clone());
methods.register_fixed_auto_impl("__new__", new_t.clone(), Immutable, Private);
// 必要なら、ユーザーが独自に上書きする
methods.register_auto_impl("new", new_t, Immutable, Public);
ctx.methods_list.push((gen.t.clone(), methods));
self.register_gen_mono_type(gen, ctx, Const);
} else {
todo!()
}
}
TypeKind::Subclass => {
if gen.t.is_monomorphic() {
let super_classes = vec![gen.require_or_sup.typ().clone()];
let super_traits = gen.impls.iter().map(|to| to.typ().clone()).collect();
let mut ctx =
Self::mono_class(gen.t.name(), super_classes, super_traits, self.level);
let mut methods = Self::methods(gen.t.name(), self.level);
if let Some(sup) = self.rec_get_const_obj(&gen.require_or_sup.typ().name()) {
let sup = enum_unwrap!(sup, ValueObj::Type);
let param_t = match sup {
TypeObj::Builtin(t) => t,
TypeObj::Generated(t) => t.require_or_sup.as_ref().typ(),
};
// `Super.Requirement := {x = Int}` and `Self.Additional := {y = Int}`
// => `Self.Requirement := {x = Int; y = Int}`
let param_t = if let Some(additional) = &gen.additional {
self.rec_intersection(&param_t, additional.typ())
} else {
param_t.clone()
};
let new_t = func1(param_t, gen.t.clone());
methods.register_fixed_auto_impl(
"__new__",
new_t.clone(),
Immutable,
Private,
);
// 必要なら、ユーザーが独自に上書きする
methods.register_auto_impl("new", new_t, Immutable, Public);
ctx.methods_list.push((gen.t.clone(), methods));
self.register_gen_mono_type(gen, ctx, Const);
} else {
todo!("super class not found")
}
} else {
todo!()
}
}
other => todo!("{other:?}"),
}
}
fn register_gen_mono_type(&mut self, gen: GenTypeObj, ctx: Self, muty: Mutability) {
// FIXME: not panic but error
// FIXME: recursive search
if self.mono_types.contains_key(&gen.t.name()) {
panic!("{} has already been registered", gen.t.name());
} else if self.rec_get_const_obj(&gen.t.name()).is_some() {
panic!("{} has already been registered as const", gen.t.name());
} else {
let t = gen.t.clone();
let meta_t = gen.meta_type();
let name = VarName::from_str(gen.t.name());
let id = DefId(get_hash(&(&self.name, &name)));
self.locals.insert(
name.clone(),
VarInfo::new(meta_t, muty, Private, VarKind::Defined(id), None),
);
self.consts
.insert(name.clone(), ValueObj::Type(TypeObj::Generated(gen)));
for impl_trait in ctx.super_traits.iter() {
if let Some(impls) = self.trait_impls.get_mut(&impl_trait.name()) {
impls.push(TraitInstance::new(t.clone(), impl_trait.clone()));
} else {
self.trait_impls.insert(
impl_trait.name(),
vec![TraitInstance::new(t.clone(), impl_trait.clone())],
);
}
}
self.mono_types.insert(name, (t, ctx));
}
}
pub(crate) fn import_mod( pub(crate) fn import_mod(
&mut self, &mut self,
var_name: &VarName, var_name: &VarName,

View file

@ -2,7 +2,7 @@
use erg_common::Str; use erg_common::Str;
use erg_common::{enum_unwrap, set}; use erg_common::{enum_unwrap, set};
use erg_type::constructors::{func1, mono_q, poly_trait, quant, refinement}; use erg_type::constructors::{func1, mono_q, poly, quant, refinement};
use erg_type::typaram::TyParam; use erg_type::typaram::TyParam;
use erg_type::{Predicate, TyBound, Type}; use erg_type::{Predicate, TyBound, Type};
use Type::*; use Type::*;
@ -28,7 +28,7 @@ impl Context {
} }
pub fn test_resolve_trait(&self) -> Result<(), ()> { pub fn test_resolve_trait(&self) -> Result<(), ()> {
let t = poly_trait("Add", vec![TyParam::t(Nat)]); let t = poly("Add", vec![TyParam::t(Nat)]);
match self.resolve_trait(t) { match self.resolve_trait(t) {
Ok(Nat) => Ok(()), Ok(Nat) => Ok(()),
Ok(other) => { Ok(other) => {
@ -46,7 +46,7 @@ impl Context {
pub fn test_resolve_trait_inner1(&self) -> Result<(), ()> { pub fn test_resolve_trait_inner1(&self) -> Result<(), ()> {
let name = Str::ever("Add"); let name = Str::ever("Add");
let params = vec![TyParam::t(Nat)]; let params = vec![TyParam::t(Nat)];
let maybe_trait = poly_trait(name.clone(), params); let maybe_trait = poly(name.clone(), params);
let mut min = Type::Obj; let mut min = Type::Obj;
for pair in self.rec_get_trait_impls(&name) { for pair in self.rec_get_trait_impls(&name) {
if self.rec_supertype_of(&pair.sup_trait, &maybe_trait) { if self.rec_supertype_of(&pair.sup_trait, &maybe_trait) {
@ -62,7 +62,7 @@ impl Context {
pub fn test_instantiation_and_generalization(&self) -> Result<(), ()> { pub fn test_instantiation_and_generalization(&self) -> Result<(), ()> {
let t = mono_q("T"); let t = mono_q("T");
let eq = poly_trait("Eq", vec![TyParam::t(t.clone())]); let eq = poly("Eq", vec![TyParam::t(t.clone())]);
let bound = TyBound::subtype_of(t.clone(), eq.clone()); let bound = TyBound::subtype_of(t.clone(), eq.clone());
let bounds = set! {bound}; let bounds = set! {bound};
let unbound_t = func1(t.clone(), t.clone()); let unbound_t = func1(t.clone(), t.clone());

View file

@ -12,7 +12,7 @@ use erg_type::constructors::*;
use erg_type::free::{Constraint, Cyclicity, FreeKind, HasLevel}; use erg_type::free::{Constraint, Cyclicity, FreeKind, HasLevel};
use erg_type::typaram::TyParam; use erg_type::typaram::TyParam;
use erg_type::value::ValueObj; use erg_type::value::ValueObj;
use erg_type::{HasType, Predicate, SubrKind, TyBound, Type}; use erg_type::{HasType, Predicate, TyBound, Type};
use crate::context::{Context, Variance}; use crate::context::{Context, Variance};
use crate::error::{TyCheckError, TyCheckResult}; use crate::error::{TyCheckError, TyCheckResult};
@ -118,22 +118,6 @@ impl Context {
_ => assume_unreachable!(), _ => assume_unreachable!(),
}, },
Subr(mut subr) => { Subr(mut subr) => {
let kind = match subr.kind {
SubrKind::FuncMethod(self_t) => {
let t = self.generalize_t_inner(*self_t, bounds, lazy_inits);
SubrKind::fn_met(t)
}
SubrKind::ProcMethod { before, after } => {
let before = self.generalize_t_inner(*before, bounds, lazy_inits);
if let Some(after) = after {
let after = self.generalize_t_inner(*after, bounds, lazy_inits);
SubrKind::pr_met(before, Some(after))
} else {
SubrKind::pr_met(before, None)
}
}
other => other,
};
subr.non_default_params.iter_mut().for_each(|nd_param| { subr.non_default_params.iter_mut().for_each(|nd_param| {
*nd_param.typ_mut() = *nd_param.typ_mut() =
self.generalize_t_inner(mem::take(nd_param.typ_mut()), bounds, lazy_inits); self.generalize_t_inner(mem::take(nd_param.typ_mut()), bounds, lazy_inits);
@ -148,7 +132,7 @@ impl Context {
}); });
let return_t = self.generalize_t_inner(*subr.return_t, bounds, lazy_inits); let return_t = self.generalize_t_inner(*subr.return_t, bounds, lazy_inits);
subr_t( subr_t(
kind, subr.kind,
subr.non_default_params, subr.non_default_params,
subr.var_params.map(|x| *x), subr.var_params.map(|x| *x),
subr.default_params, subr.default_params,
@ -157,20 +141,20 @@ impl Context {
} }
Callable { .. } => todo!(), Callable { .. } => todo!(),
Ref(t) => ref_(self.generalize_t_inner(*t, bounds, lazy_inits)), Ref(t) => ref_(self.generalize_t_inner(*t, bounds, lazy_inits)),
RefMut(t) => ref_mut(self.generalize_t_inner(*t, bounds, lazy_inits)), RefMut { before, after } => {
PolyClass { name, mut params } => { let after = if let Some(after) = after {
let params = params Some(self.generalize_t_inner(*after, bounds, lazy_inits))
.iter_mut() } else {
.map(|p| self.generalize_tp(mem::take(p), bounds, lazy_inits)) None
.collect::<Vec<_>>(); };
poly_class(name, params) ref_mut(self.generalize_t_inner(*before, bounds, lazy_inits), after)
} }
PolyTrait { name, mut params } => { Poly { name, mut params } => {
let params = params let params = params
.iter_mut() .iter_mut()
.map(|p| self.generalize_tp(mem::take(p), bounds, lazy_inits)) .map(|p| self.generalize_tp(mem::take(p), bounds, lazy_inits))
.collect::<Vec<_>>(); .collect::<Vec<_>>();
poly_trait(name, params) poly(name, params)
} }
// REVIEW: その他何でもそのまま通していいのか? // REVIEW: その他何でもそのまま通していいのか?
other => other, other => other,
@ -246,13 +230,13 @@ impl Context {
if cyclic.is_cyclic() { if cyclic.is_cyclic() {
return Err(TyCheckError::dummy_infer_error(fn_name!(), line!())); return Err(TyCheckError::dummy_infer_error(fn_name!(), line!()));
} }
Ok(Constraint::sandwiched( Ok(Constraint::new_sandwiched(
self.deref_tyvar(sub)?, self.deref_tyvar(sub)?,
self.deref_tyvar(sup)?, self.deref_tyvar(sup)?,
cyclic, cyclic,
)) ))
} }
Constraint::TypeOf(t) => Ok(Constraint::type_of(self.deref_tyvar(t)?)), Constraint::TypeOf(t) => Ok(Constraint::new_type_of(self.deref_tyvar(t)?)),
_ => unreachable!(), _ => unreachable!(),
} }
} }
@ -269,7 +253,7 @@ impl Context {
// ?T(:> Never, <: Nat)[n] => Nat // ?T(:> Never, <: Nat)[n] => Nat
Type::FreeVar(fv) if fv.constraint_is_sandwiched() => { Type::FreeVar(fv) if fv.constraint_is_sandwiched() => {
let constraint = fv.crack_constraint(); let constraint = fv.crack_constraint();
let (sub_t, super_t) = constraint.get_sub_sup_type().unwrap(); let (sub_t, super_t) = constraint.get_sub_sup().unwrap();
if self.rec_same_type_of(sub_t, super_t) { if self.rec_same_type_of(sub_t, super_t) {
self.unify(sub_t, super_t, None, None)?; self.unify(sub_t, super_t, None, None)?;
let t = if sub_t == &Never { let t = if sub_t == &Never {
@ -280,7 +264,7 @@ impl Context {
drop(constraint); drop(constraint);
fv.link(&t); fv.link(&t);
self.deref_tyvar(Type::FreeVar(fv)) self.deref_tyvar(Type::FreeVar(fv))
} else if self.level == 0 || self.level <= fv.level().unwrap() { } else if self.level <= fv.level().unwrap() {
let new_t = if sub_t == &Never { let new_t = if sub_t == &Never {
super_t.clone() super_t.clone()
} else { } else {
@ -313,32 +297,14 @@ impl Context {
let t = fv.unwrap_linked(); let t = fv.unwrap_linked();
self.deref_tyvar(t) self.deref_tyvar(t)
} }
Type::PolyClass { name, mut params } => { Type::Poly { name, mut params } => {
for param in params.iter_mut() { for param in params.iter_mut() {
*param = self.deref_tp(mem::take(param))?; *param = self.deref_tp(mem::take(param))?;
} }
Ok(Type::PolyClass { name, params }) let t = Type::Poly { name, params };
}
Type::PolyTrait { name, mut params } => {
for param in params.iter_mut() {
*param = self.deref_tp(mem::take(param))?;
}
let t = Type::PolyTrait { name, params };
self.resolve_trait(t) self.resolve_trait(t)
} }
Type::Subr(mut subr) => { Type::Subr(mut subr) => {
match &mut subr.kind {
SubrKind::FuncMethod(t) => {
*t = Box::new(self.deref_tyvar(mem::take(t))?);
}
SubrKind::ProcMethod { before, after } => {
*before = Box::new(self.deref_tyvar(mem::take(before))?);
if let Some(after) = after {
*after = Box::new(self.deref_tyvar(mem::take(after))?);
}
}
_ => {}
}
for param in subr.non_default_params.iter_mut() { for param in subr.non_default_params.iter_mut() {
*param.typ_mut() = self.deref_tyvar(mem::take(param.typ_mut()))?; *param.typ_mut() = self.deref_tyvar(mem::take(param.typ_mut()))?;
} }
@ -355,9 +321,14 @@ impl Context {
let t = self.deref_tyvar(*t)?; let t = self.deref_tyvar(*t)?;
Ok(ref_(t)) Ok(ref_(t))
} }
Type::RefMut(t) => { Type::RefMut { before, after } => {
let t = self.deref_tyvar(*t)?; let before = self.deref_tyvar(*before)?;
Ok(ref_mut(t)) let after = if let Some(after) = after {
Some(self.deref_tyvar(*after)?)
} else {
None
};
Ok(ref_mut(before, after))
} }
Type::Callable { .. } => todo!(), Type::Callable { .. } => todo!(),
Type::Record(mut rec) => { Type::Record(mut rec) => {
@ -400,7 +371,7 @@ impl Context {
self.deref_expr_t(&mut subscr.obj)?; self.deref_expr_t(&mut subscr.obj)?;
self.deref_expr_t(&mut subscr.index)?; self.deref_expr_t(&mut subscr.index)?;
} }
hir::Accessor::Local(_) | hir::Accessor::Public(_) => {} hir::Accessor::Ident(_) => {}
} }
Ok(()) Ok(())
} }
@ -490,6 +461,29 @@ impl Context {
} }
Ok(()) Ok(())
} }
hir::Expr::ClassDef(type_def) => {
for def in type_def.public_methods.iter_mut() {
match &mut def.sig {
hir::Signature::Var(var) => {
var.t = self.deref_tyvar(mem::take(&mut var.t))?;
}
hir::Signature::Subr(subr) => {
subr.t = self.deref_tyvar(mem::take(&mut subr.t))?;
}
}
for chunk in def.body.block.iter_mut() {
self.deref_expr_t(chunk)?;
}
}
Ok(())
}
hir::Expr::AttrDef(attr_def) => {
// REVIEW: attr_def.attr is not dereferenced
for chunk in attr_def.block.iter_mut() {
self.deref_expr_t(chunk)?;
}
Ok(())
}
} }
} }
@ -523,7 +517,7 @@ impl Context {
(TyParam::FreeVar(fv), tp) | (tp, TyParam::FreeVar(fv)) => { (TyParam::FreeVar(fv), tp) | (tp, TyParam::FreeVar(fv)) => {
match &*fv.borrow() { match &*fv.borrow() {
FreeKind::Linked(l) | FreeKind::UndoableLinked { t: l, .. } => { FreeKind::Linked(l) | FreeKind::UndoableLinked { t: l, .. } => {
return self.unify_tp(l, tp, lhs_variance, allow_divergence) return self.unify_tp(l, tp, lhs_variance, allow_divergence);
} }
FreeKind::Unbound { .. } | FreeKind::NamedUnbound { .. } => {} FreeKind::Unbound { .. } | FreeKind::NamedUnbound { .. } => {}
} // &fv is dropped } // &fv is dropped
@ -534,11 +528,11 @@ impl Context {
.get_type() .get_type()
.unwrap() .unwrap()
.clone(); // fvを参照しないよいにcloneする(あとでborrow_mutするため) .clone(); // fvを参照しないよいにcloneする(あとでborrow_mutするため)
let tp_t = self.eval.get_tp_t(tp, self)?; let tp_t = self.get_tp_t(tp)?;
if self.rec_supertype_of(&fv_t, &tp_t) { if self.rec_supertype_of(&fv_t, &tp_t) {
// 外部未連携型変数の場合、linkしないで制約を弱めるだけにする(see compiler/inference.md) // 外部未連携型変数の場合、linkしないで制約を弱めるだけにする(see compiler/inference.md)
if fv.level() < Some(self.level) { if fv.level() < Some(self.level) {
let new_constraint = Constraint::subtype_of(tp_t, Cyclicity::Not); let new_constraint = Constraint::new_subtype_of(tp_t, Cyclicity::Not);
if self.is_sub_constraint_of( if self.is_sub_constraint_of(
fv.borrow().constraint().unwrap(), fv.borrow().constraint().unwrap(),
&new_constraint, &new_constraint,
@ -553,7 +547,7 @@ impl Context {
} else if allow_divergence } else if allow_divergence
&& (self.eq_tp(tp, &TyParam::value(Inf)) && (self.eq_tp(tp, &TyParam::value(Inf))
|| self.eq_tp(tp, &TyParam::value(NegInf))) || self.eq_tp(tp, &TyParam::value(NegInf)))
&& self.rec_subtype_of(&fv_t, &trait_("Num")) && self.rec_subtype_of(&fv_t, &mono("Num"))
{ {
fv.link(tp); fv.link(tp);
Ok(()) Ok(())
@ -730,7 +724,7 @@ impl Context {
(Type::FreeVar(fv), t) | (t, Type::FreeVar(fv)) => { (Type::FreeVar(fv), t) | (t, Type::FreeVar(fv)) => {
match &mut *fv.borrow_mut() { match &mut *fv.borrow_mut() {
FreeKind::Linked(l) | FreeKind::UndoableLinked { t: l, .. } => { FreeKind::Linked(l) | FreeKind::UndoableLinked { t: l, .. } => {
return self.unify(l, t, lhs_loc, rhs_loc) return self.unify(l, t, lhs_loc, rhs_loc);
} }
FreeKind::Unbound { FreeKind::Unbound {
lev, constraint, .. lev, constraint, ..
@ -740,7 +734,7 @@ impl Context {
} => { } => {
t.update_level(*lev); t.update_level(*lev);
// TODO: constraint.type_of() // TODO: constraint.type_of()
if let Some(sup) = constraint.get_super_type_mut() { if let Some(sup) = constraint.get_super_mut() {
// 下のような場合は制約を弱化する // 下のような場合は制約を弱化する
// unify(?T(<: Nat), Int): (?T(<: Int)) // unify(?T(<: Nat), Int): (?T(<: Int))
if self.rec_subtype_of(sup, t) { if self.rec_subtype_of(sup, t) {
@ -751,7 +745,7 @@ impl Context {
} }
} }
} // &fv is dropped } // &fv is dropped
let new_constraint = Constraint::subtype_of(t.clone(), fv.cyclicity()); let new_constraint = Constraint::new_subtype_of(t.clone(), fv.cyclicity());
// 外部未連携型変数の場合、linkしないで制約を弱めるだけにする(see compiler/inference.md) // 外部未連携型変数の場合、linkしないで制約を弱めるだけにする(see compiler/inference.md)
// fv == ?T(: Type)の場合は?T(<: U)にする // fv == ?T(: Type)の場合は?T(<: U)にする
if fv.level() < Some(self.level) { if fv.level() < Some(self.level) {
@ -794,10 +788,7 @@ impl Context {
let lhs_t = self.into_refinement(l.clone()); let lhs_t = self.into_refinement(l.clone());
self.unify(&Type::Refinement(lhs_t), rhs_t, lhs_loc, rhs_loc) self.unify(&Type::Refinement(lhs_t), rhs_t, lhs_loc, rhs_loc)
} }
(Type::Subr(ls), Type::Subr(rs)) if ls.kind.same_kind_as(&rs.kind) => { (Type::Subr(ls), Type::Subr(rs)) if ls.kind == rs.kind => {
if let (Some(l), Some(r)) = (ls.kind.self_t(), rs.kind.self_t()) {
self.unify(l, r, lhs_loc, rhs_loc)?;
}
for (l, r) in ls for (l, r) in ls
.non_default_params .non_default_params
.iter() .iter()
@ -821,18 +812,38 @@ impl Context {
} }
self.unify(&ls.return_t, &rs.return_t, lhs_loc, rhs_loc) self.unify(&ls.return_t, &rs.return_t, lhs_loc, rhs_loc)
} }
(Type::Ref(l), Type::Ref(r)) | (Type::RefMut(l), Type::RefMut(r)) => { (Type::Ref(l), Type::Ref(r)) => self.unify(l, r, lhs_loc, rhs_loc),
self.unify(l, r, lhs_loc, rhs_loc) (
Type::RefMut {
before: lbefore,
after: lafter,
},
Type::RefMut {
before: rbefore,
after: rafter,
},
) => {
self.unify(lbefore, rbefore, lhs_loc, rhs_loc)?;
match (lafter, rafter) {
(Some(lafter), Some(rafter)) => {
self.unify(lafter, rafter, lhs_loc, rhs_loc)?;
}
(None, None) => {}
_ => todo!(),
}
Ok(())
} }
(Type::Ref(l), r) => self.unify(l, r, lhs_loc, rhs_loc),
// REVIEW: // REVIEW:
(Type::Ref(l), r) | (Type::RefMut(l), r) => self.unify(l, r, lhs_loc, rhs_loc), (Type::RefMut { before, .. }, r) => self.unify(before, r, lhs_loc, rhs_loc),
(l, Type::Ref(r)) | (l, Type::RefMut(r)) => self.unify(l, r, lhs_loc, rhs_loc), (l, Type::Ref(r)) => self.unify(l, r, lhs_loc, rhs_loc),
(l, Type::RefMut { before, .. }) => self.unify(l, before, lhs_loc, rhs_loc),
( (
Type::PolyClass { Type::Poly {
name: ln, name: ln,
params: lps, params: lps,
}, },
Type::PolyClass { Type::Poly {
name: rn, name: rn,
params: rps, params: rps,
}, },
@ -852,32 +863,7 @@ impl Context {
} }
Ok(()) Ok(())
} }
( (Type::Poly { name: _, params: _ }, _r) => {
Type::PolyTrait {
name: ln,
params: lps,
},
Type::PolyTrait {
name: rn,
params: rps,
},
) => {
if ln != rn {
return Err(TyCheckError::unification_error(
line!() as usize,
lhs_t,
rhs_t,
lhs_loc,
rhs_loc,
self.caused_by(),
));
}
for (l, r) in lps.iter().zip(rps.iter()) {
self.unify_tp(l, r, None, false)?;
}
Ok(())
}
(Type::PolyClass { name: _, params: _ }, _r) => {
todo!() todo!()
} }
(l, r) => Err(TyCheckError::unification_error( (l, r) => Err(TyCheckError::unification_error(
@ -908,50 +894,44 @@ impl Context {
(l, Type::FreeVar(fv)) if fv.is_linked() => { (l, Type::FreeVar(fv)) if fv.is_linked() => {
self.reunify(l, &fv.crack(), bef_loc, aft_loc) self.reunify(l, &fv.crack(), bef_loc, aft_loc)
} }
(Type::Ref(l), Type::Ref(r)) | (Type::RefMut(l), Type::RefMut(r)) => { (Type::Ref(l), Type::Ref(r)) => self.reunify(l, r, bef_loc, aft_loc),
self.reunify(l, r, bef_loc, aft_loc)
}
// REVIEW:
(Type::Ref(l), r) | (Type::RefMut(l), r) => self.reunify(l, r, bef_loc, aft_loc),
(l, Type::Ref(r)) | (l, Type::RefMut(r)) => self.reunify(l, r, bef_loc, aft_loc),
( (
Type::PolyClass { Type::RefMut {
name: ln, before: lbefore,
params: lps, after: lafter,
}, },
Type::PolyClass { Type::RefMut {
name: rn, before: rbefore,
params: rps, after: rafter,
}, },
) => { ) => {
if ln != rn { self.reunify(lbefore, rbefore, bef_loc, aft_loc)?;
let before_t = poly_class(ln.clone(), lps.clone()); match (lafter, rafter) {
return Err(TyCheckError::re_unification_error( (Some(lafter), Some(rafter)) => {
line!() as usize, self.reunify(lafter, rafter, bef_loc, aft_loc)?;
&before_t, }
after_t, (None, None) => {}
bef_loc, _ => todo!(),
aft_loc,
self.caused_by(),
));
}
for (l, r) in lps.iter().zip(rps.iter()) {
self.reunify_tp(l, r)?;
} }
Ok(()) Ok(())
} }
(Type::Ref(l), r) => self.reunify(l, r, bef_loc, aft_loc),
// REVIEW:
(Type::RefMut { before, .. }, r) => self.reunify(before, r, bef_loc, aft_loc),
(l, Type::Ref(r)) => self.reunify(l, r, bef_loc, aft_loc),
(l, Type::RefMut { before, .. }) => self.reunify(l, before, bef_loc, aft_loc),
( (
Type::PolyTrait { Type::Poly {
name: ln, name: ln,
params: lps, params: lps,
}, },
Type::PolyTrait { Type::Poly {
name: rn, name: rn,
params: rps, params: rps,
}, },
) => { ) => {
if ln != rn { if ln != rn {
let before_t = poly_trait(ln.clone(), lps.clone()); let before_t = poly(ln.clone(), lps.clone());
return Err(TyCheckError::re_unification_error( return Err(TyCheckError::re_unification_error(
line!() as usize, line!() as usize,
&before_t, &before_t,
@ -987,7 +967,7 @@ impl Context {
/// sub_unify({I: Int | I == 0}, ?T(<: Ord)): (/* OK */) /// sub_unify({I: Int | I == 0}, ?T(<: Ord)): (/* OK */)
/// sub_unify(Int, ?T(:> Nat)): (?T :> Int) /// sub_unify(Int, ?T(:> Nat)): (?T :> Int)
/// sub_unify(Nat, ?T(:> Int)): (/* OK */) /// sub_unify(Nat, ?T(:> Int)): (/* OK */)
/// sub_unify(Nat, Add(?R, ?O)): (?R => Nat, ?O => Nat) /// sub_unify(Nat, Add(?R)): (?R => Nat, Nat.AddO => Nat)
/// sub_unify([?T; 0], Mutate): (/* OK */) /// sub_unify([?T; 0], Mutate): (/* OK */)
/// ``` /// ```
pub(crate) fn sub_unify( pub(crate) fn sub_unify(
@ -1029,20 +1009,29 @@ impl Context {
// lfvのsupは縮小可能(minを取る)、rfvのsubは拡大可能(unionを取る) // lfvのsupは縮小可能(minを取る)、rfvのsubは拡大可能(unionを取る)
// sub_unify(?T[0](:> Never, <: Int), ?U[1](:> Never, <: Nat)): (/* ?U[1] --> ?T[0](:> Never, <: Nat)) // sub_unify(?T[0](:> Never, <: Int), ?U[1](:> Never, <: Nat)): (/* ?U[1] --> ?T[0](:> Never, <: Nat))
// sub_unify(?T[1](:> Never, <: Nat), ?U[0](:> Never, <: Int)): (/* ?T[1] --> ?U[0](:> Never, <: Nat)) // sub_unify(?T[1](:> Never, <: Nat), ?U[0](:> Never, <: Int)): (/* ?T[1] --> ?U[0](:> Never, <: Nat))
// sub_unify(?T[0](:> Never, <: Str), ?U[1](:> Never, <: Int)): (/* Error */) // sub_unify(?T[0](:> Never, <: Str), ?U[1](:> Never, <: Int)): (?T[0](:> Never, <: Str and Int) --> Error!)
// sub_unify(?T[0](:> Int, <: Add()), ?U[1](:> Never, <: Mul())): (?T[0](:> Int, <: Add() and Mul()))
// sub_unify(?T[0](:> Str, <: Obj), ?U[1](:> Int, <: Obj)): (/* ?U[1] --> ?T[0](:> Str or Int) */) // sub_unify(?T[0](:> Str, <: Obj), ?U[1](:> Int, <: Obj)): (/* ?U[1] --> ?T[0](:> Str or Int) */)
(Type::FreeVar(lfv), Type::FreeVar(rfv)) (Type::FreeVar(lfv), Type::FreeVar(rfv))
if lfv.constraint_is_sandwiched() && rfv.constraint_is_sandwiched() => if lfv.constraint_is_sandwiched() && rfv.constraint_is_sandwiched() =>
{ {
let (lsub, lsup) = lfv.crack_bound_types().unwrap(); let (lsub, lsup) = lfv.get_bound_types().unwrap();
let l_cyc = lfv.cyclicity(); let l_cyc = lfv.cyclicity();
let (rsub, rsup) = rfv.crack_bound_types().unwrap(); let (rsub, rsup) = rfv.get_bound_types().unwrap();
let r_cyc = rfv.cyclicity(); let r_cyc = rfv.cyclicity();
let cyclicity = l_cyc.combine(r_cyc); let cyclicity = l_cyc.combine(r_cyc);
let new_constraint = if let Some(min) = self.min(&lsup, &rsup) { let intersec = self.rec_intersection(&lsup, &rsup);
Constraint::sandwiched(self.rec_union(&lsub, &rsub), min.clone(), cyclicity) let new_constraint = if intersec != Type::Never {
Constraint::new_sandwiched(self.rec_union(&lsub, &rsub), intersec, cyclicity)
} else { } else {
todo!() return Err(TyCheckError::subtyping_error(
line!() as usize,
maybe_sub,
maybe_sup,
sub_loc,
sup_loc,
self.caused_by(),
));
}; };
if lfv.level().unwrap() <= rfv.level().unwrap() { if lfv.level().unwrap() <= rfv.level().unwrap() {
lfv.update_constraint(new_constraint); lfv.update_constraint(new_constraint);
@ -1067,7 +1056,7 @@ impl Context {
// sub = max(l, sub) if max exists // sub = max(l, sub) if max exists
// * sub_unify(Nat, ?T(:> Int, <: _)): (/* OK */) // * sub_unify(Nat, ?T(:> Int, <: _)): (/* OK */)
// * sub_unify(Int, ?T(:> Nat, <: Obj)): (?T(:> Int, <: Obj)) // * sub_unify(Int, ?T(:> Nat, <: Obj)): (?T(:> Int, <: Obj))
// * sub_unify(Nat, ?T(:> Never, <: Add(?R, ?O))): (?T(:> Nat, <: Add(?R, ?O)) // * sub_unify(Nat, ?T(:> Never, <: Add(?R))): (?T(:> Nat, <: Add(?R))
// sub = union(l, sub) if max does not exist // sub = union(l, sub) if max does not exist
// * sub_unify(Str, ?T(:> Int, <: Obj)): (?T(:> Str or Int, <: Obj)) // * sub_unify(Str, ?T(:> Int, <: Obj)): (?T(:> Str or Int, <: Obj))
// * sub_unify({0}, ?T(:> {1}, <: Nat)): (?T(:> {0, 1}, <: Nat)) // * sub_unify({0}, ?T(:> {1}, <: Nat)): (?T(:> {0, 1}, <: Nat))
@ -1089,16 +1078,16 @@ impl Context {
} }
if let Some(new_sub) = self.rec_max(maybe_sub, sub) { if let Some(new_sub) = self.rec_max(maybe_sub, sub) {
*constraint = *constraint =
Constraint::sandwiched(new_sub.clone(), mem::take(sup), *cyclicity); Constraint::new_sandwiched(new_sub.clone(), mem::take(sup), *cyclicity);
} else { } else {
let new_sub = self.rec_union(maybe_sub, sub); let new_sub = self.rec_union(maybe_sub, sub);
*constraint = Constraint::sandwiched(new_sub, mem::take(sup), *cyclicity); *constraint = Constraint::new_sandwiched(new_sub, mem::take(sup), *cyclicity);
} }
} }
// sub_unify(Nat, ?T(: Type)): (/* ?T(:> Nat) */) // sub_unify(Nat, ?T(: Type)): (/* ?T(:> Nat) */)
Constraint::TypeOf(ty) => { Constraint::TypeOf(ty) => {
if self.rec_supertype_of(&Type, ty) { if self.rec_supertype_of(&Type, ty) {
*constraint = Constraint::supertype_of(maybe_sub.clone(), Cyclicity::Not); *constraint = Constraint::new_supertype_of(maybe_sub.clone(), Cyclicity::Not);
} else { } else {
todo!() todo!()
} }
@ -1138,16 +1127,16 @@ impl Context {
} }
if let Some(new_sup) = self.rec_min(sup, maybe_sup) { if let Some(new_sup) = self.rec_min(sup, maybe_sup) {
*constraint = *constraint =
Constraint::sandwiched(mem::take(sub), new_sup.clone(), *cyclicity); Constraint::new_sandwiched(mem::take(sub), new_sup.clone(), *cyclicity);
} else { } else {
let new_sup = self.rec_union(sup, maybe_sup); let new_sup = self.rec_union(sup, maybe_sup);
*constraint = Constraint::sandwiched(mem::take(sub), new_sup, *cyclicity); *constraint = Constraint::new_sandwiched(mem::take(sub), new_sup, *cyclicity);
} }
} }
// sub_unify(?T(: Type), Int): (?T(<: Int)) // sub_unify(?T(: Type), Int): (?T(<: Int))
Constraint::TypeOf(ty) => { Constraint::TypeOf(ty) => {
if self.rec_supertype_of(&Type, ty) { if self.rec_supertype_of(&Type, ty) {
*constraint = Constraint::subtype_of(maybe_sup.clone(), Cyclicity::Not); *constraint = Constraint::new_subtype_of(maybe_sup.clone(), Cyclicity::Not);
} else { } else {
todo!() todo!()
} }
@ -1159,6 +1148,23 @@ impl Context {
return Ok(()); return Ok(());
} }
(Type::FreeVar(_fv), _r) => todo!(), (Type::FreeVar(_fv), _r) => todo!(),
(Type::Record(lrec), Type::Record(rrec)) => {
for (k, l) in lrec.iter() {
if let Some(r) = rrec.get(k) {
self.sub_unify(l, r, sub_loc, sup_loc, param_name)?;
} else {
return Err(TyCheckError::subtyping_error(
line!() as usize,
maybe_sub,
maybe_sup,
sub_loc,
sup_loc,
self.caused_by(),
));
}
}
return Ok(());
}
(Type::Subr(lsub), Type::Subr(rsub)) => { (Type::Subr(lsub), Type::Subr(rsub)) => {
for lpt in lsub.default_params.iter() { for lpt in lsub.default_params.iter() {
if let Some(rpt) = rsub.default_params.iter().find(|rpt| rpt.name() == lpt.name()) { if let Some(rpt) = rsub.default_params.iter().find(|rpt| rpt.name() == lpt.name()) {
@ -1171,6 +1177,14 @@ impl Context {
self.unify(&lsub.return_t, &rsub.return_t, sub_loc, sup_loc)?; self.unify(&lsub.return_t, &rsub.return_t, sub_loc, sup_loc)?;
return Ok(()); return Ok(());
} }
(_, Type::Ref(t)) => {
self.unify(maybe_sub, t, sub_loc, sup_loc)?;
return Ok(());
}
(_, Type::RefMut{ before, .. }) => {
self.unify(maybe_sub, before, sub_loc, sup_loc)?;
return Ok(());
}
(Type::MonoProj { .. }, _) => todo!(), (Type::MonoProj { .. }, _) => todo!(),
(_, Type::MonoProj { .. }) => todo!(), (_, Type::MonoProj { .. }) => todo!(),
(Refinement(_), Refinement(_)) => todo!(), (Refinement(_), Refinement(_)) => todo!(),

View file

@ -9,7 +9,7 @@ use erg_common::Str;
use Visibility::*; use Visibility::*;
use crate::error::{EffectError, EffectErrors, EffectResult}; use crate::error::{EffectError, EffectErrors, EffectResult};
use crate::hir::{Accessor, Def, Expr, Signature, HIR}; use crate::hir::{Accessor, Array, Def, Expr, Signature, Tuple, HIR};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
enum BlockKind { enum BlockKind {
@ -84,6 +84,12 @@ impl SideEffectChecker {
Expr::Def(def) => { Expr::Def(def) => {
self.check_def(def); self.check_def(def);
} }
Expr::ClassDef(type_def) => {
// TODO: grow
for def in type_def.public_methods.iter() {
self.check_def(def);
}
}
Expr::Call(call) => { Expr::Call(call) => {
for parg in call.args.pos_args.iter() { for parg in call.args.pos_args.iter() {
self.check_expr(&parg.expr); self.check_expr(&parg.expr);
@ -174,6 +180,31 @@ impl SideEffectChecker {
Expr::Def(def) => { Expr::Def(def) => {
self.check_def(def); self.check_def(def);
} }
Expr::ClassDef(type_def) => {
for def in type_def.public_methods.iter() {
self.check_def(def);
}
}
Expr::Array(array) => match array {
Array::Normal(arr) => {
for arg in arr.elems.pos_args.iter() {
self.check_expr(&arg.expr);
}
}
other => todo!("{other}"),
},
Expr::Tuple(tuple) => match tuple {
Tuple::Normal(tup) => {
for arg in tup.elems.pos_args.iter() {
self.check_expr(&arg.expr);
}
}
},
Expr::Record(record) => {
for attr in record.attrs.iter() {
self.check_def(attr);
}
}
// 引数がproceduralでも関数呼び出しなら副作用なし // 引数がproceduralでも関数呼び出しなら副作用なし
Expr::Call(call) => { Expr::Call(call) => {
if (self.is_procedural(&call.obj) if (self.is_procedural(&call.obj)
@ -228,10 +259,10 @@ impl SideEffectChecker {
Expr::Lambda(lambda) => lambda.is_procedural(), Expr::Lambda(lambda) => lambda.is_procedural(),
// 引数がproceduralでも関数呼び出しなら副作用なし // 引数がproceduralでも関数呼び出しなら副作用なし
Expr::Call(call) => self.is_procedural(&call.obj), Expr::Call(call) => self.is_procedural(&call.obj),
Expr::Accessor(Accessor::Local(local)) => local.name.is_procedural(), Expr::Accessor(Accessor::Ident(ident)) => ident.name.is_procedural(),
// procedural: x.y! (e.g. Array.sample!) // procedural: x.y! (e.g. Array.sample!)
// !procedural: !x.y // !procedural: !x.y
Expr::Accessor(Accessor::Attr(attr)) => attr.name.is_procedural(), Expr::Accessor(Accessor::Attr(attr)) => attr.ident.is_procedural(),
Expr::Accessor(_) => todo!(), Expr::Accessor(_) => todo!(),
_ => false, _ => false,
} }

View file

@ -255,6 +255,10 @@ impl TyCheckError {
Self { core, caused_by } Self { core, caused_by }
} }
pub fn dummy(errno: usize) -> Self {
Self::new(ErrorCore::dummy(errno), "".into())
}
pub fn unreachable(fn_name: &str, line: u32) -> Self { pub fn unreachable(fn_name: &str, line: u32) -> Self {
Self::new(ErrorCore::unreachable(fn_name, line), "".into()) Self::new(ErrorCore::unreachable(fn_name, line), "".into())
} }
@ -327,6 +331,30 @@ impl TyCheckError {
) )
} }
pub fn duplicate_definition_error(
errno: usize,
loc: Location,
caused_by: Str,
name: &str,
) -> Self {
let name = readable_name(name);
Self::new(
ErrorCore::new(
errno,
NameError,
loc,
switch_lang!(
"japanese" => format!("{name}は既に定義されています"),
"simplified_chinese" => format!("{name}已定义"),
"traditional_chinese" => format!("{name}已定義"),
"english" => format!("{name} is already defined"),
),
Option::<Str>::None,
),
caused_by,
)
}
pub fn violate_decl_error( pub fn violate_decl_error(
errno: usize, errno: usize,
loc: Location, loc: Location,
@ -521,10 +549,10 @@ impl TyCheckError {
TypeError, TypeError,
loc, loc,
switch_lang!( switch_lang!(
"japanese" => format!("{name}の型が違います。\n予期した型: {GREEN}{expect}{RESET}\n与えられた型: {RED}{found}{RESET}"), "japanese" => format!("{YELLOW}{name}{RESET}の型が違います。\n予期した型: {GREEN}{expect}{RESET}\n与えられた型: {RED}{found}{RESET}"),
"simplified_chinese" => format!("{name}的类型不匹配:\n预期:{GREEN}{expect}{RESET}\n但找到:{RED}{found}{RESET}"), "simplified_chinese" => format!("{YELLOW}{name}{RESET}的类型不匹配:\n预期:{GREEN}{expect}{RESET}\n但找到:{RED}{found}{RESET}"),
"traditional_chinese" => format!("{name}的類型不匹配:\n預期:{GREEN}{expect}{RESET}\n但找到:{RED}{found}{RESET}"), "traditional_chinese" => format!("{YELLOW}{name}{RESET}的類型不匹配:\n預期:{GREEN}{expect}{RESET}\n但找到:{RED}{found}{RESET}"),
"english" => format!("the type of {name} is mismatched:\nexpected: {GREEN}{expect}{RESET}\nbut found: {RED}{found}{RESET}"), "english" => format!("the type of {YELLOW}{name}{RESET} is mismatched:\nexpected: {GREEN}{expect}{RESET}\nbut found: {RED}{found}{RESET}"),
), ),
hint, hint,
), ),
@ -657,10 +685,10 @@ impl TyCheckError {
AssignError, AssignError,
loc, loc,
switch_lang!( switch_lang!(
"japanese" => format!("定数{name}には再代入できません"), "japanese" => format!("変数{name}に再代入されています"),
"simplified_chinese" => format!("不能为不可变变量{name}分配两次"), "simplified_chinese" => format!("不能为变量{name}分配两次"),
"traditional_chinese" => format!("不能為不可變變量{name}分配兩次"), "traditional_chinese" => format!("不能為變量{name}分配兩次"),
"english" => format!("cannot assign twice to the immutable variable {name}"), "english" => format!("cannot assign twice to the variable {name}"),
), ),
None, None,
), ),
@ -1006,7 +1034,7 @@ passed keyword args: {RED}{kw_args_len}{RESET}"
Self::new( Self::new(
ErrorCore::new( ErrorCore::new(
errno, errno,
NameError, VisibilityError,
loc, loc,
switch_lang!( switch_lang!(
"japanese" => format!("{RED}{name}{RESET}{visibility}変数です"), "japanese" => format!("{RED}{name}{RESET}{visibility}変数です"),
@ -1019,6 +1047,79 @@ passed keyword args: {RED}{kw_args_len}{RESET}"
caused_by, caused_by,
) )
} }
pub fn not_const_expr(errno: usize, loc: Location, caused_by: Str) -> Self {
Self::new(
ErrorCore::new(
errno,
NotConstExpr,
loc,
switch_lang!(
"japanese" => "定数式ではありません",
"simplified_chinese" => "不是常量表达式",
"traditional_chinese" => "不是常量表達式",
"english" => "not a constant expression",
),
None,
),
caused_by,
)
}
pub fn override_error<S: Into<Str>>(
errno: usize,
name: &str,
name_loc: Location,
superclass: &Type,
caused_by: S,
) -> Self {
Self::new(
ErrorCore::new(
errno,
NameError,
name_loc,
switch_lang!(
"japanese" => format!(
"{RED}{name}{RESET}は{YELLOW}{superclass}{RESET}で既に定義されています",
),
"simplified_chinese" => format!(
"{RED}{name}{RESET}已在{YELLOW}{superclass}{RESET}中定义",
),
"traditional_chinese" => format!(
"{RED}{name}{RESET}已在{YELLOW}{superclass}{RESET}中定義",
),
"english" => format!(
"{RED}{name}{RESET} is already defined in {YELLOW}{superclass}{RESET}",
),
),
Some(switch_lang!(
"japanese" => "デフォルトでオーバーライドはできません(`Override`デコレータを使用してください)",
"simplified_chinese" => "默认不可重写(请使用`Override`装饰器)",
"traditional_chinese" => "默認不可重寫(請使用`Override`裝飾器)",
"english" => "cannot override by default (use `Override` decorator)",
).into()),
),
caused_by.into(),
)
}
pub fn inheritance_error(errno: usize, class: String, loc: Location, caused_by: Str) -> Self {
Self::new(
ErrorCore::new(
errno,
InheritanceError,
loc,
switch_lang!(
"japanese" => format!("{class}は継承できません"),
"simplified_chinese" => format!("{class}不可继承"),
"traditional_chinese" => format!("{class}不可繼承"),
"english" => format!("{class} is not inheritable"),
),
None,
),
caused_by,
)
}
} }
#[derive(Debug)] #[derive(Debug)]

View file

@ -11,16 +11,16 @@ use erg_common::{
impl_stream_for_wrapper, impl_stream_for_wrapper,
}; };
use erg_parser::ast::{fmt_lines, DefId, Identifier, Params}; use erg_parser::ast::{fmt_lines, DefId, Params, TypeSpec, VarName};
use erg_parser::token::{Token, TokenKind}; use erg_parser::token::{Token, TokenKind};
use erg_type::constructors::{array, tuple}; use erg_type::constructors::{array, tuple};
use erg_type::typaram::TyParam; use erg_type::typaram::TyParam;
use erg_type::value::ValueObj; use erg_type::value::{TypeKind, ValueObj};
use erg_type::{impl_t, impl_t_for_enum, HasType, Type}; use erg_type::{impl_t, impl_t_for_enum, HasType, Type};
use crate::context::eval::type_from_token_kind;
use crate::error::readable_name; use crate::error::readable_name;
use crate::eval::type_from_token_kind;
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct Literal { pub struct Literal {
@ -119,6 +119,7 @@ impl KwArg {
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct Args { pub struct Args {
pub pos_args: Vec<PosArg>, pub pos_args: Vec<PosArg>,
pub var_args: Option<Box<PosArg>>,
pub kw_args: Vec<KwArg>, pub kw_args: Vec<KwArg>,
paren: Option<(Token, Token)>, paren: Option<(Token, Token)>,
} }
@ -128,6 +129,10 @@ impl NestedDisplay for Args {
if !self.pos_args.is_empty() { if !self.pos_args.is_empty() {
fmt_lines(self.pos_args.iter(), f, level)?; fmt_lines(self.pos_args.iter(), f, level)?;
} }
if let Some(var_args) = &self.var_args {
writeln!(f, "...")?;
var_args.fmt_nest(f, level)?;
}
if !self.kw_args.is_empty() { if !self.kw_args.is_empty() {
fmt_lines(self.kw_args.iter(), f, level)?; fmt_lines(self.kw_args.iter(), f, level)?;
} }
@ -139,6 +144,7 @@ impl From<Vec<Expr>> for Args {
fn from(exprs: Vec<Expr>) -> Self { fn from(exprs: Vec<Expr>) -> Self {
Self { Self {
pos_args: exprs.into_iter().map(PosArg::new).collect(), pos_args: exprs.into_iter().map(PosArg::new).collect(),
var_args: None,
kw_args: Vec::new(), kw_args: Vec::new(),
paren: None, paren: None,
} }
@ -167,30 +173,33 @@ impl Locational for Args {
// impl_stream!(Args, KwArg, kw_args); // impl_stream!(Args, KwArg, kw_args);
impl Args { impl Args {
pub const fn new( pub fn new(
pos_args: Vec<PosArg>, pos_args: Vec<PosArg>,
var_args: Option<PosArg>,
kw_args: Vec<KwArg>, kw_args: Vec<KwArg>,
paren: Option<(Token, Token)>, paren: Option<(Token, Token)>,
) -> Self { ) -> Self {
Self { Self {
pos_args, pos_args,
var_args: var_args.map(Box::new),
kw_args, kw_args,
paren, paren,
} }
} }
pub const fn empty() -> Self { pub fn empty() -> Self {
Self::new(vec![], vec![], None) Self::new(vec![], None, vec![], None)
} }
#[inline] #[inline]
pub fn len(&self) -> usize { pub fn len(&self) -> usize {
self.pos_args.len() + self.kw_args.len() let var_argc = if self.var_args.is_none() { 0 } else { 1 };
self.pos_args.len() + var_argc + self.kw_args.len()
} }
#[inline] #[inline]
pub fn is_empty(&self) -> bool { pub fn is_empty(&self) -> bool {
self.pos_args.is_empty() && self.kw_args.is_empty() self.pos_args.is_empty() && self.var_args.is_none() && self.kw_args.is_empty()
} }
#[inline] #[inline]
@ -243,86 +252,89 @@ impl Args {
.map(|a| &a.expr) .map(|a| &a.expr)
} }
} }
}
/// represents local variables pub fn remove_left_or_key(&mut self, key: &str) -> Option<Expr> {
#[derive(Debug, Clone)] if !self.pos_args.is_empty() {
pub struct Local { Some(self.pos_args.remove(0).expr)
pub name: Token,
/// オブジェクト自身の名前
__name__: Option<Str>,
pub(crate) t: Type,
}
impl NestedDisplay for Local {
fn fmt_nest(&self, f: &mut fmt::Formatter<'_>, _level: usize) -> fmt::Result {
let __name__ = if let Some(__name__) = self.__name__() {
format!("(__name__ = {__name__})")
} else { } else {
"".to_string() if let Some(pos) = self
}; .kw_args
write!(f, "{} (: {}){}", self.name.content, self.t, __name__) .iter()
} .position(|arg| &arg.keyword.inspect()[..] == key)
} {
Some(self.kw_args.remove(pos).expr)
impl_display_from_nested!(Local); } else {
impl_t!(Local); None
}
impl Locational for Local { }
#[inline]
fn loc(&self) -> Location {
self.name.loc()
}
}
impl Local {
pub const fn new(name: Token, __name__: Option<Str>, t: Type) -> Self {
Self { name, __name__, t }
} }
// &strにするとクローンしたいときにアロケーションコストがかかるので&Strのままで pub fn get_left_or_key(&self, key: &str) -> Option<&Expr> {
#[inline] if !self.pos_args.is_empty() {
pub fn inspect(&self) -> &Str { Some(&self.pos_args.get(0)?.expr)
&self.name.content
}
pub const fn __name__(&self) -> Option<&Str> {
self.__name__.as_ref()
}
}
#[derive(Debug, Clone)]
pub struct Public {
pub dot: Token,
pub name: Token,
/// オブジェクト自身の名前
__name__: Option<Str>,
t: Type,
}
impl NestedDisplay for Public {
fn fmt_nest(&self, f: &mut fmt::Formatter<'_>, _level: usize) -> fmt::Result {
let __name__ = if let Some(__name__) = self.__name__() {
format!("(__name__ = {__name__})")
} else { } else {
"".to_string() if let Some(pos) = self
}; .kw_args
write!(f, ".{} (: {}){}", self.name.content, self.t, __name__) .iter()
.position(|arg| &arg.keyword.inspect()[..] == key)
{
Some(&self.kw_args.get(pos)?.expr)
} else {
None
}
}
} }
} }
impl_display_from_nested!(Public); #[derive(Debug, Clone, PartialEq, Eq, Hash)]
impl_t!(Public); pub struct Identifier {
pub dot: Option<Token>,
pub name: VarName,
pub __name__: Option<Str>,
pub t: Type,
}
impl Locational for Public { impl NestedDisplay for Identifier {
#[inline] fn fmt_nest(&self, f: &mut fmt::Formatter<'_>, _level: usize) -> fmt::Result {
match &self.dot {
Some(_dot) => {
write!(f, ".{}", self.name)?;
}
None => {
write!(f, "::{}", self.name)?;
}
}
if let Some(__name__) = &self.__name__ {
write!(f, "(__name__: {})", __name__)?;
}
if self.t != Type::Uninited {
write!(f, "(: {})", self.t)?;
}
Ok(())
}
}
impl_display_from_nested!(Identifier);
impl_t!(Identifier);
impl Locational for Identifier {
fn loc(&self) -> Location { fn loc(&self) -> Location {
Location::concat(&self.dot, &self.name) if let Some(dot) = &self.dot {
Location::concat(dot, &self.name)
} else {
self.name.loc()
}
} }
} }
impl Public { impl From<&Identifier> for Field {
pub const fn new(dot: Token, name: Token, __name__: Option<Str>, t: Type) -> Self { fn from(ident: &Identifier) -> Self {
Self::new(ident.vis(), ident.inspect().clone())
}
}
impl Identifier {
pub const fn new(dot: Option<Token>, name: VarName, __name__: Option<Str>, t: Type) -> Self {
Self { Self {
dot, dot,
name, name,
@ -331,39 +343,75 @@ impl Public {
} }
} }
// &strにするとクローンしたいときにアロケーションコストがかかるので&Strのままで pub fn public(name: &'static str) -> Self {
#[inline] Self::bare(
pub fn inspect(&self) -> &Str { Some(Token::from_str(TokenKind::Dot, ".")),
&self.name.content VarName::from_static(name),
)
} }
pub const fn __name__(&self) -> Option<&Str> { pub fn private(name: Str) -> Self {
self.__name__.as_ref() Self::bare(None, VarName::from_str(name))
}
pub fn private_with_line(name: Str, line: usize) -> Self {
Self::bare(None, VarName::from_str_and_line(name, line))
}
pub fn public_with_line(dot: Token, name: Str, line: usize) -> Self {
Self::bare(Some(dot), VarName::from_str_and_line(name, line))
}
pub const fn bare(dot: Option<Token>, name: VarName) -> Self {
Self::new(dot, name, None, Type::Uninited)
}
pub fn is_const(&self) -> bool {
self.name.is_const()
}
pub const fn vis(&self) -> Visibility {
match &self.dot {
Some(_) => Visibility::Public,
None => Visibility::Private,
}
}
pub const fn inspect(&self) -> &Str {
&self.name.inspect()
}
pub fn is_procedural(&self) -> bool {
self.name.is_procedural()
} }
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct Attribute { pub struct Attribute {
pub obj: Box<Expr>, pub obj: Box<Expr>,
pub name: Token, pub ident: Identifier,
t: Type, t: Type,
} }
impl NestedDisplay for Attribute { impl NestedDisplay for Attribute {
fn fmt_nest(&self, f: &mut fmt::Formatter<'_>, _level: usize) -> fmt::Result { fn fmt_nest(&self, f: &mut fmt::Formatter<'_>, _level: usize) -> fmt::Result {
write!(f, "({}).{}(: {})", self.obj, self.name.content, self.t) if self.t != Type::Uninited {
write!(f, "({}){}(: {})", self.obj, self.ident, self.t)
} else {
write!(f, "({}){}", self.obj, self.ident)
}
} }
} }
impl_display_from_nested!(Attribute); impl_display_from_nested!(Attribute);
impl_locational!(Attribute, obj, name); impl_locational!(Attribute, obj, ident);
impl_t!(Attribute); impl_t!(Attribute);
impl Attribute { impl Attribute {
pub fn new(obj: Expr, name: Token, t: Type) -> Self { pub fn new(obj: Expr, ident: Identifier, t: Type) -> Self {
Self { Self {
obj: Box::new(obj), obj: Box::new(obj),
name, ident,
t, t,
} }
} }
@ -426,55 +474,64 @@ impl Subscript {
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub enum Accessor { pub enum Accessor {
Local(Local), Ident(Identifier),
Public(Public),
Attr(Attribute), Attr(Attribute),
TupleAttr(TupleAttribute), TupleAttr(TupleAttribute),
Subscr(Subscript), Subscr(Subscript),
} }
impl_nested_display_for_enum!(Accessor; Local, Public, Attr, TupleAttr, Subscr); impl_nested_display_for_enum!(Accessor; Ident, Attr, TupleAttr, Subscr);
impl_display_from_nested!(Accessor); impl_display_from_nested!(Accessor);
impl_locational_for_enum!(Accessor; Local, Public, Attr, TupleAttr, Subscr); impl_locational_for_enum!(Accessor; Ident, Attr, TupleAttr, Subscr);
impl_t_for_enum!(Accessor; Local, Public, Attr, TupleAttr, Subscr); impl_t_for_enum!(Accessor; Ident, Attr, TupleAttr, Subscr);
impl Accessor { impl Accessor {
pub const fn local(symbol: Token, t: Type) -> Self { pub fn private_with_line(name: Str, line: usize) -> Self {
Self::Local(Local::new(symbol, None, t)) Self::Ident(Identifier::private_with_line(name, line))
} }
pub const fn public(dot: Token, name: Token, t: Type) -> Self { pub fn public_with_line(name: Str, line: usize) -> Self {
Self::Public(Public::new(dot, name, None, t)) Self::Ident(Identifier::public_with_line(Token::dummy(), name, line))
} }
pub fn attr(obj: Expr, name: Token, t: Type) -> Self { pub const fn private(name: Token, t: Type) -> Self {
Self::Attr(Attribute::new(obj, name, t)) Self::Ident(Identifier::new(None, VarName::new(name), None, t))
}
pub fn attr(obj: Expr, ident: Identifier, t: Type) -> Self {
Self::Attr(Attribute::new(obj, ident, t))
} }
pub fn subscr(obj: Expr, index: Expr, t: Type) -> Self { pub fn subscr(obj: Expr, index: Expr, t: Type) -> Self {
Self::Subscr(Subscript::new(obj, index, t)) Self::Subscr(Subscript::new(obj, index, t))
} }
pub fn var_full_name(&self) -> Option<String> { pub fn show(&self) -> String {
match self { match self {
Self::Local(local) => Some(readable_name(local.inspect()).to_string()), Self::Ident(ident) => readable_name(ident.inspect()).to_string(),
Self::Attr(attr) => attr Self::Attr(attr) => {
.obj attr.obj
.var_full_name() .show_acc()
.map(|n| n + "." + readable_name(attr.name.inspect())), .unwrap_or_else(|| attr.obj.ref_t().to_string())
Self::TupleAttr(t_attr) => t_attr + "." // TODO: visibility
.obj + readable_name(attr.ident.inspect())
.var_full_name() }
.map(|n| n + "." + t_attr.index.token.inspect()), Self::TupleAttr(t_attr) => {
Self::Subscr(_) | Self::Public(_) => todo!(), t_attr
.obj
.show_acc()
.unwrap_or_else(|| t_attr.obj.ref_t().to_string())
+ "."
+ t_attr.index.token.inspect()
}
Self::Subscr(_) => todo!(),
} }
} }
// 参照するオブジェクト自体が持っている固有の名前 // 参照するオブジェクト自体が持っている固有の名前(クラス、モジュールなど)
pub fn __name__(&self) -> Option<&str> { pub fn __name__(&self) -> Option<&str> {
match self { match self {
Self::Local(local) => local.__name__().map(|s| &s[..]), Self::Ident(ident) => ident.__name__.as_ref().map(|s| &s[..]),
Self::Public(public) => public.__name__().map(|s| &s[..]),
_ => None, _ => None,
} }
} }
@ -688,6 +745,15 @@ impl NestedDisplay for RecordAttrs {
} }
} }
impl_display_from_nested!(RecordAttrs);
impl_stream_for_wrapper!(RecordAttrs, Def);
impl Locational for RecordAttrs {
fn loc(&self) -> Location {
Location::concat(self.0.first().unwrap(), self.0.last().unwrap())
}
}
impl From<Vec<Def>> for RecordAttrs { impl From<Vec<Def>> for RecordAttrs {
fn from(attrs: Vec<Def>) -> Self { fn from(attrs: Vec<Def>) -> Self {
Self(attrs) Self(attrs)
@ -695,10 +761,6 @@ impl From<Vec<Def>> for RecordAttrs {
} }
impl RecordAttrs { impl RecordAttrs {
pub const fn new() -> Self {
Self(vec![])
}
pub fn len(&self) -> usize { pub fn len(&self) -> usize {
self.0.len() self.0.len()
} }
@ -718,6 +780,10 @@ impl RecordAttrs {
pub fn push(&mut self, attr: Def) { pub fn push(&mut self, attr: Def) {
self.0.push(attr); self.0.push(attr);
} }
pub fn extend(&mut self, attrs: RecordAttrs) {
self.0.extend(attrs.0);
}
} }
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
@ -875,7 +941,7 @@ impl UnaryOp {
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct Call { pub struct Call {
pub obj: Box<Expr>, pub obj: Box<Expr>,
pub method_name: Option<Token>, pub method_name: Option<Identifier>,
pub args: Args, pub args: Args,
/// 全体の型(引数自体の型は関係ない)、e.g. `abs(-1)` -> `Neg -> Nat` /// 全体の型(引数自体の型は関係ない)、e.g. `abs(-1)` -> `Neg -> Nat`
pub sig_t: Type, pub sig_t: Type,
@ -885,9 +951,9 @@ impl NestedDisplay for Call {
fn fmt_nest(&self, f: &mut std::fmt::Formatter<'_>, level: usize) -> std::fmt::Result { fn fmt_nest(&self, f: &mut std::fmt::Formatter<'_>, level: usize) -> std::fmt::Result {
writeln!( writeln!(
f, f,
"({}){}(: {}):", "({}){} (: {}):",
self.obj, self.obj,
fmt_option!(pre ".", self.method_name), fmt_option!(self.method_name),
self.sig_t self.sig_t
)?; )?;
self.args.fmt_nest(f, level + 1) self.args.fmt_nest(f, level + 1)
@ -930,7 +996,7 @@ impl Locational for Call {
} }
impl Call { impl Call {
pub fn new(obj: Expr, method_name: Option<Token>, args: Args, sig_t: Type) -> Self { pub fn new(obj: Expr, method_name: Option<Identifier>, args: Args, sig_t: Type) -> Self {
Self { Self {
obj: Box::new(obj), obj: Box::new(obj),
method_name, method_name,
@ -941,7 +1007,7 @@ impl Call {
pub fn is_import_call(&self) -> bool { pub fn is_import_call(&self) -> bool {
self.obj self.obj
.var_full_name() .show_acc()
.map(|s| &s[..] == "import" || &s[..] == "pyimport" || &s[..] == "py") .map(|s| &s[..] == "import" || &s[..] == "pyimport" || &s[..] == "py")
.unwrap_or(false) .unwrap_or(false)
} }
@ -1002,6 +1068,7 @@ impl NestedDisplay for VarSignature {
impl_display_from_nested!(VarSignature); impl_display_from_nested!(VarSignature);
impl_locational!(VarSignature, ident); impl_locational!(VarSignature, ident);
impl_t!(VarSignature);
impl VarSignature { impl VarSignature {
pub const fn new(ident: Identifier, t: Type) -> Self { pub const fn new(ident: Identifier, t: Type) -> Self {
@ -1032,6 +1099,7 @@ impl NestedDisplay for SubrSignature {
impl_display_from_nested!(SubrSignature); impl_display_from_nested!(SubrSignature);
impl_locational!(SubrSignature, ident, params); impl_locational!(SubrSignature, ident, params);
impl_t!(SubrSignature);
impl SubrSignature { impl SubrSignature {
pub const fn new(ident: Identifier, params: Params, t: Type) -> Self { pub const fn new(ident: Identifier, params: Params, t: Type) -> Self {
@ -1087,6 +1155,7 @@ pub enum Signature {
impl_nested_display_for_chunk_enum!(Signature; Var, Subr); impl_nested_display_for_chunk_enum!(Signature; Var, Subr);
impl_display_for_enum!(Signature; Var, Subr,); impl_display_for_enum!(Signature; Var, Subr,);
impl_t_for_enum!(Signature; Var, Subr);
impl_locational_for_enum!(Signature; Var, Subr,); impl_locational_for_enum!(Signature; Var, Subr,);
impl Signature { impl Signature {
@ -1121,6 +1190,13 @@ impl Signature {
Self::Subr(s) => &s.ident, Self::Subr(s) => &s.ident,
} }
} }
pub fn ident_mut(&mut self) -> &mut Identifier {
match self {
Self::Var(v) => &mut v.ident,
Self::Subr(s) => &mut s.ident,
}
}
} }
/// represents a declaration of a variable /// represents a declaration of a variable
@ -1188,19 +1264,6 @@ impl DefBody {
pub const fn new(op: Token, block: Block, id: DefId) -> Self { pub const fn new(op: Token, block: Block, id: DefId) -> Self {
Self { op, block, id } Self { op, block, id }
} }
pub fn is_type(&self) -> bool {
match self.block.first().unwrap() {
Expr::Call(call) => {
if let Expr::Accessor(Accessor::Local(local)) = call.obj.as_ref() {
&local.inspect()[..] == "Type"
} else {
false
}
}
_ => false,
}
}
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
@ -1244,6 +1307,155 @@ impl Def {
} }
} }
#[derive(Debug, Clone)]
pub struct Methods {
pub class: TypeSpec,
pub vis: Token, // `.` or `::`
pub defs: RecordAttrs, // TODO: allow declaration
}
impl NestedDisplay for Methods {
fn fmt_nest(&self, f: &mut fmt::Formatter<'_>, level: usize) -> fmt::Result {
writeln!(f, "{}{}", self.class, self.vis.content)?;
self.defs.fmt_nest(f, level + 1)
}
}
impl_display_from_nested!(Methods);
impl_locational!(Methods, class, defs);
impl HasType for Methods {
#[inline]
fn ref_t(&self) -> &Type {
Type::NONE
}
#[inline]
fn ref_mut_t(&mut self) -> &mut Type {
todo!()
}
#[inline]
fn signature_t(&self) -> Option<&Type> {
None
}
#[inline]
fn signature_mut_t(&mut self) -> Option<&mut Type> {
None
}
}
impl Methods {
pub const fn new(class: TypeSpec, vis: Token, defs: RecordAttrs) -> Self {
Self { class, vis, defs }
}
}
#[derive(Debug, Clone)]
pub struct ClassDef {
pub kind: TypeKind,
pub sig: Signature,
pub require_or_sup: Box<Expr>,
/// The type of `new` that is automatically defined if not defined
pub need_to_gen_new: bool,
pub __new__: Type,
pub private_methods: RecordAttrs,
pub public_methods: RecordAttrs,
}
impl NestedDisplay for ClassDef {
fn fmt_nest(&self, f: &mut fmt::Formatter<'_>, level: usize) -> fmt::Result {
self.sig.fmt_nest(f, level)?;
writeln!(f, ":")?;
self.private_methods.fmt_nest(f, level + 1)?;
self.public_methods.fmt_nest(f, level + 1)
}
}
impl_display_from_nested!(ClassDef);
impl_locational!(ClassDef, sig);
impl HasType for ClassDef {
#[inline]
fn ref_t(&self) -> &Type {
Type::NONE
}
#[inline]
fn ref_mut_t(&mut self) -> &mut Type {
todo!()
}
#[inline]
fn signature_t(&self) -> Option<&Type> {
None
}
#[inline]
fn signature_mut_t(&mut self) -> Option<&mut Type> {
None
}
}
impl ClassDef {
pub fn new(
kind: TypeKind,
sig: Signature,
require_or_sup: Expr,
need_to_gen_new: bool,
__new__: Type,
private_methods: RecordAttrs,
public_methods: RecordAttrs,
) -> Self {
Self {
kind,
sig,
require_or_sup: Box::new(require_or_sup),
need_to_gen_new,
__new__,
private_methods,
public_methods,
}
}
}
#[derive(Debug, Clone)]
pub struct AttrDef {
pub attr: Accessor,
pub block: Block,
}
impl NestedDisplay for AttrDef {
fn fmt_nest(&self, f: &mut fmt::Formatter<'_>, level: usize) -> fmt::Result {
self.attr.fmt_nest(f, level)?;
writeln!(f, " = ")?;
self.block.fmt_nest(f, level + 1)
}
}
impl_display_from_nested!(AttrDef);
impl_locational!(AttrDef, attr, block);
impl HasType for AttrDef {
#[inline]
fn ref_t(&self) -> &Type {
Type::NONE
}
#[inline]
fn ref_mut_t(&mut self) -> &mut Type {
todo!()
}
#[inline]
fn signature_t(&self) -> Option<&Type> {
None
}
#[inline]
fn signature_mut_t(&mut self) -> Option<&mut Type> {
None
}
}
impl AttrDef {
pub const fn new(attr: Accessor, block: Block) -> Self {
Self { attr, block }
}
}
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub enum Expr { pub enum Expr {
Lit(Literal), Lit(Literal),
@ -1259,12 +1471,14 @@ pub enum Expr {
Lambda(Lambda), Lambda(Lambda),
Decl(Decl), Decl(Decl),
Def(Def), Def(Def),
ClassDef(ClassDef),
AttrDef(AttrDef),
} }
impl_nested_display_for_chunk_enum!(Expr; Lit, Accessor, Array, Tuple, Dict, Record, BinOp, UnaryOp, Call, Lambda, Decl, Def); impl_nested_display_for_chunk_enum!(Expr; Lit, Accessor, Array, Tuple, Dict, Record, BinOp, UnaryOp, Call, Lambda, Decl, Def, ClassDef, AttrDef);
impl_display_from_nested!(Expr); impl_display_from_nested!(Expr);
impl_locational_for_enum!(Expr; Lit, Accessor, Array, Tuple, Dict, Record, BinOp, UnaryOp, Call, Lambda, Decl, Def); impl_locational_for_enum!(Expr; Lit, Accessor, Array, Tuple, Dict, Record, BinOp, UnaryOp, Call, Lambda, Decl, Def, ClassDef, AttrDef);
impl_t_for_enum!(Expr; Lit, Accessor, Array, Tuple, Dict, Record, BinOp, UnaryOp, Call, Lambda, Decl, Def); impl_t_for_enum!(Expr; Lit, Accessor, Array, Tuple, Dict, Record, BinOp, UnaryOp, Call, Lambda, Decl, Def, ClassDef, AttrDef);
impl Expr { impl Expr {
pub fn receiver_t(&self) -> Option<&Type> { pub fn receiver_t(&self) -> Option<&Type> {
@ -1274,9 +1488,9 @@ impl Expr {
} }
} }
pub fn var_full_name(&self) -> Option<String> { pub fn show_acc(&self) -> Option<String> {
match self { match self {
Expr::Accessor(acc) => acc.var_full_name(), Expr::Accessor(acc) => Some(acc.show()),
_ => None, _ => None,
} }
} }
@ -1285,7 +1499,7 @@ impl Expr {
pub fn __name__(&self) -> Option<&str> { pub fn __name__(&self) -> Option<&str> {
match self { match self {
Expr::Accessor(acc) => acc.__name__(), Expr::Accessor(acc) => acc.__name__(),
_ => todo!(), _ => None,
} }
} }
} }

View file

@ -7,8 +7,8 @@ pub use compile::*;
mod codegen; mod codegen;
pub mod effectcheck; pub mod effectcheck;
pub mod error; pub mod error;
pub mod eval;
pub mod hir; pub mod hir;
pub mod link;
pub mod lower; pub mod lower;
pub use lower::ASTLowerer; pub use lower::ASTLowerer;
pub mod context; pub mod context;

View file

@ -0,0 +1,93 @@
use erg_common::dict::Dict;
use erg_common::log;
use erg_common::traits::{Locational, Stream};
use erg_common::Str;
use erg_parser::ast::{ClassDef, Expr, Module, PreDeclTypeSpec, TypeSpec, AST};
use crate::error::{TyCheckError, TyCheckErrors};
/// Combine method definitions across multiple modules, specialized class contexts, etc.
#[derive(Debug)]
pub struct Linker {
// TODO: inner scope types
pub def_root_pos_map: Dict<Str, usize>,
pub errs: TyCheckErrors,
}
impl Linker {
pub fn new() -> Self {
Self {
def_root_pos_map: Dict::new(),
errs: TyCheckErrors::empty(),
}
}
pub fn link(mut self, mut ast: AST) -> Result<AST, TyCheckErrors> {
log!(info "the linking process has started.");
let mut new = vec![];
while let Some(chunk) = ast.module.lpop() {
match chunk {
Expr::Def(def) => {
match def.body.block.first().unwrap() {
Expr::Call(call) => {
match call.obj.get_name().map(|s| &s[..]) {
// TODO: decorator
Some("Class" | "Inherit" | "Inheritable") => {
self.def_root_pos_map.insert(
def.sig.ident().unwrap().inspect().clone(),
new.len(),
);
let type_def = ClassDef::new(def, vec![]);
new.push(Expr::ClassDef(type_def));
}
_ => {
new.push(Expr::Def(def));
}
}
}
_ => {
new.push(Expr::Def(def));
}
}
}
Expr::Methods(methods) => match &methods.class {
TypeSpec::PreDeclTy(PreDeclTypeSpec::Simple(simple)) => {
if let Some(pos) = self.def_root_pos_map.get(simple.name.inspect()) {
let mut class_def = match new.remove(*pos) {
Expr::ClassDef(class_def) => class_def,
_ => unreachable!(),
};
class_def.methods_list.push(methods);
new.insert(*pos, Expr::ClassDef(class_def));
} else {
let similar_name = Str::from(
self.def_root_pos_map
.keys()
.fold("".to_string(), |acc, key| acc + &key[..] + ","),
);
self.errs.push(TyCheckError::no_var_error(
line!() as usize,
methods.class.loc(),
"".into(),
simple.name.inspect(),
Some(&similar_name),
));
}
}
other => todo!("{other}"),
},
other => {
new.push(other);
}
}
}
let ast = AST::new(ast.name, Module::new(new));
log!(info "the linking process has completed:\n{}", ast);
if self.errs.is_empty() {
Ok(ast)
} else {
Err(self.errs)
}
}
}

View file

@ -9,18 +9,48 @@ use erg_common::{enum_unwrap, fmt_option, fn_name, get_hash, log, switch_lang, S
use erg_parser::ast; use erg_parser::ast;
use erg_parser::ast::AST; use erg_parser::ast::AST;
use erg_type::constructors::{array, array_mut, class, free_var, func, poly_class, proc, quant}; use erg_parser::token::{Token, TokenKind};
use erg_type::constructors::{array, array_mut, free_var, func, mono, poly, proc, quant};
use erg_type::free::Constraint; use erg_type::free::Constraint;
use erg_type::typaram::TyParam; use erg_type::typaram::TyParam;
use erg_type::value::ValueObj; use erg_type::value::{TypeObj, ValueObj};
use erg_type::{HasType, ParamTy, Type}; use erg_type::{HasType, ParamTy, Type};
use crate::context::{Context, ContextKind, RegistrationMode}; use crate::context::{Context, ContextKind, RegistrationMode};
use crate::error::{LowerError, LowerErrors, LowerResult, LowerWarnings}; use crate::error::{LowerError, LowerErrors, LowerResult, LowerWarnings};
use crate::hir; use crate::hir;
use crate::hir::HIR; use crate::hir::HIR;
use crate::varinfo::VarKind;
use Visibility::*; use Visibility::*;
/// HACK: Cannot be methodized this because a reference has been taken immediately before.
macro_rules! check_inheritable {
($self: ident, $type_obj: expr, $sup_class: expr, $sub_sig: expr) => {
match $type_obj.require_or_sup.as_ref() {
TypeObj::Generated(gen) => {
if let Some(impls) = gen.impls.as_ref() {
if !impls.contains_intersec(&mono("InheritableType")) {
$self.errs.push(LowerError::inheritance_error(
line!() as usize,
$sup_class.to_string(),
$sup_class.loc(),
$sub_sig.ident().inspect().clone(),
));
}
} else {
$self.errs.push(LowerError::inheritance_error(
line!() as usize,
$sup_class.to_string(),
$sup_class.loc(),
$sub_sig.ident().inspect().clone(),
));
}
}
_ => {}
}
};
}
/// Singleton that checks types of an AST, and convert (lower) it into a HIR /// Singleton that checks types of an AST, and convert (lower) it into a HIR
#[derive(Debug)] #[derive(Debug)]
pub struct ASTLowerer { pub struct ASTLowerer {
@ -137,7 +167,7 @@ impl ASTLowerer {
new_array.push(elem); new_array.push(elem);
} }
let elem_t = if union == Type::Never { let elem_t = if union == Type::Never {
free_var(self.ctx.level, Constraint::type_of(Type::Type)) free_var(self.ctx.level, Constraint::new_type_of(Type::Type))
} else { } else {
union union
}; };
@ -162,11 +192,11 @@ impl ASTLowerer {
} }
fn gen_array_with_length_type(&self, elem: &hir::Expr, len: &ast::Expr) -> Type { fn gen_array_with_length_type(&self, elem: &hir::Expr, len: &ast::Expr) -> Type {
let maybe_len = self.ctx.eval.eval_const_expr(len, &self.ctx); let maybe_len = self.ctx.eval_const_expr(len, None);
match maybe_len { match maybe_len {
Some(v @ ValueObj::Nat(_)) => { Ok(v @ ValueObj::Nat(_)) => {
if elem.ref_t().is_mut() { if elem.ref_t().is_mut() {
poly_class( poly(
"ArrayWithMutType!", "ArrayWithMutType!",
vec![TyParam::t(elem.t()), TyParam::Value(v)], vec![TyParam::t(elem.t()), TyParam::Value(v)],
) )
@ -174,9 +204,9 @@ impl ASTLowerer {
array(elem.t(), TyParam::Value(v)) array(elem.t(), TyParam::Value(v))
} }
} }
Some(v @ ValueObj::Mut(_)) if v.class() == class("Nat!") => { Ok(v @ ValueObj::Mut(_)) if v.class() == mono("Nat!") => {
if elem.ref_t().is_mut() { if elem.ref_t().is_mut() {
poly_class( poly(
"ArrayWithMutTypeAndLength!", "ArrayWithMutTypeAndLength!",
vec![TyParam::t(elem.t()), TyParam::Value(v)], vec![TyParam::t(elem.t()), TyParam::Value(v)],
) )
@ -184,11 +214,11 @@ impl ASTLowerer {
array_mut(elem.t(), TyParam::Value(v)) array_mut(elem.t(), TyParam::Value(v))
} }
} }
Some(other) => todo!("{other} is not a Nat object"), Ok(other) => todo!("{other} is not a Nat object"),
// TODO: [T; !_] // REVIEW: is it ok to ignore the error?
None => { Err(_e) => {
if elem.ref_t().is_mut() { if elem.ref_t().is_mut() {
poly_class( poly(
"ArrayWithMutType!", "ArrayWithMutType!",
vec![TyParam::t(elem.t()), TyParam::erased(Type::Nat)], vec![TyParam::t(elem.t()), TyParam::erased(Type::Nat)],
) )
@ -217,13 +247,24 @@ impl ASTLowerer {
Ok(hir::NormalTuple::new(hir::Args::from(new_tuple))) Ok(hir::NormalTuple::new(hir::Args::from(new_tuple)))
} }
fn lower_record(&mut self, record: ast::NormalRecord) -> LowerResult<hir::Record> { fn lower_record(&mut self, record: ast::Record) -> LowerResult<hir::Record> {
log!(info "entered {}({record})", fn_name!());
match record {
ast::Record::Normal(rec) => self.lower_normal_record(rec),
ast::Record::Shortened(_rec) => unreachable!(), // should be desugared
}
}
fn lower_normal_record(&mut self, record: ast::NormalRecord) -> LowerResult<hir::Record> {
log!(info "entered {}({record})", fn_name!()); log!(info "entered {}({record})", fn_name!());
let mut hir_record = let mut hir_record =
hir::Record::new(record.l_brace, record.r_brace, hir::RecordAttrs::new()); hir::Record::new(record.l_brace, record.r_brace, hir::RecordAttrs::empty());
self.ctx.grow("<record>", ContextKind::Dummy, Private)?; self.ctx.grow("<record>", ContextKind::Dummy, Private)?;
for attr in record.attrs.into_iter() { for attr in record.attrs.into_iter() {
let attr = self.lower_def(attr)?; let attr = self.lower_def(attr).map_err(|e| {
self.pop_append_errs();
e
})?;
hir_record.push(attr); hir_record.push(attr);
} }
self.pop_append_errs(); self.pop_append_errs();
@ -233,37 +274,16 @@ impl ASTLowerer {
fn lower_acc(&mut self, acc: ast::Accessor) -> LowerResult<hir::Accessor> { fn lower_acc(&mut self, acc: ast::Accessor) -> LowerResult<hir::Accessor> {
log!(info "entered {}({acc})", fn_name!()); log!(info "entered {}({acc})", fn_name!());
match acc { match acc {
ast::Accessor::Local(local) => { ast::Accessor::Ident(ident) => {
// `match` is an untypable special form let ident = self.lower_ident(ident)?;
// `match`は型付け不可能な特殊形式 let acc = hir::Accessor::Ident(ident);
let (t, __name__) = if &local.inspect()[..] == "match" {
(Type::Failure, None)
} else {
(
self.ctx
.rec_get_var_t(&local.symbol, Private, &self.ctx.name)?,
self.ctx.get_local_uniq_obj_name(&local.symbol),
)
};
let acc = hir::Accessor::Local(hir::Local::new(local.symbol, __name__, t));
Ok(acc)
}
ast::Accessor::Public(public) => {
let (t, __name__) = (
self.ctx
.rec_get_var_t(&public.symbol, Public, &self.ctx.name)?,
self.ctx.get_local_uniq_obj_name(&public.symbol),
);
let public = hir::Public::new(public.dot, public.symbol, __name__, t);
let acc = hir::Accessor::Public(public);
Ok(acc) Ok(acc)
} }
ast::Accessor::Attr(attr) => { ast::Accessor::Attr(attr) => {
let obj = self.lower_expr(*attr.obj)?; let obj = self.lower_expr(*attr.obj)?;
let t = self let t = self.ctx.rec_get_attr_t(&obj, &attr.ident, &self.ctx.name)?;
.ctx let ident = hir::Identifier::bare(attr.ident.dot, attr.ident.name);
.rec_get_attr_t(&obj, &attr.name.symbol, &self.ctx.name)?; let acc = hir::Accessor::Attr(hir::Attribute::new(obj, ident, t));
let acc = hir::Accessor::Attr(hir::Attribute::new(obj, attr.name.symbol, t));
Ok(acc) Ok(acc)
} }
ast::Accessor::TupleAttr(t_attr) => { ast::Accessor::TupleAttr(t_attr) => {
@ -291,6 +311,21 @@ impl ASTLowerer {
} }
} }
fn lower_ident(&self, ident: ast::Identifier) -> LowerResult<hir::Identifier> {
// `match` is an untypable special form
// `match`は型付け不可能な特殊形式
let (t, __name__) = if ident.vis().is_private() && &ident.inspect()[..] == "match" {
(Type::Failure, None)
} else {
(
self.ctx.rec_get_var_t(&ident, &self.ctx.name)?,
self.ctx.get_local_uniq_obj_name(ident.name.token()),
)
};
let ident = hir::Identifier::new(ident.dot, ident.name, __name__, t);
Ok(ident)
}
fn lower_bin(&mut self, bin: ast::BinOp) -> LowerResult<hir::BinOp> { fn lower_bin(&mut self, bin: ast::BinOp) -> LowerResult<hir::BinOp> {
log!(info "entered {}({bin})", fn_name!()); log!(info "entered {}({bin})", fn_name!());
let mut args = bin.args.into_iter(); let mut args = bin.args.into_iter();
@ -320,6 +355,7 @@ impl ASTLowerer {
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()),
None,
Vec::with_capacity(kw_args.len()), Vec::with_capacity(kw_args.len()),
paren, paren,
); );
@ -330,14 +366,55 @@ impl ASTLowerer {
hir_args.push_kw(hir::KwArg::new(arg.keyword, self.lower_expr(arg.expr)?)); hir_args.push_kw(hir::KwArg::new(arg.keyword, self.lower_expr(arg.expr)?));
} }
let obj = self.lower_expr(*call.obj)?; let obj = self.lower_expr(*call.obj)?;
let t = self.ctx.get_call_t( let sig_t = self.ctx.get_call_t(
&obj, &obj,
&call.method_name, &call.method_name,
&hir_args.pos_args, &hir_args.pos_args,
&hir_args.kw_args, &hir_args.kw_args,
&self.ctx.name, &self.ctx.name,
)?; )?;
Ok(hir::Call::new(obj, call.method_name, hir_args, t)) let method_name = if let Some(method_name) = call.method_name {
Some(hir::Identifier::new(
method_name.dot,
method_name.name,
None,
Type::Uninited,
))
} else {
None
};
Ok(hir::Call::new(obj, method_name, hir_args, sig_t))
}
fn lower_pack(&mut self, pack: ast::DataPack) -> LowerResult<hir::Call> {
log!(info "entered {}({pack})", fn_name!());
let class = self.lower_expr(*pack.class)?;
let args = self.lower_record(pack.args)?;
let args = vec![hir::PosArg::new(hir::Expr::Record(args))];
let method_name = ast::Identifier::new(
Some(Token::new(
TokenKind::Dot,
Str::ever("."),
pack.connector.lineno,
pack.connector.col_begin,
)),
ast::VarName::new(Token::new(
TokenKind::Symbol,
Str::ever("new"),
pack.connector.lineno,
pack.connector.col_begin,
)),
);
let sig_t = self.ctx.get_call_t(
&class,
&Some(method_name.clone()),
&args,
&[],
&self.ctx.name,
)?;
let args = hir::Args::new(args, None, vec![], None);
let method_name = hir::Identifier::bare(method_name.dot, method_name.name);
Ok(hir::Call::new(class, Some(method_name), args, sig_t))
} }
/// TODO: varargs /// TODO: varargs
@ -358,12 +435,10 @@ impl ASTLowerer {
self.pop_append_errs(); self.pop_append_errs();
e e
})?; })?;
self.ctx self.ctx.preregister(&lambda.body).map_err(|e| {
.preregister(lambda.body.ref_payload()) self.pop_append_errs();
.map_err(|e| { e
self.pop_append_errs(); })?;
e
})?;
let body = self.lower_block(lambda.body).map_err(|e| { let body = self.lower_block(lambda.body).map_err(|e| {
self.pop_append_errs(); self.pop_append_errs();
e e
@ -406,20 +481,24 @@ impl ASTLowerer {
fn lower_def(&mut self, def: ast::Def) -> LowerResult<hir::Def> { fn lower_def(&mut self, def: ast::Def) -> LowerResult<hir::Def> {
log!(info "entered {}({})", fn_name!(), def.sig); log!(info "entered {}({})", fn_name!(), def.sig);
if let Some(name) = def.sig.name_as_str() { if def.body.block.len() >= 1 {
self.ctx.grow(name, ContextKind::Instant, Private)?; let name = if let Some(name) = def.sig.name_as_str() {
name
} else {
"<lambda>"
};
self.ctx.grow(name, ContextKind::Instant, def.sig.vis())?;
let res = match def.sig { let res = match def.sig {
ast::Signature::Subr(sig) => self.lower_subr_def(sig, def.body), ast::Signature::Subr(sig) => self.lower_subr_def(sig, def.body),
ast::Signature::Var(sig) => self.lower_var_def(sig, def.body), ast::Signature::Var(sig) => self.lower_var_def(sig, def.body),
}; };
// TODO: Context上の関数に型境界情報を追加 // TODO: Context上の関数に型境界情報を追加
self.pop_append_errs(); self.pop_append_errs();
res return res;
} else { }
match def.sig { match def.sig {
ast::Signature::Subr(sig) => self.lower_subr_def(sig, def.body), ast::Signature::Subr(sig) => self.lower_subr_def(sig, def.body),
ast::Signature::Var(sig) => self.lower_var_def(sig, def.body), ast::Signature::Var(sig) => self.lower_var_def(sig, def.body),
}
} }
} }
@ -429,7 +508,7 @@ impl ASTLowerer {
body: ast::DefBody, body: ast::DefBody,
) -> LowerResult<hir::Def> { ) -> LowerResult<hir::Def> {
log!(info "entered {}({sig})", fn_name!()); log!(info "entered {}({sig})", fn_name!());
self.ctx.preregister(body.block.ref_payload())?; self.ctx.preregister(&body.block)?;
let block = self.lower_block(body.block)?; let block = self.lower_block(body.block)?;
let found_body_t = block.ref_t(); let found_body_t = block.ref_t();
let opt_expect_body_t = self let opt_expect_body_t = self
@ -444,10 +523,14 @@ impl ASTLowerer {
_ => unreachable!(), _ => unreachable!(),
}; };
if let Some(expect_body_t) = opt_expect_body_t { if let Some(expect_body_t) = opt_expect_body_t {
if let Err(e) = // TODO: expect_body_t is smaller for constants
self.return_t_check(sig.loc(), ident.inspect(), &expect_body_t, found_body_t) // TODO: 定数の場合、expect_body_tのほうが小さくなってしまう
{ if !sig.is_const() {
self.errs.push(e); if let Err(e) =
self.return_t_check(sig.loc(), ident.inspect(), &expect_body_t, found_body_t)
{
self.errs.push(e);
}
} }
} }
let id = body.id; let id = body.id;
@ -469,7 +552,8 @@ impl ASTLowerer {
} }
_other => {} _other => {}
} }
let sig = hir::VarSignature::new(ident.clone(), found_body_t.clone()); let ident = hir::Identifier::bare(ident.dot.clone(), ident.name.clone());
let sig = hir::VarSignature::new(ident, found_body_t.clone());
let body = hir::DefBody::new(body.op, block, body.id); let body = hir::DefBody::new(body.op, block, body.id);
Ok(hir::Def::new(hir::Signature::Var(sig), body)) Ok(hir::Def::new(hir::Signature::Var(sig), body))
} }
@ -487,22 +571,20 @@ impl ASTLowerer {
.as_ref() .as_ref()
.unwrap() .unwrap()
.get_current_scope_var(sig.ident.inspect()) .get_current_scope_var(sig.ident.inspect())
.unwrap_or_else(|| { .unwrap()
log!(info "{}\n", sig.ident.inspect());
log!(info "{}\n", self.ctx.outer.as_ref().unwrap());
panic!()
}) // FIXME: or instantiate
.t .t
.clone(); .clone();
self.ctx.assign_params(&sig.params, None)?; self.ctx.assign_params(&sig.params, None)?;
self.ctx.preregister(body.block.ref_payload())?; self.ctx.preregister(&body.block)?;
let block = self.lower_block(body.block)?; let block = self.lower_block(body.block)?;
let found_body_t = block.ref_t(); let found_body_t = block.ref_t();
let expect_body_t = t.return_t().unwrap(); let expect_body_t = t.return_t().unwrap();
if let Err(e) = if !sig.is_const() {
self.return_t_check(sig.loc(), sig.ident.inspect(), &expect_body_t, found_body_t) if let Err(e) =
{ self.return_t_check(sig.loc(), sig.ident.inspect(), &expect_body_t, found_body_t)
self.errs.push(e); {
self.errs.push(e);
}
} }
let id = body.id; let id = body.id;
self.ctx self.ctx
@ -510,11 +592,156 @@ impl ASTLowerer {
.as_mut() .as_mut()
.unwrap() .unwrap()
.assign_subr(&sig, id, found_body_t)?; .assign_subr(&sig, id, found_body_t)?;
let sig = hir::SubrSignature::new(sig.ident, sig.params, t); let ident = hir::Identifier::bare(sig.ident.dot, sig.ident.name);
let sig = hir::SubrSignature::new(ident, sig.params, t);
let body = hir::DefBody::new(body.op, block, body.id); let body = hir::DefBody::new(body.op, block, body.id);
Ok(hir::Def::new(hir::Signature::Subr(sig), body)) Ok(hir::Def::new(hir::Signature::Subr(sig), body))
} }
fn lower_class_def(&mut self, class_def: ast::ClassDef) -> LowerResult<hir::ClassDef> {
log!(info "entered {}({class_def})", fn_name!());
let mut hir_def = self.lower_def(class_def.def)?;
let mut private_methods = hir::RecordAttrs::empty();
let mut public_methods = hir::RecordAttrs::empty();
for mut methods in class_def.methods_list.into_iter() {
let class = self
.ctx
.instantiate_typespec(&methods.class, RegistrationMode::Normal)?;
self.ctx
.grow(&class.name(), ContextKind::MethodDefs, Private)?;
for def in methods.defs.iter_mut() {
if methods.vis.is(TokenKind::Dot) {
def.sig.ident_mut().unwrap().dot = Some(Token::new(
TokenKind::Dot,
".",
def.sig.ln_begin().unwrap(),
def.sig.col_begin().unwrap(),
));
}
self.ctx.preregister_def(def)?;
}
for def in methods.defs.into_iter() {
if methods.vis.is(TokenKind::Dot) {
let def = self.lower_def(def).map_err(|e| {
self.pop_append_errs();
e
})?;
public_methods.push(def);
} else {
let def = self.lower_def(def).map_err(|e| {
self.pop_append_errs();
e
})?;
private_methods.push(def);
}
}
match self.ctx.pop() {
Ok(methods) => {
self.check_override(&class, &methods);
if let Some((_, class_root)) = self.ctx.rec_get_mut_nominal_type_ctx(&class) {
for (newly_defined_name, _vi) in methods.locals.iter() {
for (_, already_defined_methods) in class_root.methods_list.iter_mut() {
// TODO: 特殊化なら同じ名前でもOK
// TODO: 定義のメソッドもエラー表示
if let Some((_already_defined_name, already_defined_vi)) =
already_defined_methods
.get_local_kv(&newly_defined_name.inspect())
{
if already_defined_vi.kind != VarKind::Auto {
self.errs.push(LowerError::duplicate_definition_error(
line!() as usize,
newly_defined_name.loc(),
methods.name.clone(),
newly_defined_name.inspect(),
));
} else {
already_defined_methods
.locals
.remove(&newly_defined_name.inspect()[..]);
}
}
}
}
class_root.methods_list.push((class, methods));
} else {
todo!()
}
}
Err(mut errs) => {
self.errs.append(&mut errs);
}
}
}
let (_, ctx) = self
.ctx
.rec_get_nominal_type_ctx(&mono(hir_def.sig.ident().inspect()))
.unwrap();
let type_obj = enum_unwrap!(self.ctx.rec_get_const_obj(hir_def.sig.ident().inspect()).unwrap(), ValueObj::Type:(TypeObj::Generated:(_)));
let sup_type = enum_unwrap!(&hir_def.body.block.first().unwrap(), hir::Expr::Call)
.args
.get_left_or_key("Super")
.unwrap();
check_inheritable!(self, type_obj, sup_type, &hir_def.sig);
// vi.t.non_default_params().unwrap()[0].typ().clone()
let (__new__, need_to_gen_new) = if let (Some(dunder_new_vi), Some(new_vi)) = (
ctx.get_current_scope_var("__new__"),
ctx.get_current_scope_var("new"),
) {
(dunder_new_vi.t.clone(), new_vi.kind == VarKind::Auto)
} else {
todo!()
};
let require_or_sup = self.get_require_or_sup(hir_def.body.block.remove(0));
Ok(hir::ClassDef::new(
type_obj.kind,
hir_def.sig,
require_or_sup,
need_to_gen_new,
__new__,
private_methods,
public_methods,
))
}
fn check_override(&mut self, class: &Type, ctx: &Context) {
if let Some(sups) = self.ctx.rec_get_nominal_super_type_ctxs(class) {
for (sup_t, sup) in sups.skip(1) {
for (method_name, vi) in ctx.locals.iter() {
if let Some(_sup_vi) = sup.get_current_scope_var(&method_name.inspect()) {
// must `@Override`
if let Some(decos) = &vi.comptime_decos {
if decos.contains("Override") {
continue;
}
}
self.errs.push(LowerError::override_error(
line!() as usize,
method_name.inspect(),
method_name.loc(),
sup_t,
ctx.caused_by(),
));
}
}
}
}
}
fn get_require_or_sup(&self, expr: hir::Expr) -> hir::Expr {
match expr {
acc @ hir::Expr::Accessor(_) => acc,
hir::Expr::Call(mut call) => match call.obj.show_acc().as_ref().map(|s| &s[..]) {
Some("Class") => call.args.remove_left_or_key("Requirement").unwrap(),
Some("Inherit") => call.args.remove_left_or_key("Super").unwrap(),
Some("Inheritable") => {
self.get_require_or_sup(call.args.remove_left_or_key("Class").unwrap())
}
_ => todo!(),
},
other => todo!("{other}"),
}
}
// Call.obj == Accessor cannot be type inferred by itself (it can only be inferred with arguments) // Call.obj == Accessor cannot be type inferred by itself (it can only be inferred with arguments)
// so turn off type checking (check=false) // so turn off type checking (check=false)
fn lower_expr(&mut self, expr: ast::Expr) -> LowerResult<hir::Expr> { fn lower_expr(&mut self, expr: ast::Expr) -> LowerResult<hir::Expr> {
@ -528,8 +755,10 @@ impl ASTLowerer {
ast::Expr::BinOp(bin) => Ok(hir::Expr::BinOp(self.lower_bin(bin)?)), ast::Expr::BinOp(bin) => Ok(hir::Expr::BinOp(self.lower_bin(bin)?)),
ast::Expr::UnaryOp(unary) => Ok(hir::Expr::UnaryOp(self.lower_unary(unary)?)), ast::Expr::UnaryOp(unary) => Ok(hir::Expr::UnaryOp(self.lower_unary(unary)?)),
ast::Expr::Call(call) => Ok(hir::Expr::Call(self.lower_call(call)?)), ast::Expr::Call(call) => Ok(hir::Expr::Call(self.lower_call(call)?)),
ast::Expr::DataPack(pack) => Ok(hir::Expr::Call(self.lower_pack(pack)?)),
ast::Expr::Lambda(lambda) => Ok(hir::Expr::Lambda(self.lower_lambda(lambda)?)), ast::Expr::Lambda(lambda) => Ok(hir::Expr::Lambda(self.lower_lambda(lambda)?)),
ast::Expr::Def(def) => Ok(hir::Expr::Def(self.lower_def(def)?)), ast::Expr::Def(def) => Ok(hir::Expr::Def(self.lower_def(def)?)),
ast::Expr::ClassDef(defs) => Ok(hir::Expr::ClassDef(self.lower_class_def(defs)?)),
other => todo!("{other}"), other => todo!("{other}"),
} }
} }
@ -548,7 +777,7 @@ impl ASTLowerer {
log!(info "the AST lowering process has started."); log!(info "the AST lowering process has started.");
log!(info "the type-checking process has started."); log!(info "the type-checking process has started.");
let mut module = hir::Module::with_capacity(ast.module.len()); let mut module = hir::Module::with_capacity(ast.module.len());
self.ctx.preregister(ast.module.ref_payload())?; self.ctx.preregister(ast.module.block())?;
for expr in ast.module.into_iter() { for expr in ast.module.into_iter() {
match self.lower_expr(expr).and_then(|e| self.use_check(e, mode)) { match self.lower_expr(expr).and_then(|e| self.use_check(e, mode)) {
Ok(expr) => { Ok(expr) => {

View file

@ -99,11 +99,12 @@ impl OwnershipChecker {
// TODO: referenced // TODO: referenced
Expr::Call(call) => { Expr::Call(call) => {
let args_owns = call.signature_t().unwrap().args_ownership(); let args_owns = call.signature_t().unwrap().args_ownership();
if let Some(ownership) = args_owns.self_ { let non_defaults_len = if call.method_name.is_some() {
self.check_expr(&call.obj, ownership); args_owns.non_defaults.len() - 1
} } else {
let (non_default_args, var_args) = args_owns.non_defaults.len()
call.args.pos_args.split_at(args_owns.non_defaults.len()); };
let (non_default_args, var_args) = call.args.pos_args.split_at(non_defaults_len);
for (nd_arg, ownership) in for (nd_arg, ownership) in
non_default_args.iter().zip(args_owns.non_defaults.iter()) non_default_args.iter().zip(args_owns.non_defaults.iter())
{ {
@ -185,26 +186,15 @@ impl OwnershipChecker {
fn check_acc(&mut self, acc: &Accessor, ownership: Ownership) { fn check_acc(&mut self, acc: &Accessor, ownership: Ownership) {
match acc { match acc {
Accessor::Local(local) => { Accessor::Ident(ident) => {
self.check_if_dropped(local.inspect(), local.loc()); self.check_if_dropped(ident.inspect(), ident.loc());
if acc.ref_t().is_mut() && ownership.is_owned() { if acc.ref_t().is_mut() && ownership.is_owned() {
log!( log!(
"drop: {} (in {})", "drop: {} (in {})",
local.inspect(), ident.inspect(),
local.ln_begin().unwrap_or(0) ident.ln_begin().unwrap_or(0)
); );
self.drop(local.inspect(), acc.loc()); self.drop(ident.inspect(), acc.loc());
}
}
Accessor::Public(public) => {
self.check_if_dropped(public.inspect(), public.loc());
if acc.ref_t().is_mut() && ownership.is_owned() {
log!(
"drop: {} (in {})",
public.inspect(),
public.ln_begin().unwrap_or(0)
);
self.drop(public.inspect(), acc.loc());
} }
} }
Accessor::Attr(attr) => { Accessor::Attr(attr) => {

View file

@ -17,14 +17,14 @@ fn test_instantiation_and_generalization() -> Result<(), ()> {
/* /*
#[test] #[test]
fn test_resolve_trait() -> Result<(), ()> { fn test_resolve_trait() -> Result<(), ()> {
let context = Context::new_root_module(); let context = Context::new_main_module();
context.test_resolve_trait()?; context.test_resolve_trait()?;
Ok(()) Ok(())
} }
#[test] #[test]
fn test_resolve_trait_inner1() -> Result<(), ()> { fn test_resolve_trait_inner1() -> Result<(), ()> {
let context = Context::new_root_module(); let context = Context::new_main_module();
context.test_resolve_trait_inner1()?; context.test_resolve_trait_inner1()?;
Ok(()) Ok(())
} }

View file

@ -1,6 +1,8 @@
use std::fmt; use std::fmt;
use erg_common::set::Set;
use erg_common::vis::Visibility; use erg_common::vis::Visibility;
use erg_common::Str;
use Visibility::*; use Visibility::*;
use erg_parser::ast::DefId; use erg_parser::ast::DefId;
@ -59,12 +61,14 @@ impl ParamIdx {
pub enum VarKind { pub enum VarKind {
Defined(DefId), Defined(DefId),
Declared, Declared,
// TODO: flatten
Parameter { Parameter {
def_id: DefId, def_id: DefId,
idx: ParamIdx, idx: ParamIdx,
default: DefaultInfo, default: DefaultInfo,
}, },
Generated, Auto,
FixedAuto,
DoesNotExist, DoesNotExist,
Builtin, Builtin,
} }
@ -108,6 +112,7 @@ pub struct VarInfo {
pub muty: Mutability, pub muty: Mutability,
pub vis: Visibility, pub vis: Visibility,
pub kind: VarKind, pub kind: VarKind,
pub comptime_decos: Option<Set<Str>>,
} }
impl fmt::Display for VarInfo { impl fmt::Display for VarInfo {
@ -140,11 +145,28 @@ impl HasType for VarInfo {
} }
impl VarInfo { impl VarInfo {
pub const ILLEGAL: &'static Self = pub const ILLEGAL: &'static Self = &VarInfo::new(
&VarInfo::new(Type::Failure, Immutable, Private, VarKind::DoesNotExist); Type::Failure,
Immutable,
Private,
VarKind::DoesNotExist,
None,
);
pub const fn new(t: Type, muty: Mutability, vis: Visibility, kind: VarKind) -> Self { pub const fn new(
Self { t, muty, vis, kind } t: Type,
muty: Mutability,
vis: Visibility,
kind: VarKind,
comptime_decos: Option<Set<Str>>,
) -> Self {
Self {
t,
muty,
vis,
kind,
comptime_decos,
}
} }
pub fn same_id_as(&self, id: DefId) -> bool { pub fn same_id_as(&self, id: DefId) -> bool {

View file

@ -1,6 +1,6 @@
[package] [package]
name = "erg_parser" name = "erg_parser"
version = "0.3.2" version = "0.4.0-beta.1"
description = "The Erg parser" description = "The Erg parser"
authors = ["mtshiba <sbym1346@gmail.com>"] authors = ["mtshiba <sbym1346@gmail.com>"]
license = "MIT OR Apache-2.0" license = "MIT OR Apache-2.0"
@ -16,7 +16,7 @@ simplified_chinese = [ "erg_common/simplified_chinese" ]
traditional_chinese = [ "erg_common/traditional_chinese" ] traditional_chinese = [ "erg_common/traditional_chinese" ]
[dependencies] [dependencies]
erg_common = { version = "0.3.2", path = "../erg_common" } erg_common = { version = "0.4.0-beta.1", path = "../erg_common" }
[lib] [lib]
path = "lib.rs" path = "lib.rs"

View file

@ -6,15 +6,13 @@ use erg_common::error::Location;
use erg_common::set::Set as HashSet; use erg_common::set::Set as HashSet;
use erg_common::traits::{Locational, NestedDisplay, Stream}; use erg_common::traits::{Locational, NestedDisplay, Stream};
use erg_common::vis::{Field, Visibility}; use erg_common::vis::{Field, Visibility};
// use erg_common::ty::SubrKind;
// use erg_common::value::{Field, ValueObj, Visibility};
use erg_common::Str;
use erg_common::{ 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,
}; };
use erg_common::{fmt_vec_split_with, Str};
use crate::token::{Token, TokenKind}; use crate::token::{Token, TokenKind};
@ -228,107 +226,26 @@ impl Args {
} }
} }
/// represents a local (private) variable
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct Local {
pub symbol: Token,
}
impl NestedDisplay for Local {
fn fmt_nest(&self, f: &mut std::fmt::Formatter<'_>, _level: usize) -> std::fmt::Result {
write!(f, "{}", self.symbol.content)
}
}
impl_display_from_nested!(Local);
impl_locational!(Local, symbol);
impl Local {
pub const fn new(symbol: Token) -> Self {
Self { symbol }
}
pub fn static_dummy(name: &'static str) -> Self {
Self::new(Token::static_symbol(name))
}
pub fn dummy(name: &str) -> Self {
Self::new(Token::symbol(name))
}
pub fn dummy_with_line(name: &str, line: usize) -> Self {
Self::new(Token::new(TokenKind::Symbol, Str::rc(name), line, 0))
}
// &strにするとクローンしたいときにアロケーションコストがかかるので&Strのままで
pub const fn inspect(&self) -> &Str {
&self.symbol.content
}
pub fn is_const(&self) -> bool {
self.symbol.inspect().chars().next().unwrap().is_uppercase()
}
}
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct Public {
pub dot: Token,
pub symbol: Token,
}
impl NestedDisplay for Public {
fn fmt_nest(&self, f: &mut std::fmt::Formatter<'_>, _level: usize) -> std::fmt::Result {
write!(f, ".{}", self.symbol.content)
}
}
impl_display_from_nested!(Public);
impl_locational!(Public, dot, symbol);
impl Public {
pub const fn new(dot: Token, symbol: Token) -> Self {
Self { dot, symbol }
}
pub fn dummy(name: &'static str) -> Self {
Self::new(
Token::from_str(TokenKind::Dot, "."),
Token::from_str(TokenKind::Symbol, name),
)
}
// &strにするとクローンしたいときにアロケーションコストがかかるので&Strのままで
pub const fn inspect(&self) -> &Str {
&self.symbol.content
}
pub fn is_const(&self) -> bool {
self.symbol.inspect().chars().next().unwrap().is_uppercase()
}
}
#[derive(Clone, Debug, PartialEq, Eq, Hash)] #[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct Attribute { pub struct Attribute {
pub obj: Box<Expr>, pub obj: Box<Expr>,
pub vis: Token, pub ident: Identifier,
pub name: Local,
} }
impl NestedDisplay for Attribute { impl NestedDisplay for Attribute {
fn fmt_nest(&self, f: &mut std::fmt::Formatter<'_>, _level: usize) -> std::fmt::Result { fn fmt_nest(&self, f: &mut std::fmt::Formatter<'_>, _level: usize) -> std::fmt::Result {
write!(f, "({}){}{}", self.obj, self.vis.inspect(), self.name) write!(f, "({}){}", self.obj, self.ident)
} }
} }
impl_display_from_nested!(Attribute); impl_display_from_nested!(Attribute);
impl_locational!(Attribute, obj, name); impl_locational!(Attribute, obj, ident);
impl Attribute { impl Attribute {
pub fn new(obj: Expr, vis: Token, name: Local) -> Self { pub fn new(obj: Expr, ident: Identifier) -> Self {
Self { Self {
obj: Box::new(obj), obj: Box::new(obj),
vis, ident,
name,
} }
} }
} }
@ -384,28 +301,27 @@ impl Subscript {
#[derive(Clone, Debug, PartialEq, Eq, Hash)] #[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub enum Accessor { pub enum Accessor {
Local(Local), Ident(Identifier),
Public(Public),
Attr(Attribute), Attr(Attribute),
TupleAttr(TupleAttribute), TupleAttr(TupleAttribute),
Subscr(Subscript), Subscr(Subscript),
} }
impl_nested_display_for_enum!(Accessor; Local, Public, Attr, TupleAttr, Subscr); impl_nested_display_for_enum!(Accessor; Ident, Attr, TupleAttr, Subscr);
impl_display_from_nested!(Accessor); impl_display_from_nested!(Accessor);
impl_locational_for_enum!(Accessor; Local, Public, Attr, TupleAttr, Subscr); impl_locational_for_enum!(Accessor; Ident Attr, TupleAttr, Subscr);
impl Accessor { impl Accessor {
pub const fn local(symbol: Token) -> Self { pub const fn local(symbol: Token) -> Self {
Self::Local(Local::new(symbol)) Self::Ident(Identifier::new(None, VarName::new(symbol)))
} }
pub const fn public(dot: Token, symbol: Token) -> Self { pub const fn public(dot: Token, symbol: Token) -> Self {
Self::Public(Public::new(dot, symbol)) Self::Ident(Identifier::new(Some(dot), VarName::new(symbol)))
} }
pub fn attr(obj: Expr, vis: Token, name: Local) -> Self { pub fn attr(obj: Expr, ident: Identifier) -> Self {
Self::Attr(Attribute::new(obj, vis, name)) Self::Attr(Attribute::new(obj, ident))
} }
pub fn tuple_attr(obj: Expr, index: Literal) -> Self { pub fn tuple_attr(obj: Expr, index: Literal) -> Self {
@ -418,19 +334,17 @@ impl Accessor {
pub const fn name(&self) -> Option<&Str> { pub const fn name(&self) -> Option<&Str> {
match self { match self {
Self::Local(local) => Some(local.inspect()), Self::Ident(ident) => Some(ident.inspect()),
Self::Public(local) => Some(local.inspect()),
_ => None, _ => None,
} }
} }
pub fn is_const(&self) -> bool { pub fn is_const(&self) -> bool {
match self { match self {
Self::Local(local) => local.is_const(), Self::Ident(ident) => ident.is_const(),
Self::Public(public) => public.is_const(),
Self::Subscr(subscr) => subscr.obj.is_const_acc(), Self::Subscr(subscr) => subscr.obj.is_const_acc(),
Self::TupleAttr(attr) => attr.obj.is_const_acc(), Self::TupleAttr(attr) => attr.obj.is_const_acc(),
Self::Attr(attr) => attr.obj.is_const_acc() && attr.name.is_const(), Self::Attr(attr) => attr.obj.is_const_acc() && attr.ident.is_const(),
} }
} }
} }
@ -496,7 +410,7 @@ pub struct ArrayComprehension {
pub l_sqbr: Token, pub l_sqbr: Token,
pub r_sqbr: Token, pub r_sqbr: Token,
pub elem: Box<Expr>, pub elem: Box<Expr>,
pub generators: Vec<(Local, Expr)>, pub generators: Vec<(Identifier, Expr)>,
pub guards: Vec<Expr>, pub guards: Vec<Expr>,
} }
@ -524,7 +438,7 @@ impl ArrayComprehension {
l_sqbr: Token, l_sqbr: Token,
r_sqbr: Token, r_sqbr: Token,
elem: Expr, elem: Expr,
generators: Vec<(Local, Expr)>, generators: Vec<(Identifier, Expr)>,
guards: Vec<Expr>, guards: Vec<Expr>,
) -> Self { ) -> Self {
Self { Self {
@ -675,10 +589,18 @@ impl From<Vec<Def>> for RecordAttrs {
} }
impl RecordAttrs { impl RecordAttrs {
pub const fn new(attrs: Vec<Def>) -> Self {
Self(attrs)
}
pub fn iter(&self) -> impl Iterator<Item = &Def> { pub fn iter(&self) -> impl Iterator<Item = &Def> {
self.0.iter() self.0.iter()
} }
pub fn iter_mut(&mut self) -> impl Iterator<Item = &mut Def> {
self.0.iter_mut()
}
pub fn into_iter(self) -> impl IntoIterator<Item = Def> { pub fn into_iter(self) -> impl IntoIterator<Item = Def> {
self.0.into_iter() self.0.into_iter()
} }
@ -714,12 +636,45 @@ impl NormalRecord {
/// e.g. {x; y; z} (syntax sugar of {x = x; y = y; z = z}) /// e.g. {x; y; z} (syntax sugar of {x = x; y = y; z = z})
#[derive(Clone, Debug, PartialEq, Eq, Hash)] #[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct SimpleRecord { pub struct ShortenedRecord {
pub l_brace: Token, pub l_brace: Token,
pub r_brace: Token, pub r_brace: Token,
idents: Vec<Identifier>, pub idents: Vec<Identifier>,
} }
impl NestedDisplay for ShortenedRecord {
fn fmt_nest(&self, f: &mut fmt::Formatter<'_>, _level: usize) -> fmt::Result {
write!(f, "{{")?;
for ident in self.idents.iter() {
write!(f, "{}; ", ident)?;
}
write!(f, "}}")
}
}
impl_display_from_nested!(ShortenedRecord);
impl_locational!(ShortenedRecord, l_brace, r_brace);
impl ShortenedRecord {
pub const fn new(l_brace: Token, r_brace: Token, idents: Vec<Identifier>) -> Self {
Self {
l_brace,
r_brace,
idents,
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum Record {
Normal(NormalRecord),
Shortened(ShortenedRecord),
}
impl_nested_display_for_enum!(Record; Normal, Shortened);
impl_display_for_enum!(Record; Normal, Shortened);
impl_locational_for_enum!(Record; Normal, Shortened);
#[derive(Clone, Debug, PartialEq, Eq, Hash)] #[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct NormalSet { pub struct NormalSet {
l_brace: Token, l_brace: Token,
@ -821,7 +776,7 @@ impl UnaryOp {
#[derive(Clone, Debug, PartialEq, Eq, Hash)] #[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct Call { pub struct Call {
pub obj: Box<Expr>, pub obj: Box<Expr>,
pub method_name: Option<Token>, pub method_name: Option<Identifier>,
pub args: Args, pub args: Args,
} }
@ -829,7 +784,7 @@ impl NestedDisplay for Call {
fn fmt_nest(&self, f: &mut std::fmt::Formatter<'_>, level: usize) -> std::fmt::Result { fn fmt_nest(&self, f: &mut std::fmt::Formatter<'_>, level: usize) -> std::fmt::Result {
write!(f, "({})", self.obj)?; write!(f, "({})", self.obj)?;
if let Some(method_name) = self.method_name.as_ref() { if let Some(method_name) = self.method_name.as_ref() {
write!(f, ".{}", method_name.content)?; write!(f, "{}", method_name)?;
} }
writeln!(f, ":")?; writeln!(f, ":")?;
self.args.fmt_nest(f, level + 1) self.args.fmt_nest(f, level + 1)
@ -849,7 +804,7 @@ impl Locational for Call {
} }
impl Call { impl Call {
pub fn new(obj: Expr, method_name: Option<Token>, args: Args) -> Self { pub fn new(obj: Expr, method_name: Option<Identifier>, args: Args) -> Self {
Self { Self {
obj: Box::new(obj), obj: Box::new(obj),
method_name, method_name,
@ -858,6 +813,38 @@ impl Call {
} }
} }
/// e.g. `Data::{x = 1; y = 2}`
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct DataPack {
pub class: Box<Expr>,
pub connector: Token,
pub args: Record,
}
impl NestedDisplay for DataPack {
fn fmt_nest(&self, f: &mut std::fmt::Formatter<'_>, _level: usize) -> std::fmt::Result {
write!(f, "{}::{}", self.class, self.args)
}
}
impl_display_from_nested!(DataPack);
impl Locational for DataPack {
fn loc(&self) -> Location {
Location::concat(self.class.as_ref(), &self.args)
}
}
impl DataPack {
pub fn new(class: Expr, connector: Token, args: Record) -> Self {
Self {
class: Box::new(class),
connector,
args,
}
}
}
#[derive(Clone, Debug, PartialEq, Eq, Hash)] #[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct Block(Vec<Expr>); pub struct Block(Vec<Expr>);
@ -1412,33 +1399,13 @@ impl ParamTySpec {
} }
} }
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum SubrKindSpec {
Func,
Proc,
FuncMethod(Box<TypeSpec>),
ProcMethod {
before: Box<TypeSpec>,
after: Option<Box<TypeSpec>>,
},
}
impl SubrKindSpec {
pub const fn arrow(&self) -> Str {
match self {
Self::Func | Self::FuncMethod(_) => Str::ever("->"),
Self::Proc | Self::ProcMethod { .. } => Str::ever("=>"),
}
}
}
#[derive(Clone, Debug, PartialEq, Eq, Hash)] #[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct SubrTypeSpec { pub struct SubrTypeSpec {
pub kind: SubrKindSpec,
pub lparen: Option<Token>, pub lparen: Option<Token>,
pub non_defaults: Vec<ParamTySpec>, pub non_defaults: Vec<ParamTySpec>,
pub var_args: Option<Box<ParamTySpec>>, pub var_args: Option<Box<ParamTySpec>>,
pub defaults: Vec<ParamTySpec>, pub defaults: Vec<ParamTySpec>,
pub arrow: Token,
pub return_t: Box<TypeSpec>, pub return_t: Box<TypeSpec>,
} }
@ -1450,7 +1417,7 @@ impl fmt::Display for SubrTypeSpec {
fmt_vec(&self.non_defaults), fmt_vec(&self.non_defaults),
fmt_option!(pre "...", &self.var_args), fmt_option!(pre "...", &self.var_args),
fmt_vec(&self.defaults), fmt_vec(&self.defaults),
self.kind.arrow(), self.arrow.content,
self.return_t self.return_t
) )
} }
@ -1469,19 +1436,19 @@ impl Locational for SubrTypeSpec {
impl SubrTypeSpec { impl SubrTypeSpec {
pub fn new( pub fn new(
kind: SubrKindSpec,
lparen: Option<Token>, lparen: Option<Token>,
non_defaults: Vec<ParamTySpec>, non_defaults: Vec<ParamTySpec>,
var_args: Option<ParamTySpec>, var_args: Option<ParamTySpec>,
defaults: Vec<ParamTySpec>, defaults: Vec<ParamTySpec>,
arrow: Token,
return_t: TypeSpec, return_t: TypeSpec,
) -> Self { ) -> Self {
Self { Self {
kind,
lparen, lparen,
non_defaults, non_defaults,
var_args: var_args.map(Box::new), var_args: var_args.map(Box::new),
defaults, defaults,
arrow,
return_t: Box::new(return_t), return_t: Box::new(return_t),
} }
} }
@ -1580,40 +1547,6 @@ impl TypeSpec {
pub const fn interval(op: Token, lhs: ConstExpr, rhs: ConstExpr) -> Self { pub const fn interval(op: Token, lhs: ConstExpr, rhs: ConstExpr) -> Self {
Self::Interval { op, lhs, rhs } Self::Interval { op, lhs, rhs }
} }
pub fn func(
lparen: Option<Token>,
non_defaults: Vec<ParamTySpec>,
var_args: Option<ParamTySpec>,
defaults: Vec<ParamTySpec>,
return_t: TypeSpec,
) -> Self {
Self::Subr(SubrTypeSpec::new(
SubrKindSpec::Func,
lparen,
non_defaults,
var_args,
defaults,
return_t,
))
}
pub fn proc(
lparen: Option<Token>,
non_defaults: Vec<ParamTySpec>,
var_args: Option<ParamTySpec>,
defaults: Vec<ParamTySpec>,
return_t: TypeSpec,
) -> Self {
Self::Subr(SubrTypeSpec::new(
SubrKindSpec::Proc,
lparen,
non_defaults,
var_args,
defaults,
return_t,
))
}
} }
#[derive(Clone, Debug, PartialEq, Eq, Hash)] #[derive(Clone, Debug, PartialEq, Eq, Hash)]
@ -1657,7 +1590,7 @@ impl Locational for TypeBoundSpecs {
/// デコレータは関数を返す関数オブジェクトならば何でも指定できる /// デコレータは関数を返す関数オブジェクトならば何でも指定できる
/// e.g. @(x -> x) /// e.g. @(x -> x)
#[derive(Debug, Clone, PartialEq, Eq, Hash)] #[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct Decorator(Expr); pub struct Decorator(pub Expr);
impl Decorator { impl Decorator {
pub const fn new(expr: Expr) -> Self { pub const fn new(expr: Expr) -> Self {
@ -1760,15 +1693,17 @@ pub struct Identifier {
pub name: VarName, pub name: VarName,
} }
impl fmt::Display for Identifier { impl NestedDisplay for Identifier {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt_nest(&self, f: &mut fmt::Formatter<'_>, _level: usize) -> fmt::Result {
match &self.dot { match &self.dot {
Some(_dot) => write!(f, ".{}", self.name), Some(_dot) => write!(f, ".{}", self.name),
None => write!(f, "{}", self.name), None => write!(f, "::{}", self.name),
} }
} }
} }
impl_display_from_nested!(Identifier);
impl Locational for Identifier { impl Locational for Identifier {
fn loc(&self) -> Location { fn loc(&self) -> Location {
if let Some(dot) = &self.dot { if let Some(dot) = &self.dot {
@ -1805,13 +1740,17 @@ impl Identifier {
Self::new(None, VarName::from_str_and_line(name, line)) Self::new(None, VarName::from_str_and_line(name, line))
} }
pub fn public_with_line(dot: Token, name: Str, line: usize) -> Self {
Self::new(Some(dot), VarName::from_str_and_line(name, line))
}
pub fn is_const(&self) -> bool { pub fn is_const(&self) -> bool {
self.name.is_const() self.name.is_const()
} }
pub const fn vis(&self) -> Visibility { pub const fn vis(&self) -> Visibility {
match &self.dot { match &self.dot {
Some(_dot) => Visibility::Public, Some(_) => Visibility::Public,
None => Visibility::Private, None => Visibility::Private,
} }
} }
@ -1907,32 +1846,96 @@ impl VarTuplePattern {
} }
} }
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct VarRecordAttr {
pub lhs: Identifier,
pub rhs: VarSignature,
}
impl NestedDisplay for VarRecordAttr {
fn fmt_nest(&self, f: &mut fmt::Formatter<'_>, _level: usize) -> fmt::Result {
write!(f, "{} = {}", self.lhs, self.rhs)
}
}
impl_display_from_nested!(VarRecordAttr);
impl_locational!(VarRecordAttr, lhs, rhs);
impl VarRecordAttr {
pub const fn new(lhs: Identifier, rhs: VarSignature) -> Self {
Self { lhs, rhs }
}
}
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct VarRecordAttrs {
pub(crate) elems: Vec<VarRecordAttr>,
}
impl NestedDisplay for VarRecordAttrs {
fn fmt_nest(&self, f: &mut fmt::Formatter<'_>, _level: usize) -> fmt::Result {
write!(f, "{}", fmt_vec_split_with(&self.elems, "; "))
}
}
impl_display_from_nested!(VarRecordAttrs);
impl_stream!(VarRecordAttrs, VarRecordAttr, elems);
impl VarRecordAttrs {
pub const fn new(elems: Vec<VarRecordAttr>) -> Self {
Self { elems }
}
pub const fn empty() -> Self {
Self::new(vec![])
}
}
#[derive(Clone, Debug, PartialEq, Eq, Hash)] #[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct VarRecordPattern { pub struct VarRecordPattern {
l_brace: Token, l_brace: Token,
// TODO: レコード専用の構造体を作る pub(crate) attrs: VarRecordAttrs,
pub(crate) elems: Vars,
r_brace: Token, r_brace: Token,
} }
impl fmt::Display for VarRecordPattern { impl fmt::Display for VarRecordPattern {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{{{}}}", self.elems) write!(f, "{{{}}}", self.attrs)
} }
} }
impl_locational!(VarRecordPattern, l_brace, r_brace); impl_locational!(VarRecordPattern, l_brace, r_brace);
impl VarRecordPattern { impl VarRecordPattern {
pub const fn new(l_brace: Token, elems: Vars, r_brace: Token) -> Self { pub const fn new(l_brace: Token, attrs: VarRecordAttrs, r_brace: Token) -> Self {
Self { Self {
l_brace, l_brace,
elems, attrs,
r_brace, r_brace,
} }
} }
} }
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct VarDataPackPattern {
pub class: TypeSpec,
pub args: VarRecordPattern,
}
impl fmt::Display for VarDataPackPattern {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}::{}", self.class, self.args)
}
}
impl_locational!(VarDataPackPattern, class, args);
impl VarDataPackPattern {
pub const fn new(class: TypeSpec, args: VarRecordPattern) -> Self {
Self { class, args }
}
}
#[derive(Clone, Debug, PartialEq, Eq, Hash)] #[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub enum VarPattern { pub enum VarPattern {
Discard(Token), Discard(Token),
@ -1943,6 +1946,8 @@ pub enum VarPattern {
Tuple(VarTuplePattern), Tuple(VarTuplePattern),
// e.g. `{name; age}`, `{_; [car, cdr]}` // e.g. `{name; age}`, `{_; [car, cdr]}`
Record(VarRecordPattern), Record(VarRecordPattern),
// e.g. `Data::{x, y}`
DataPack(VarDataPackPattern),
} }
impl NestedDisplay for VarPattern { impl NestedDisplay for VarPattern {
@ -1953,12 +1958,13 @@ impl NestedDisplay for VarPattern {
Self::Array(a) => write!(f, "{}", a), Self::Array(a) => write!(f, "{}", a),
Self::Tuple(t) => write!(f, "{}", t), Self::Tuple(t) => write!(f, "{}", t),
Self::Record(r) => write!(f, "{}", r), Self::Record(r) => write!(f, "{}", r),
Self::DataPack(d) => write!(f, "{}", d),
} }
} }
} }
impl_display_from_nested!(VarPattern); impl_display_from_nested!(VarPattern);
impl_locational_for_enum!(VarPattern; Discard, Ident, Array, Tuple, Record); impl_locational_for_enum!(VarPattern; Discard, Ident, Array, Tuple, Record, DataPack);
impl VarPattern { impl VarPattern {
pub const fn inspect(&self) -> Option<&Str> { pub const fn inspect(&self) -> Option<&Str> {
@ -1968,18 +1974,6 @@ impl VarPattern {
} }
} }
pub fn inspects(&self) -> Vec<&Str> {
match self {
Self::Ident(ident) => vec![ident.inspect()],
Self::Array(VarArrayPattern { elems, .. })
| Self::Tuple(VarTuplePattern { elems, .. })
| Self::Record(VarRecordPattern { elems, .. }) => {
elems.iter().flat_map(|s| s.pat.inspects()).collect()
}
_ => vec![],
}
}
// _!(...) = ... is invalid // _!(...) = ... is invalid
pub fn is_procedural(&self) -> bool { pub fn is_procedural(&self) -> bool {
match self { match self {
@ -2052,6 +2046,13 @@ impl VarSignature {
pub const fn vis(&self) -> Visibility { pub const fn vis(&self) -> Visibility {
self.pat.vis() self.pat.vis()
} }
pub fn ident(&self) -> Option<&Identifier> {
match &self.pat {
VarPattern::Ident(ident) => Some(ident),
_ => None,
}
}
} }
#[derive(Clone, Debug, PartialEq, Eq, Hash)] #[derive(Clone, Debug, PartialEq, Eq, Hash)]
@ -2156,26 +2157,38 @@ impl ParamRecordPattern {
pub enum ParamPattern { pub enum ParamPattern {
Discard(Token), Discard(Token),
VarName(VarName), VarName(VarName),
// TODO: ConstField(), // TODO: ConstAttr(),
// e.g. `a` of `[*a, b] = [1, 2, 3]` (a == [1, 2], b == 3)
// `b` of `[a, *b] = [1, 2, 3]` (a == 1, b == [2, 3])
VarArgsName(VarName),
Lit(Literal), Lit(Literal),
Array(ParamArrayPattern), Array(ParamArrayPattern),
Tuple(ParamTuplePattern), Tuple(ParamTuplePattern),
Record(ParamRecordPattern), Record(ParamRecordPattern),
// DataPack(ParamDataPackPattern),
Ref(VarName), Ref(VarName),
RefMut(VarName), RefMut(VarName),
VarArgs(VarName),
} }
impl_display_for_enum!(ParamPattern; Discard, VarName, VarArgsName, Lit, Array, Tuple, Record, Ref, RefMut, VarArgs); impl NestedDisplay for ParamPattern {
impl_locational_for_enum!(ParamPattern; Discard, VarName, VarArgsName, Lit, Array, Tuple, Record, Ref, RefMut, VarArgs); fn fmt_nest(&self, f: &mut fmt::Formatter<'_>, _level: usize) -> fmt::Result {
match self {
Self::Discard(tok) => write!(f, "{}", tok),
Self::VarName(var_name) => write!(f, "{}", var_name),
Self::Lit(lit) => write!(f, "{}", lit),
Self::Array(array) => write!(f, "{}", array),
Self::Tuple(tuple) => write!(f, "{}", tuple),
Self::Record(record) => write!(f, "{}", record),
Self::Ref(var_name) => write!(f, "ref {}", var_name),
Self::RefMut(var_name) => write!(f, "ref! {}", var_name),
}
}
}
impl_display_from_nested!(ParamPattern);
impl_locational_for_enum!(ParamPattern; Discard, VarName, Lit, Array, Tuple, Record, Ref, RefMut);
impl ParamPattern { impl ParamPattern {
pub const fn inspect(&self) -> Option<&Str> { pub const fn inspect(&self) -> Option<&Str> {
match self { match self {
Self::VarName(n) | Self::VarArgsName(n) => Some(n.inspect()), Self::VarName(n) | Self::Ref(n) | Self::RefMut(n) => Some(n.inspect()),
_ => None, _ => None,
} }
} }
@ -2187,7 +2200,7 @@ impl ParamPattern {
pub fn is_procedural(&self) -> bool { pub fn is_procedural(&self) -> bool {
match self { match self {
Self::Discard(_) => true, Self::Discard(_) => true,
Self::VarName(n) | Self::VarArgsName(n) => n.is_procedural(), Self::VarName(n) | Self::Ref(n) | Self::RefMut(n) => n.is_procedural(),
_ => false, _ => false,
} }
} }
@ -2195,7 +2208,7 @@ impl ParamPattern {
pub fn is_const(&self) -> bool { pub fn is_const(&self) -> bool {
match self { match self {
Self::Discard(_) => true, Self::Discard(_) => true,
Self::VarName(n) | Self::VarArgsName(n) => n.is_const(), Self::VarName(n) | Self::Ref(n) | Self::RefMut(n) => n.is_const(),
_ => false, _ => false,
} }
} }
@ -2289,7 +2302,11 @@ impl Locational for Params {
} else if !self.non_defaults.is_empty() { } else if !self.non_defaults.is_empty() {
Location::concat(&self.non_defaults[0], self.non_defaults.last().unwrap()) Location::concat(&self.non_defaults[0], self.non_defaults.last().unwrap())
} else if let Some(var_args) = &self.var_args { } else if let Some(var_args) = &self.var_args {
Location::concat(var_args.as_ref(), self.defaults.last().unwrap()) if !self.defaults.is_empty() {
Location::concat(var_args.as_ref(), self.defaults.last().unwrap())
} else {
var_args.loc()
}
} else if !self.defaults.is_empty() { } else if !self.defaults.is_empty() {
Location::concat(&self.defaults[0], self.defaults.last().unwrap()) Location::concat(&self.defaults[0], self.defaults.last().unwrap())
} else { } else {
@ -2540,6 +2557,19 @@ impl Signature {
} }
} }
pub fn ident_mut(&mut self) -> Option<&mut Identifier> {
match self {
Self::Var(var) => {
if let VarPattern::Ident(ident) = &mut var.pat {
Some(ident)
} else {
None
}
}
Self::Subr(subr) => Some(&mut subr.ident),
}
}
pub fn t_spec(&self) -> Option<&TypeSpec> { pub fn t_spec(&self) -> Option<&TypeSpec> {
match self { match self {
Self::Var(v) => v.t_spec.as_ref(), Self::Var(v) => v.t_spec.as_ref(),
@ -2610,7 +2640,8 @@ pub struct Def {
impl NestedDisplay for Def { impl NestedDisplay for Def {
fn fmt_nest(&self, f: &mut fmt::Formatter<'_>, level: usize) -> fmt::Result { fn fmt_nest(&self, f: &mut fmt::Formatter<'_>, level: usize) -> fmt::Result {
writeln!(f, "{} {}", self.sig, self.body.op.content)?; self.sig.fmt_nest(f, level)?;
writeln!(f, " {}", self.body.op.content)?;
self.body.block.fmt_nest(f, level + 1) self.body.block.fmt_nest(f, level + 1)
} }
} }
@ -2640,28 +2671,58 @@ impl Def {
/// f(a) = ... /// f(a) = ...
/// ``` /// ```
#[derive(Debug, Clone, PartialEq, Eq, Hash)] #[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct MethodDefs { pub struct Methods {
pub class: TypeSpec, pub class: TypeSpec,
pub vis: Token, // `.` or `::` pub vis: Token, // `.` or `::`
pub defs: RecordAttrs, // TODO: allow declaration pub defs: RecordAttrs, // TODO: allow declaration
} }
impl NestedDisplay for MethodDefs { impl NestedDisplay for Methods {
fn fmt_nest(&self, f: &mut fmt::Formatter<'_>, level: usize) -> fmt::Result { fn fmt_nest(&self, f: &mut fmt::Formatter<'_>, level: usize) -> fmt::Result {
writeln!(f, "{}{}", self.class, self.vis)?; writeln!(f, "{}{}", self.class, self.vis.content)?;
self.defs.fmt_nest(f, level + 1) self.defs.fmt_nest(f, level + 1)
} }
} }
impl_display_from_nested!(MethodDefs); impl_display_from_nested!(Methods);
impl_locational!(MethodDefs, class, defs); impl_locational!(Methods, class, defs);
impl MethodDefs { impl Methods {
pub const fn new(class: TypeSpec, vis: Token, defs: RecordAttrs) -> Self { pub const fn new(class: TypeSpec, vis: Token, defs: RecordAttrs) -> Self {
Self { class, vis, defs } Self { class, vis, defs }
} }
} }
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct ClassDef {
pub def: Def,
pub methods_list: Vec<Methods>,
}
impl NestedDisplay for ClassDef {
fn fmt_nest(&self, f: &mut fmt::Formatter<'_>, level: usize) -> fmt::Result {
write!(f, "(class)")?;
self.def.fmt_nest(f, level)?;
for methods in self.methods_list.iter() {
write!(f, "(methods)")?;
methods.fmt_nest(f, level + 1)?;
}
Ok(())
}
}
impl_display_from_nested!(ClassDef);
impl_locational!(ClassDef, def);
impl ClassDef {
pub const fn new(def: Def, methods: Vec<Methods>) -> Self {
Self {
def,
methods_list: methods,
}
}
}
/// Expression(式) /// Expression(式)
#[derive(Debug, Clone, PartialEq, Eq, Hash)] #[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum Expr { pub enum Expr {
@ -2671,19 +2732,21 @@ pub enum Expr {
Tuple(Tuple), Tuple(Tuple),
Dict(Dict), Dict(Dict),
Set(Set), Set(Set),
Record(NormalRecord), Record(Record),
BinOp(BinOp), BinOp(BinOp),
UnaryOp(UnaryOp), UnaryOp(UnaryOp),
Call(Call), Call(Call),
DataPack(DataPack),
Lambda(Lambda), Lambda(Lambda),
TypeAsc(TypeAscription), TypeAsc(TypeAscription),
Def(Def), Def(Def),
MethodDefs(MethodDefs), Methods(Methods),
ClassDef(ClassDef),
} }
impl_nested_display_for_chunk_enum!(Expr; Lit, Accessor, Array, Tuple, Dict, Set, Record, BinOp, UnaryOp, Call, Lambda, TypeAsc, Def, MethodDefs); impl_nested_display_for_chunk_enum!(Expr; Lit, Accessor, Array, Tuple, Dict, Set, Record, BinOp, UnaryOp, Call, DataPack, Lambda, TypeAsc, Def, Methods, ClassDef);
impl_display_from_nested!(Expr); impl_display_from_nested!(Expr);
impl_locational_for_enum!(Expr; Lit, Accessor, Array, Tuple, Dict, Set, Record, BinOp, UnaryOp, Call, Lambda, TypeAsc, Def, MethodDefs); impl_locational_for_enum!(Expr; Lit, Accessor, Array, Tuple, Dict, Set, Record, BinOp, UnaryOp, Call, DataPack, Lambda, TypeAsc, Def, Methods, ClassDef);
impl Expr { impl Expr {
pub fn is_match_call(&self) -> bool { pub fn is_match_call(&self) -> bool {
@ -2720,7 +2783,7 @@ impl Expr {
} }
#[derive(Clone, Debug, PartialEq, Eq, Hash)] #[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct Module(Vec<Expr>); pub struct Module(Block);
impl fmt::Display for Module { impl fmt::Display for Module {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
@ -2734,7 +2797,34 @@ impl Locational for Module {
} }
} }
impl_stream_for_wrapper!(Module, Expr); impl Stream<Expr> for Module {
fn payload(self) -> Vec<Expr> {
self.0.payload()
}
fn ref_payload(&self) -> &Vec<Expr> {
self.0.ref_payload()
}
fn ref_mut_payload(&mut self) -> &mut Vec<Expr> {
self.0.ref_mut_payload()
}
}
impl Module {
pub const fn empty() -> Self {
Self(Block::empty())
}
pub const fn new(payload: Vec<Expr>) -> Self {
Self(Block::new(payload))
}
#[inline]
pub fn with_capacity(capacity: usize) -> Self {
Self(Block::with_capacity(capacity))
}
pub fn block(&self) -> &Block {
&self.0
}
}
#[derive(Debug)] #[derive(Debug)]
pub struct AST { pub struct AST {

View file

@ -11,17 +11,19 @@ use erg_common::Str;
use erg_common::{enum_unwrap, get_hash, set}; use erg_common::{enum_unwrap, get_hash, set};
use crate::ast::{ use crate::ast::{
Accessor, Args, Block, Call, Def, DefBody, DefId, Expr, Identifier, Lambda, LambdaSignature, Accessor, Args, Array, BinOp, Block, Call, DataPack, Def, DefBody, DefId, Expr, Identifier,
Literal, Local, Module, ParamPattern, ParamSignature, Params, PosArg, Signature, SubrSignature, KwArg, Lambda, LambdaSignature, Literal, Methods, Module, NormalArray, NormalRecord,
TypeBoundSpecs, TypeSpec, VarName, VarPattern, VarSignature, NormalTuple, ParamPattern, ParamSignature, Params, PosArg, Record, RecordAttrs,
ShortenedRecord, Signature, SubrSignature, Tuple, TypeAscription, TypeBoundSpecs, TypeSpec,
UnaryOp, VarName, VarPattern, VarRecordAttr, VarSignature,
}; };
use crate::token::{Token, TokenKind}; use crate::token::{Token, TokenKind};
#[derive(Debug, Clone, PartialEq, Eq)] #[derive(Debug, Clone, PartialEq, Eq)]
enum BufIndex<'s> { enum BufIndex<'i> {
Array(usize), Array(usize),
Tuple(usize), Tuple(usize),
Record(&'s str), Record(&'i Identifier),
} }
#[derive(Debug)] #[derive(Debug)]
@ -46,7 +48,10 @@ impl Desugarer {
pub fn desugar(&mut self, module: Module) -> Module { pub fn desugar(&mut self, module: Module) -> Module {
let module = self.desugar_multiple_pattern_def(module); let module = self.desugar_multiple_pattern_def(module);
self.desugar_pattern(module) let module = self.desugar_pattern(module);
let module = self.desugar_shortened_record(module);
// let module = self.desugar_self(module);
module
} }
fn desugar_ubar_lambda(&self, _module: Module) -> Module { fn desugar_ubar_lambda(&self, _module: Module) -> Module {
@ -74,7 +79,7 @@ impl Desugarer {
} else { } else {
self.gen_match_call(previous, def) self.gen_match_call(previous, def)
}; };
let param_name = enum_unwrap!(&call.args.pos_args().iter().next().unwrap().expr, Expr::Accessor:(Accessor::Local:(_))).inspect(); let param_name = enum_unwrap!(&call.args.pos_args().iter().next().unwrap().expr, Expr::Accessor:(Accessor::Ident:(_))).inspect();
// FIXME: multiple params // FIXME: multiple params
let param = VarName::new(Token::new( let param = VarName::new(Token::new(
TokenKind::Symbol, TokenKind::Symbol,
@ -160,6 +165,19 @@ impl Desugarer {
todo!() todo!()
} }
fn gen_buf_name_and_sig(
&mut self,
line: usize,
t_spec: Option<TypeSpec>,
) -> (String, Signature) {
let buf_name = self.fresh_var_name();
let buf_sig = Signature::Var(VarSignature::new(
VarPattern::Ident(Identifier::private_with_line(Str::rc(&buf_name), line)),
t_spec,
));
(buf_name, buf_sig)
}
/// `[i, j] = [1, 2]` -> `i = 1; j = 2` /// `[i, j] = [1, 2]` -> `i = 1; j = 2`
/// `[i, j] = l` -> `i = l[0]; j = l[1]` /// `[i, j] = l` -> `i = l[0]; j = l[1]`
/// `[i, [j, k]] = l` -> `i = l[0]; j = l[1][0]; k = l[1][1]` /// `[i, [j, k]] = l` -> `i = l[0]; j = l[1][0]; k = l[1][1]`
@ -174,14 +192,8 @@ impl Desugarer {
body, body,
}) => match &v.pat { }) => match &v.pat {
VarPattern::Tuple(tup) => { VarPattern::Tuple(tup) => {
let buf_name = self.fresh_var_name(); let (buf_name, buf_sig) =
let buf_sig = Signature::Var(VarSignature::new( self.gen_buf_name_and_sig(v.ln_begin().unwrap(), v.t_spec);
VarPattern::Ident(Identifier::private_with_line(
Str::rc(&buf_name),
v.ln_begin().unwrap(),
)),
v.t_spec,
));
let buf_def = Def::new(buf_sig, body); let buf_def = Def::new(buf_sig, body);
new.push(Expr::Def(buf_def)); new.push(Expr::Def(buf_def));
for (n, elem) in tup.elems.iter().enumerate() { for (n, elem) in tup.elems.iter().enumerate() {
@ -194,14 +206,8 @@ impl Desugarer {
} }
} }
VarPattern::Array(arr) => { VarPattern::Array(arr) => {
let buf_name = self.fresh_var_name(); let (buf_name, buf_sig) =
let buf_sig = Signature::Var(VarSignature::new( self.gen_buf_name_and_sig(v.ln_begin().unwrap(), v.t_spec);
VarPattern::Ident(Identifier::private_with_line(
Str::rc(&buf_name),
v.ln_begin().unwrap(),
)),
v.t_spec,
));
let buf_def = Def::new(buf_sig, body); let buf_def = Def::new(buf_sig, body);
new.push(Expr::Def(buf_def)); new.push(Expr::Def(buf_def));
for (n, elem) in arr.elems.iter().enumerate() { for (n, elem) in arr.elems.iter().enumerate() {
@ -213,7 +219,36 @@ impl Desugarer {
); );
} }
} }
VarPattern::Record(_rec) => todo!(), VarPattern::Record(rec) => {
let (buf_name, buf_sig) =
self.gen_buf_name_and_sig(v.ln_begin().unwrap(), v.t_spec);
let buf_def = Def::new(buf_sig, body);
new.push(Expr::Def(buf_def));
for VarRecordAttr { lhs, rhs } in rec.attrs.iter() {
self.desugar_nested_var_pattern(
&mut new,
rhs,
&buf_name,
BufIndex::Record(lhs),
);
}
}
VarPattern::DataPack(pack) => {
let (buf_name, buf_sig) = self.gen_buf_name_and_sig(
v.ln_begin().unwrap(),
Some(pack.class.clone()), // TODO: これだとvの型指定の意味がなくなる
);
let buf_def = Def::new(buf_sig, body);
new.push(Expr::Def(buf_def));
for VarRecordAttr { lhs, rhs } in pack.args.attrs.iter() {
self.desugar_nested_var_pattern(
&mut new,
rhs,
&buf_name,
BufIndex::Record(lhs),
);
}
}
VarPattern::Ident(_i) => { VarPattern::Ident(_i) => {
let def = Def::new(Signature::Var(v), body); let def = Def::new(Signature::Var(v), body);
new.push(Expr::Def(def)); new.push(Expr::Def(def));
@ -243,14 +278,7 @@ impl Desugarer {
BufIndex::Array(n) => { BufIndex::Array(n) => {
Accessor::subscr(obj, Expr::Lit(Literal::nat(n, sig.ln_begin().unwrap()))) Accessor::subscr(obj, Expr::Lit(Literal::nat(n, sig.ln_begin().unwrap())))
} }
BufIndex::Record(attr) => { BufIndex::Record(attr) => Accessor::attr(obj, attr.clone()),
// TODO: visibility
Accessor::attr(
obj,
Token::from_str(TokenKind::Dot, "."),
Local::dummy_with_line(attr, sig.ln_begin().unwrap()),
)
}
}; };
let id = DefId(get_hash(&(&acc, buf_name))); let id = DefId(get_hash(&(&acc, buf_name)));
let block = Block::new(vec![Expr::Accessor(acc)]); let block = Block::new(vec![Expr::Accessor(acc)]);
@ -258,14 +286,7 @@ impl Desugarer {
let body = DefBody::new(op, block, id); let body = DefBody::new(op, block, id);
match &sig.pat { match &sig.pat {
VarPattern::Tuple(tup) => { VarPattern::Tuple(tup) => {
let buf_name = self.fresh_var_name(); let (buf_name, buf_sig) = self.gen_buf_name_and_sig(sig.ln_begin().unwrap(), None);
let buf_sig = Signature::Var(VarSignature::new(
VarPattern::Ident(Identifier::private_with_line(
Str::rc(&buf_name),
sig.ln_begin().unwrap(),
)),
None,
));
let buf_def = Def::new(buf_sig, body); let buf_def = Def::new(buf_sig, body);
new_module.push(Expr::Def(buf_def)); new_module.push(Expr::Def(buf_def));
for (n, elem) in tup.elems.iter().enumerate() { for (n, elem) in tup.elems.iter().enumerate() {
@ -278,14 +299,7 @@ impl Desugarer {
} }
} }
VarPattern::Array(arr) => { VarPattern::Array(arr) => {
let buf_name = self.fresh_var_name(); let (buf_name, buf_sig) = self.gen_buf_name_and_sig(sig.ln_begin().unwrap(), None);
let buf_sig = Signature::Var(VarSignature::new(
VarPattern::Ident(Identifier::private_with_line(
Str::rc(&buf_name),
sig.ln_begin().unwrap(),
)),
None,
));
let buf_def = Def::new(buf_sig, body); let buf_def = Def::new(buf_sig, body);
new_module.push(Expr::Def(buf_def)); new_module.push(Expr::Def(buf_def));
for (n, elem) in arr.elems.iter().enumerate() { for (n, elem) in arr.elems.iter().enumerate() {
@ -297,7 +311,33 @@ impl Desugarer {
); );
} }
} }
VarPattern::Record(_rec) => todo!(), VarPattern::Record(rec) => {
let (buf_name, buf_sig) = self.gen_buf_name_and_sig(sig.ln_begin().unwrap(), None);
let buf_def = Def::new(buf_sig, body);
new_module.push(Expr::Def(buf_def));
for VarRecordAttr { lhs, rhs } in rec.attrs.iter() {
self.desugar_nested_var_pattern(
new_module,
rhs,
&buf_name,
BufIndex::Record(lhs),
);
}
}
VarPattern::DataPack(pack) => {
let (buf_name, buf_sig) =
self.gen_buf_name_and_sig(sig.ln_begin().unwrap(), Some(pack.class.clone()));
let buf_def = Def::new(buf_sig, body);
new_module.push(Expr::Def(buf_def));
for VarRecordAttr { lhs, rhs } in pack.args.attrs.iter() {
self.desugar_nested_var_pattern(
new_module,
rhs,
&buf_name,
BufIndex::Record(lhs),
);
}
}
VarPattern::Ident(_ident) => { VarPattern::Ident(_ident) => {
let def = Def::new(Signature::Var(sig.clone()), body); let def = Def::new(Signature::Var(sig.clone()), body);
new_module.push(Expr::Def(def)); new_module.push(Expr::Def(def));
@ -306,21 +346,162 @@ impl Desugarer {
} }
} }
/// `F(I | I > 0)` -> `F(I: {I: Int | I > 0})` /// `{x; y}` -> `{x = x; y = y}`
fn desugar_refinement_pattern(&self, _mod: Module) -> Module { fn desugar_shortened_record(&self, mut module: Module) -> Module {
todo!() let mut new = Module::with_capacity(module.len());
while let Some(chunk) = module.lpop() {
new.push(self.rec_desugar_shortened_record(chunk));
}
new
} }
/// ```python fn rec_desugar_shortened_record(&self, expr: Expr) -> Expr {
/// @deco match expr {
/// f x = ... Expr::Record(Record::Shortened(rec)) => {
/// ``` let rec = self.desugar_shortened_record_inner(rec);
/// ↓ Expr::Record(Record::Normal(rec))
/// ```python }
/// _f x = ... Expr::DataPack(pack) => {
/// f = deco _f if let Record::Shortened(rec) = pack.args {
/// ``` let class = self.rec_desugar_shortened_record(*pack.class);
fn desugar_decorators(&self, _mod: Module) -> Module { let rec = self.desugar_shortened_record_inner(rec);
let args = Record::Normal(rec);
Expr::DataPack(DataPack::new(class, pack.connector, args))
} else {
Expr::DataPack(pack)
}
}
Expr::Array(array) => match array {
Array::Normal(arr) => {
let (elems, _, _) = arr.elems.deconstruct();
let elems = elems
.into_iter()
.map(|elem| PosArg::new(self.rec_desugar_shortened_record(elem.expr)))
.collect();
let elems = Args::new(elems, vec![], None);
let arr = NormalArray::new(arr.l_sqbr, arr.r_sqbr, elems);
Expr::Array(Array::Normal(arr))
}
_ => todo!(),
},
Expr::Tuple(tuple) => match tuple {
Tuple::Normal(tup) => {
let (elems, _, paren) = tup.elems.deconstruct();
let elems = elems
.into_iter()
.map(|elem| PosArg::new(self.rec_desugar_shortened_record(elem.expr)))
.collect();
let new_tup = Args::new(elems, vec![], paren);
let tup = NormalTuple::new(new_tup);
Expr::Tuple(Tuple::Normal(tup))
}
},
Expr::Set(set) => {
todo!("{set}")
}
Expr::Dict(dict) => {
todo!("{dict}")
}
Expr::BinOp(binop) => {
let mut args = binop.args.into_iter();
let lhs = self.rec_desugar_shortened_record(*args.next().unwrap());
let rhs = self.rec_desugar_shortened_record(*args.next().unwrap());
Expr::BinOp(BinOp::new(binop.op, lhs, rhs))
}
Expr::UnaryOp(unaryop) => {
let mut args = unaryop.args.into_iter();
let expr = self.rec_desugar_shortened_record(*args.next().unwrap());
Expr::UnaryOp(UnaryOp::new(unaryop.op, expr))
}
Expr::Call(call) => {
let obj = self.rec_desugar_shortened_record(*call.obj);
let (pos_args, kw_args, paren) = call.args.deconstruct();
let pos_args = pos_args
.into_iter()
.map(|arg| PosArg::new(self.rec_desugar_shortened_record(arg.expr)))
.collect();
let kw_args = kw_args
.into_iter()
.map(|arg| {
let expr = self.rec_desugar_shortened_record(arg.expr);
KwArg::new(arg.keyword, arg.t_spec, expr) // TODO: t_spec
})
.collect();
let args = Args::new(pos_args, kw_args, paren);
Expr::Call(Call::new(obj, call.method_name, args))
}
Expr::Def(def) => {
let mut chunks = vec![];
for chunk in def.body.block.into_iter() {
chunks.push(self.rec_desugar_shortened_record(chunk));
}
let body = DefBody::new(def.body.op, Block::new(chunks), def.body.id);
Expr::Def(Def::new(def.sig, body))
}
Expr::Lambda(lambda) => {
let mut chunks = vec![];
for chunk in lambda.body.into_iter() {
chunks.push(self.rec_desugar_shortened_record(chunk));
}
let body = Block::new(chunks);
Expr::Lambda(Lambda::new(lambda.sig, lambda.op, body, lambda.id))
}
Expr::TypeAsc(tasc) => {
let expr = self.rec_desugar_shortened_record(*tasc.expr);
Expr::TypeAsc(TypeAscription::new(expr, tasc.t_spec))
}
Expr::Methods(method_defs) => {
let mut new_defs = vec![];
for def in method_defs.defs.into_iter() {
let mut chunks = vec![];
for chunk in def.body.block.into_iter() {
chunks.push(self.rec_desugar_shortened_record(chunk));
}
let body = DefBody::new(def.body.op, Block::new(chunks), def.body.id);
new_defs.push(Def::new(def.sig, body));
}
let new_defs = RecordAttrs::from(new_defs);
Expr::Methods(Methods::new(method_defs.class, method_defs.vis, new_defs))
}
// TODO: Accessorにも一応レコードを入れられる
other => other,
}
}
fn desugar_shortened_record_inner(&self, rec: ShortenedRecord) -> NormalRecord {
let mut attrs = vec![];
for attr in rec.idents.into_iter() {
let var = VarSignature::new(VarPattern::Ident(attr.clone()), None);
let sig = Signature::Var(var);
let body = DefBody::new(
Token::from_str(TokenKind::Equal, "="),
Block::new(vec![Expr::local(
attr.inspect(),
attr.ln_begin().unwrap(),
attr.col_begin().unwrap(),
)]),
DefId(get_hash(&(&sig, attr.inspect()))),
);
let def = Def::new(sig, body);
attrs.push(def);
}
let attrs = RecordAttrs::new(attrs);
NormalRecord::new(rec.l_brace, rec.r_brace, attrs)
}
fn desugar_self(&self, mut module: Module) -> Module {
let mut new = Module::with_capacity(module.len());
while let Some(chunk) = module.lpop() {
new.push(self.rec_desugar_self(chunk));
}
new
}
fn rec_desugar_self(&self, _expr: Expr) -> Expr {
todo!()
}
/// `F(I | I > 0)` -> `F(I: {I: Int | I > 0})`
fn desugar_refinement_pattern(&self, _mod: Module) -> Module {
todo!() todo!()
} }
} }

View file

@ -412,7 +412,9 @@ impl Lexer /*<'a>*/ {
while let Some(ch) = self.peek_cur_ch() { while let Some(ch) = self.peek_cur_ch() {
match ch { match ch {
// `.` may be a dot operator, don't consume // `.` may be a dot operator, don't consume
'.' => return self.lex_num_dot(num), '.' => {
return self.lex_num_dot(num);
}
n if n.is_ascii_digit() || n == '_' => { n if n.is_ascii_digit() || n == '_' => {
num.push(self.consume().unwrap()); num.push(self.consume().unwrap());
} }
@ -525,6 +527,8 @@ impl Lexer /*<'a>*/ {
"isnot" => IsNotOp, "isnot" => IsNotOp,
"dot" => DotOp, "dot" => DotOp,
"cross" => CrossOp, "cross" => CrossOp,
"ref" => RefOp,
"ref!" => RefMutOp,
// これらはリテラルというより定数だが便宜的にリテラルということにしておく // これらはリテラルというより定数だが便宜的にリテラルということにしておく
"True" | "False" => BoolLit, "True" | "False" => BoolLit,
"None" => NoneLit, "None" => NoneLit,

View file

@ -56,7 +56,7 @@ pub enum ArrayInner {
WithLength(PosArg, Expr), WithLength(PosArg, Expr),
Comprehension { Comprehension {
elem: PosArg, elem: PosArg,
generators: Vec<(Local, Expr)>, generators: Vec<(Identifier, Expr)>,
guards: Vec<Expr>, guards: Vec<Expr>,
}, },
} }
@ -64,7 +64,7 @@ pub enum ArrayInner {
pub enum BraceContainer { pub enum BraceContainer {
Set(Set), Set(Set),
Dict(Dict), Dict(Dict),
Record(NormalRecord), Record(Record),
} }
/// Perform recursive descent parsing. /// Perform recursive descent parsing.
@ -145,12 +145,6 @@ impl Parser {
} }
} }
fn throw_syntax_err<L: Locational>(&mut self, l: &L, caused_by: &str) -> ParseError {
log!(err "error caused by: {caused_by}");
self.next_expr();
ParseError::simple_syntax_error(0, l.loc())
}
fn skip_and_throw_syntax_err(&mut self, caused_by: &str) -> ParseError { fn skip_and_throw_syntax_err(&mut self, caused_by: &str) -> ParseError {
let loc = self.peek().unwrap().loc(); let loc = self.peek().unwrap().loc();
log!(err "error caused by: {caused_by}"); log!(err "error caused by: {caused_by}");
@ -275,7 +269,10 @@ impl Parser {
Some(t) if t.is(EOF) => { Some(t) if t.is(EOF) => {
break; break;
} }
Some(t) if t.is(Indent) || t.is(Dedent) => { Some(t) if t.is(Indent) => {
switch_unreachable!()
}
Some(t) if t.is(Dedent) => {
switch_unreachable!() switch_unreachable!()
} }
Some(_) => match self.try_reduce_chunk(true) { Some(_) => match self.try_reduce_chunk(true) {
@ -284,7 +281,7 @@ impl Parser {
} }
Err(_) => {} Err(_) => {}
}, },
_ => switch_unreachable!(), None => switch_unreachable!(),
} }
} }
self.level -= 1; self.level -= 1;
@ -306,29 +303,22 @@ impl Parser {
Some(t) if t.category_is(TC::Separator) => { Some(t) if t.category_is(TC::Separator) => {
self.skip(); self.skip();
} }
Some(t) => { Some(t) if t.is(Indent) => {
if t.is(Indent) { self.skip();
self.skip();
while self.cur_is(Newline) {
self.skip();
}
} else if self.cur_is(Dedent) {
self.skip();
break;
} else if t.is(EOF) {
break;
}
match self.try_reduce_chunk(true) {
Ok(expr) => {
block.push(expr);
if self.cur_is(Dedent) {
self.skip();
break;
}
}
Err(_) => {}
}
} }
Some(t) if t.is(Dedent) => {
self.skip();
break;
}
Some(t) if t.is(EOF) => {
break;
}
Some(_) => match self.try_reduce_chunk(true) {
Ok(expr) => {
block.push(expr);
}
Err(_) => {}
},
_ => switch_unreachable!(), _ => switch_unreachable!(),
} }
} }
@ -418,8 +408,8 @@ impl Parser {
let token = self.lpop(); let token = self.lpop();
match token.kind { match token.kind {
Symbol => { Symbol => {
let attr = Local::new(token); let ident = Identifier::new(Some(vis), VarName::new(token));
acc = Accessor::attr(Expr::Accessor(acc), vis, attr); acc = Accessor::attr(Expr::Accessor(acc), ident);
} }
NatLit => { NatLit => {
let attr = Literal::from(token); let attr = Literal::from(token);
@ -444,9 +434,16 @@ impl Parser {
let token = self.lpop(); let token = self.lpop();
match token.kind { match token.kind {
Symbol => { Symbol => {
let attr = Local::new(token); let ident = Identifier::new(None, VarName::new(token));
acc = Accessor::attr(Expr::Accessor(acc), vis, attr); acc = Accessor::attr(Expr::Accessor(acc), ident);
} }
// DataPack
LBrace => {
self.restore(token);
self.restore(vis);
break;
}
// MethodDefs
Newline => { Newline => {
self.restore(token); self.restore(token);
self.restore(vis); self.restore(vis);
@ -495,8 +492,8 @@ impl Parser {
fn validate_const_expr(&mut self, expr: Expr) -> ParseResult<ConstExpr> { fn validate_const_expr(&mut self, expr: Expr) -> ParseResult<ConstExpr> {
match expr { match expr {
Expr::Lit(l) => Ok(ConstExpr::Lit(l)), Expr::Lit(l) => Ok(ConstExpr::Lit(l)),
Expr::Accessor(Accessor::Local(local)) => { Expr::Accessor(Accessor::Ident(local)) => {
let local = ConstLocal::new(local.symbol); let local = ConstLocal::new(local.name.into_token());
Ok(ConstExpr::Accessor(ConstAccessor::Local(local))) Ok(ConstExpr::Accessor(ConstAccessor::Local(local)))
} }
// TODO: App, Array, Record, BinOp, UnaryOp, // TODO: App, Array, Record, BinOp, UnaryOp,
@ -606,7 +603,11 @@ impl Parser {
{ {
Some(self.try_reduce_args()) Some(self.try_reduce_args())
} }
Some(t) if (t.is(Dot) || t.is(DblColon)) && !self.nth_is(1, Newline) => { Some(t)
if (t.is(Dot) || t.is(DblColon))
&& !self.nth_is(1, Newline)
&& !self.nth_is(1, LBrace) =>
{
Some(self.try_reduce_args()) Some(self.try_reduce_args())
} }
_ => None, _ => None,
@ -743,8 +744,8 @@ impl Parser {
// TODO: type specification // TODO: type specification
debug_power_assert!(self.cur_is(Walrus)); debug_power_assert!(self.cur_is(Walrus));
self.skip(); self.skip();
let kw = if let Accessor::Local(n) = acc { let kw = if let Accessor::Ident(n) = acc {
n.symbol n.name.into_token()
} else { } else {
self.next_expr(); self.next_expr();
self.level -= 1; self.level -= 1;
@ -788,8 +789,8 @@ impl Parser {
let acc = self.try_reduce_acc().map_err(|_| self.stack_dec())?; let acc = self.try_reduce_acc().map_err(|_| self.stack_dec())?;
debug_power_assert!(self.cur_is(Walrus)); debug_power_assert!(self.cur_is(Walrus));
self.skip(); self.skip();
let keyword = if let Accessor::Local(n) = acc { let keyword = if let Accessor::Ident(n) = acc {
n.symbol n.name.into_token()
} else { } else {
self.next_expr(); self.next_expr();
self.level -= 1; self.level -= 1;
@ -827,13 +828,16 @@ impl Parser {
} }
} }
fn try_reduce_method_defs(&mut self, class: Expr, vis: Token) -> ParseResult<MethodDefs> { fn try_reduce_method_defs(&mut self, class: Expr, vis: Token) -> ParseResult<Methods> {
debug_call_info!(self); debug_call_info!(self);
if self.cur_is(Indent) { if self.cur_is(Indent) {
self.skip(); self.skip();
} else { } else {
todo!() todo!()
} }
while self.cur_is(Newline) {
self.skip();
}
let first = self.try_reduce_chunk(false).map_err(|_| self.stack_dec())?; let first = self.try_reduce_chunk(false).map_err(|_| self.stack_dec())?;
let first = option_enum_unwrap!(first, Expr::Def).unwrap_or_else(|| todo!()); let first = option_enum_unwrap!(first, Expr::Def).unwrap_or_else(|| todo!());
let mut defs = vec![first]; let mut defs = vec![first];
@ -841,13 +845,22 @@ impl Parser {
match self.peek() { match self.peek() {
Some(t) if t.category_is(TC::Separator) => { Some(t) if t.category_is(TC::Separator) => {
self.skip(); self.skip();
if self.cur_is(Dedent) { }
self.skip(); Some(t) if t.is(Dedent) => {
break; self.skip();
} break;
}
Some(_) => {
let def = self.try_reduce_chunk(false).map_err(|_| self.stack_dec())?; let def = self.try_reduce_chunk(false).map_err(|_| self.stack_dec())?;
let def = option_enum_unwrap!(def, Expr::Def).unwrap_or_else(|| todo!()); match def {
defs.push(def); Expr::Def(def) => {
defs.push(def);
}
other => {
self.errs
.push(ParseError::simple_syntax_error(0, other.loc()));
}
}
} }
_ => todo!(), _ => todo!(),
} }
@ -857,7 +870,7 @@ impl Parser {
.convert_rhs_to_type_spec(class) .convert_rhs_to_type_spec(class)
.map_err(|_| self.stack_dec())?; .map_err(|_| self.stack_dec())?;
self.level -= 1; self.level -= 1;
Ok(MethodDefs::new(class, vis, defs)) Ok(Methods::new(class, vis, defs))
} }
fn try_reduce_do_block(&mut self) -> ParseResult<Lambda> { fn try_reduce_do_block(&mut self) -> ParseResult<Lambda> {
@ -967,10 +980,12 @@ impl Parser {
.transpose() .transpose()
.map_err(|_| self.stack_dec())? .map_err(|_| self.stack_dec())?
{ {
let call = Call::new(obj, Some(symbol), args); let ident = Identifier::new(None, VarName::new(symbol));
let call = Call::new(obj, Some(ident), args);
stack.push(ExprOrOp::Expr(Expr::Call(call))); stack.push(ExprOrOp::Expr(Expr::Call(call)));
} else { } else {
let acc = Accessor::attr(obj, vis, Local::new(symbol)); let ident = Identifier::new(None, VarName::new(symbol));
let acc = Accessor::attr(obj, ident);
stack.push(ExprOrOp::Expr(Expr::Accessor(acc))); stack.push(ExprOrOp::Expr(Expr::Accessor(acc)));
} }
} }
@ -979,7 +994,25 @@ impl Parser {
let defs = self let defs = self
.try_reduce_method_defs(maybe_class, vis) .try_reduce_method_defs(maybe_class, vis)
.map_err(|_| self.stack_dec())?; .map_err(|_| self.stack_dec())?;
return Ok(Expr::MethodDefs(defs)); let expr = Expr::Methods(defs);
assert_eq!(stack.len(), 0);
self.level -= 1;
return Ok(expr);
}
l_brace if l_brace.is(LBrace) => {
let maybe_class = enum_unwrap!(stack.pop(), Some:(ExprOrOp::Expr:(_)));
self.restore(l_brace);
let container = self
.try_reduce_brace_container()
.map_err(|_| self.stack_dec())?;
match container {
BraceContainer::Record(args) => {
let pack = DataPack::new(maybe_class, vis, args);
stack.push(ExprOrOp::Expr(Expr::DataPack(pack)));
}
BraceContainer::Dict(dict) => todo!("{dict}"),
BraceContainer::Set(set) => todo!("{set}"),
}
} }
other => { other => {
self.restore(other); self.restore(other);
@ -1007,10 +1040,12 @@ impl Parser {
.transpose() .transpose()
.map_err(|_| self.stack_dec())? .map_err(|_| self.stack_dec())?
{ {
let call = Call::new(obj, Some(symbol), args); let ident = Identifier::new(Some(vis), VarName::new(symbol));
let call = Call::new(obj, Some(ident), args);
stack.push(ExprOrOp::Expr(Expr::Call(call))); stack.push(ExprOrOp::Expr(Expr::Call(call)));
} else { } else {
let acc = Accessor::attr(obj, vis, Local::new(symbol)); let ident = Identifier::new(Some(vis), VarName::new(symbol));
let acc = Accessor::attr(obj, ident);
stack.push(ExprOrOp::Expr(Expr::Accessor(acc))); stack.push(ExprOrOp::Expr(Expr::Accessor(acc)));
} }
} }
@ -1019,7 +1054,7 @@ impl Parser {
let defs = self let defs = self
.try_reduce_method_defs(maybe_class, vis) .try_reduce_method_defs(maybe_class, vis)
.map_err(|_| self.stack_dec())?; .map_err(|_| self.stack_dec())?;
return Ok(Expr::MethodDefs(defs)); return Ok(Expr::Methods(defs));
} }
other => { other => {
self.restore(other); self.restore(other);
@ -1037,6 +1072,11 @@ impl Parser {
.map_err(|_| self.stack_dec())?; .map_err(|_| self.stack_dec())?;
stack.push(ExprOrOp::Expr(Expr::Tuple(tup))); stack.push(ExprOrOp::Expr(Expr::Tuple(tup)));
} }
Some(t) if t.category_is(TC::Reserved) => {
self.level -= 1;
let err = self.skip_and_throw_syntax_err(caused_by!());
self.errs.push(err);
}
_ => { _ => {
if stack.len() <= 1 { if stack.len() <= 1 {
break; break;
@ -1156,10 +1196,12 @@ impl Parser {
.transpose() .transpose()
.map_err(|_| self.stack_dec())? .map_err(|_| self.stack_dec())?
{ {
let call = Call::new(obj, Some(symbol), args); let ident = Identifier::new(Some(vis), VarName::new(symbol));
let call = Call::new(obj, Some(ident), args);
stack.push(ExprOrOp::Expr(Expr::Call(call))); stack.push(ExprOrOp::Expr(Expr::Call(call)));
} else { } else {
let acc = Accessor::attr(obj, vis, Local::new(symbol)); let ident = Identifier::new(Some(vis), VarName::new(symbol));
let acc = Accessor::attr(obj, ident);
stack.push(ExprOrOp::Expr(Expr::Accessor(acc))); stack.push(ExprOrOp::Expr(Expr::Accessor(acc)));
} }
} }
@ -1179,6 +1221,12 @@ impl Parser {
.map_err(|_| self.stack_dec())?; .map_err(|_| self.stack_dec())?;
stack.push(ExprOrOp::Expr(Expr::Tuple(tup))); stack.push(ExprOrOp::Expr(Expr::Tuple(tup)));
} }
Some(t) if t.category_is(TC::Reserved) => {
self.level -= 1;
let err = self.skip_and_throw_syntax_err(caused_by!());
self.errs.push(err);
return Err(());
}
_ => { _ => {
if stack.len() <= 1 { if stack.len() <= 1 {
break; break;
@ -1340,8 +1388,8 @@ impl Parser {
if let Some(res) = self.opt_reduce_args() { if let Some(res) = self.opt_reduce_args() {
let args = res.map_err(|_| self.stack_dec())?; let args = res.map_err(|_| self.stack_dec())?;
let (obj, method_name) = match acc { let (obj, method_name) = match acc {
Accessor::Attr(attr) => (*attr.obj, Some(attr.name.symbol)), Accessor::Attr(attr) => (*attr.obj, Some(attr.ident)),
Accessor::Local(local) => (Expr::Accessor(Accessor::Local(local)), None), Accessor::Ident(ident) => (Expr::Accessor(Accessor::Ident(ident)), None),
_ => todo!(), _ => todo!(),
}; };
let call = Call::new(obj, method_name, args); let call = Call::new(obj, method_name, args);
@ -1403,6 +1451,7 @@ impl Parser {
/// Set, Dict, Record /// Set, Dict, Record
fn try_reduce_brace_container(&mut self) -> ParseResult<BraceContainer> { fn try_reduce_brace_container(&mut self) -> ParseResult<BraceContainer> {
debug_call_info!(self); debug_call_info!(self);
assert!(self.cur_is(LBrace));
let l_brace = self.lpop(); let l_brace = self.lpop();
if self.cur_is(Newline) { if self.cur_is(Newline) {
self.skip(); self.skip();
@ -1416,12 +1465,20 @@ impl Parser {
match first { match first {
Expr::Def(def) => { Expr::Def(def) => {
let record = self let record = self
.try_reduce_record(l_brace, def) .try_reduce_normal_record(l_brace, def)
.map_err(|_| self.stack_dec())?; .map_err(|_| self.stack_dec())?;
self.level -= 1; self.level -= 1;
Ok(BraceContainer::Record(record)) Ok(BraceContainer::Record(Record::Normal(record)))
}
// Dict
Expr::TypeAsc(_) => todo!(),
Expr::Accessor(acc) if self.cur_is(Semi) => {
let record = self
.try_reduce_shortened_record(l_brace, acc)
.map_err(|_| self.stack_dec())?;
self.level -= 1;
Ok(BraceContainer::Record(Record::Shortened(record)))
} }
Expr::TypeAsc(_) => todo!(), // invalid syntax
other => { other => {
let set = self let set = self
.try_reduce_set(l_brace, other) .try_reduce_set(l_brace, other)
@ -1432,27 +1489,28 @@ impl Parser {
} }
} }
fn try_reduce_record(&mut self, l_brace: Token, first: Def) -> ParseResult<NormalRecord> { fn try_reduce_normal_record(
&mut self,
l_brace: Token,
first: Def,
) -> ParseResult<NormalRecord> {
debug_call_info!(self); debug_call_info!(self);
let mut attrs = vec![first]; let mut attrs = vec![first];
loop { loop {
match self.peek() { match self.peek() {
Some(t) if t.category_is(TC::Separator) => { Some(t) if t.category_is(TC::Separator) => {
self.skip(); self.skip();
if self.cur_is(Dedent) { }
self.skip(); Some(t) if t.is(Dedent) => {
if self.cur_is(RBrace) { self.skip();
let r_brace = self.lpop(); if self.cur_is(RBrace) {
self.level -= 1; let r_brace = self.lpop();
let attrs = RecordAttrs::from(attrs); self.level -= 1;
return Ok(NormalRecord::new(l_brace, r_brace, attrs)); let attrs = RecordAttrs::from(attrs);
} else { return Ok(NormalRecord::new(l_brace, r_brace, attrs));
todo!() } else {
} todo!()
} }
let def = self.try_reduce_chunk(false).map_err(|_| self.stack_dec())?;
let def = option_enum_unwrap!(def, Expr::Def).unwrap_or_else(|| todo!());
attrs.push(def);
} }
Some(term) if term.is(RBrace) => { Some(term) if term.is(RBrace) => {
let r_brace = self.lpop(); let r_brace = self.lpop();
@ -1460,6 +1518,55 @@ impl Parser {
let attrs = RecordAttrs::from(attrs); let attrs = RecordAttrs::from(attrs);
return Ok(NormalRecord::new(l_brace, r_brace, attrs)); return Ok(NormalRecord::new(l_brace, r_brace, attrs));
} }
Some(_) => {
let def = self.try_reduce_chunk(false).map_err(|_| self.stack_dec())?;
let def = option_enum_unwrap!(def, Expr::Def).unwrap_or_else(|| todo!());
attrs.push(def);
}
_ => todo!(),
}
}
}
fn try_reduce_shortened_record(
&mut self,
l_brace: Token,
first: Accessor,
) -> ParseResult<ShortenedRecord> {
debug_call_info!(self);
let first = match first {
Accessor::Ident(ident) => ident,
other => todo!("{other}"), // syntax error
};
let mut idents = vec![first];
loop {
match self.peek() {
Some(t) if t.category_is(TC::Separator) => {
self.skip();
}
Some(t) if t.is(Dedent) => {
self.skip();
if self.cur_is(RBrace) {
let r_brace = self.lpop();
self.level -= 1;
return Ok(ShortenedRecord::new(l_brace, r_brace, idents));
} else {
todo!()
}
}
Some(term) if term.is(RBrace) => {
let r_brace = self.lpop();
self.level -= 1;
return Ok(ShortenedRecord::new(l_brace, r_brace, idents));
}
Some(_) => {
let acc = self.try_reduce_acc().map_err(|_| self.stack_dec())?;
let acc = match acc {
Accessor::Ident(ident) => ident,
other => todo!("{other}"), // syntax error
};
idents.push(acc);
}
_ => todo!(), _ => todo!(),
} }
} }
@ -1556,6 +1663,14 @@ impl Parser {
self.level -= 1; self.level -= 1;
Ok(Signature::Var(var)) Ok(Signature::Var(var))
} }
Expr::DataPack(pack) => {
let data_pack = self
.convert_data_pack_to_data_pack_pat(pack)
.map_err(|_| self.stack_dec())?;
let var = VarSignature::new(VarPattern::DataPack(data_pack), None);
self.level -= 1;
Ok(Signature::Var(var))
}
Expr::Tuple(tuple) => { Expr::Tuple(tuple) => {
let tuple_pat = self let tuple_pat = self
.convert_tuple_to_tuple_pat(tuple) .convert_tuple_to_tuple_pat(tuple)
@ -1573,7 +1688,7 @@ impl Parser {
} }
other => { other => {
self.level -= 1; self.level -= 1;
let err = self.throw_syntax_err(&other, caused_by!()); let err = ParseError::simple_syntax_error(line!() as usize, other.loc());
self.errs.push(err); self.errs.push(err);
Err(()) Err(())
} }
@ -1583,22 +1698,14 @@ impl Parser {
fn convert_accessor_to_var_sig(&mut self, _accessor: Accessor) -> ParseResult<VarSignature> { fn convert_accessor_to_var_sig(&mut self, _accessor: Accessor) -> ParseResult<VarSignature> {
debug_call_info!(self); debug_call_info!(self);
match _accessor { match _accessor {
Accessor::Local(local) => { Accessor::Ident(ident) => {
let pat = VarPattern::Ident(Identifier::new(None, VarName::new(local.symbol))); let pat = VarPattern::Ident(ident);
self.level -= 1;
Ok(VarSignature::new(pat, None))
}
Accessor::Public(public) => {
let pat = VarPattern::Ident(Identifier::new(
Some(public.dot),
VarName::new(public.symbol),
));
self.level -= 1; self.level -= 1;
Ok(VarSignature::new(pat, None)) Ok(VarSignature::new(pat, None))
} }
other => { other => {
self.level -= 1; self.level -= 1;
let err = self.throw_syntax_err(&other, caused_by!()); let err = ParseError::simple_syntax_error(line!() as usize, other.loc());
self.errs.push(err); self.errs.push(err);
Err(()) Err(())
} }
@ -1610,12 +1717,54 @@ impl Parser {
todo!() todo!()
} }
fn convert_record_to_record_pat( fn convert_record_to_record_pat(&mut self, record: Record) -> ParseResult<VarRecordPattern> {
&mut self,
_record: NormalRecord,
) -> ParseResult<VarRecordPattern> {
debug_call_info!(self); debug_call_info!(self);
todo!() match record {
Record::Normal(rec) => {
let mut pats = vec![];
for mut attr in rec.attrs.into_iter() {
let lhs =
option_enum_unwrap!(attr.sig, Signature::Var).unwrap_or_else(|| todo!());
let lhs =
option_enum_unwrap!(lhs.pat, VarPattern::Ident).unwrap_or_else(|| todo!());
assert_eq!(attr.body.block.len(), 1);
let rhs = option_enum_unwrap!(attr.body.block.remove(0), Expr::Accessor)
.unwrap_or_else(|| todo!());
let rhs = self
.convert_accessor_to_var_sig(rhs)
.map_err(|_| self.stack_dec())?;
pats.push(VarRecordAttr::new(lhs, rhs));
}
let attrs = VarRecordAttrs::new(pats);
self.level -= 1;
Ok(VarRecordPattern::new(rec.l_brace, attrs, rec.r_brace))
}
Record::Shortened(rec) => {
let mut pats = vec![];
for ident in rec.idents.into_iter() {
let rhs = VarSignature::new(VarPattern::Ident(ident.clone()), None);
pats.push(VarRecordAttr::new(ident.clone(), rhs));
}
let attrs = VarRecordAttrs::new(pats);
self.level -= 1;
Ok(VarRecordPattern::new(rec.l_brace, attrs, rec.r_brace))
}
}
}
fn convert_data_pack_to_data_pack_pat(
&mut self,
pack: DataPack,
) -> ParseResult<VarDataPackPattern> {
debug_call_info!(self);
let class = self
.convert_rhs_to_type_spec(*pack.class)
.map_err(|_| self.stack_dec())?;
let args = self
.convert_record_to_record_pat(pack.args)
.map_err(|_| self.stack_dec())?;
self.level -= 1;
Ok(VarDataPackPattern::new(class, args))
} }
fn convert_tuple_to_tuple_pat(&mut self, tuple: Tuple) -> ParseResult<VarTuplePattern> { fn convert_tuple_to_tuple_pat(&mut self, tuple: Tuple) -> ParseResult<VarTuplePattern> {
@ -1675,7 +1824,7 @@ impl Parser {
.map_err(|_| self.stack_dec())?, .map_err(|_| self.stack_dec())?,
other => { other => {
self.level -= 1; self.level -= 1;
let err = self.throw_syntax_err(&other, caused_by!()); let err = ParseError::simple_syntax_error(line!() as usize, other.loc());
self.errs.push(err); self.errs.push(err);
return Err(()); return Err(());
} }
@ -1691,13 +1840,10 @@ impl Parser {
fn convert_accessor_to_ident(&mut self, _accessor: Accessor) -> ParseResult<Identifier> { fn convert_accessor_to_ident(&mut self, _accessor: Accessor) -> ParseResult<Identifier> {
debug_call_info!(self); debug_call_info!(self);
let ident = match _accessor { let ident = match _accessor {
Accessor::Local(local) => Identifier::new(None, VarName::new(local.symbol)), Accessor::Ident(ident) => ident,
Accessor::Public(public) => {
Identifier::new(Some(public.dot), VarName::new(public.symbol))
}
other => { other => {
self.level -= 1; self.level -= 1;
let err = self.throw_syntax_err(&other, caused_by!()); let err = ParseError::simple_syntax_error(line!() as usize, other.loc());
self.errs.push(err); self.errs.push(err);
return Err(()); return Err(());
} }
@ -1747,15 +1893,15 @@ impl Parser {
) -> ParseResult<ParamSignature> { ) -> ParseResult<ParamSignature> {
debug_call_info!(self); debug_call_info!(self);
match expr { match expr {
Expr::Accessor(Accessor::Local(local)) => { Expr::Accessor(Accessor::Ident(ident)) => {
if &local.inspect()[..] == "self" && !allow_self { if &ident.inspect()[..] == "self" && !allow_self {
self.level -= 1; self.level -= 1;
let err = self.throw_syntax_err(&local, caused_by!()); let err = ParseError::simple_syntax_error(line!() as usize, ident.loc());
self.errs.push(err); self.errs.push(err);
return Err(()); return Err(());
} }
let name = VarName::new(local.symbol); // FIXME deny: public
let pat = ParamPattern::VarName(name); let pat = ParamPattern::VarName(ident.name);
let param = ParamSignature::new(pat, None, None); let param = ParamSignature::new(pat, None, None);
self.level -= 1; self.level -= 1;
Ok(param) Ok(param)
@ -1800,45 +1946,36 @@ impl Parser {
self.level -= 1; self.level -= 1;
Ok(param) Ok(param)
} }
Expr::Call(mut call) => match *call.obj { Expr::UnaryOp(unary) => match unary.op.kind {
Expr::Accessor(Accessor::Local(local)) => match &local.inspect()[..] { TokenKind::RefOp => {
"ref" => { let var = unary.args.into_iter().next().unwrap();
assert_eq!(call.args.len(), 1); let var = option_enum_unwrap!(*var, Expr::Accessor:(Accessor::Ident:(_)))
let var = call.args.remove_pos(0).expr; .unwrap_or_else(|| todo!());
let var = option_enum_unwrap!(var, Expr::Accessor:(Accessor::Local:(_))) let pat = ParamPattern::Ref(var.name);
.unwrap_or_else(|| todo!()); let param = ParamSignature::new(pat, None, None);
let pat = ParamPattern::Ref(VarName::new(var.symbol));
let param = ParamSignature::new(pat, None, None);
self.level -= 1;
Ok(param)
}
"ref!" => {
assert_eq!(call.args.len(), 1);
let var = call.args.remove_pos(0).expr;
let var = option_enum_unwrap!(var, Expr::Accessor:(Accessor::Local:(_)))
.unwrap_or_else(|| todo!());
let pat = ParamPattern::RefMut(VarName::new(var.symbol));
let param = ParamSignature::new(pat, None, None);
self.level -= 1;
Ok(param)
}
_other => {
self.level -= 1;
let err = self.throw_syntax_err(&local, caused_by!());
self.errs.push(err);
Err(())
}
},
other => {
self.level -= 1; self.level -= 1;
let err = self.throw_syntax_err(&other, caused_by!()); Ok(param)
}
TokenKind::RefMutOp => {
let var = unary.args.into_iter().next().unwrap();
let var = option_enum_unwrap!(*var, Expr::Accessor:(Accessor::Ident:(_)))
.unwrap_or_else(|| todo!());
let pat = ParamPattern::RefMut(var.name);
let param = ParamSignature::new(pat, None, None);
self.level -= 1;
Ok(param)
}
// TODO: Spread
_other => {
self.level -= 1;
let err = ParseError::simple_syntax_error(line!() as usize, unary.loc());
self.errs.push(err); self.errs.push(err);
Err(()) Err(())
} }
}, },
other => { other => {
self.level -= 1; self.level -= 1;
let err = self.throw_syntax_err(&other, caused_by!()); let err = ParseError::simple_syntax_error(line!() as usize, other.loc());
self.errs.push(err); self.errs.push(err);
Err(()) Err(())
} }
@ -1864,7 +2001,7 @@ impl Parser {
fn convert_record_to_param_record_pat( fn convert_record_to_param_record_pat(
&mut self, &mut self,
_record: NormalRecord, _record: Record,
) -> ParseResult<ParamRecordPattern> { ) -> ParseResult<ParamRecordPattern> {
debug_call_info!(self); debug_call_info!(self);
todo!() todo!()
@ -1937,7 +2074,7 @@ impl Parser {
} }
other => { other => {
self.level -= 1; self.level -= 1;
let err = self.throw_syntax_err(&other, caused_by!()); let err = ParseError::simple_syntax_error(line!() as usize, other.loc());
self.errs.push(err); self.errs.push(err);
Err(()) Err(())
} }
@ -1981,10 +2118,7 @@ impl Parser {
todo!() todo!()
} }
fn convert_record_to_param_pat( fn convert_record_to_param_pat(&mut self, _record: Record) -> ParseResult<ParamRecordPattern> {
&mut self,
_record: NormalRecord,
) -> ParseResult<ParamRecordPattern> {
debug_call_info!(self); debug_call_info!(self);
todo!() todo!()
} }
@ -2038,10 +2172,9 @@ impl Parser {
) -> ParseResult<PreDeclTypeSpec> { ) -> ParseResult<PreDeclTypeSpec> {
debug_call_info!(self); debug_call_info!(self);
let t_spec = match accessor { let t_spec = match accessor {
Accessor::Local(local) => PreDeclTypeSpec::Simple(SimpleTypeSpec::new( Accessor::Ident(ident) => {
VarName::new(local.symbol), PreDeclTypeSpec::Simple(SimpleTypeSpec::new(ident.name, ConstArgs::empty()))
ConstArgs::empty(), }
)),
other => todo!("{other}"), other => todo!("{other}"),
}; };
self.level -= 1; self.level -= 1;

View file

@ -103,6 +103,10 @@ pub enum TokenKind {
DotOp, DotOp,
/// `cross` (vector product) /// `cross` (vector product)
CrossOp, CrossOp,
/// `ref` (special unary)
RefOp,
/// `ref!` (special unary)
RefMutOp,
/// = /// =
Equal, Equal,
/// := /// :=
@ -183,10 +187,8 @@ pub enum TokenCategory {
LambdaOp, LambdaOp,
/// \n ; /// \n ;
Separator, Separator,
/// ^ (reserved) /// ^ &
Caret, Reserved,
/// &
Amper,
/// @ /// @
AtSign, AtSign,
/// | /// |
@ -210,7 +212,7 @@ impl TokenKind {
Symbol => TokenCategory::Symbol, Symbol => TokenCategory::Symbol,
NatLit | IntLit | RatioLit | StrLit | BoolLit | NoneLit | EllipsisLit | NoImplLit NatLit | IntLit | RatioLit | StrLit | BoolLit | NoneLit | EllipsisLit | NoImplLit
| InfLit => TokenCategory::Literal, | InfLit => TokenCategory::Literal,
PrePlus | PreMinus | PreBitNot | Mutate => 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 TokenCategory::SpecialBinOp
@ -220,8 +222,7 @@ impl TokenKind {
Semi | Newline => TokenCategory::Separator, Semi | Newline => TokenCategory::Separator,
LParen | LBrace | LSqBr | Indent => TokenCategory::LEnclosure, LParen | LBrace | LSqBr | Indent => TokenCategory::LEnclosure,
RParen | RBrace | RSqBr | Dedent => TokenCategory::REnclosure, RParen | RBrace | RSqBr | Dedent => TokenCategory::REnclosure,
Caret => TokenCategory::Caret, Caret | Amper => TokenCategory::Reserved,
Amper => TokenCategory::Amper,
AtSign => TokenCategory::AtSign, AtSign => TokenCategory::AtSign,
VBar => TokenCategory::VBar, VBar => TokenCategory::VBar,
UBar => TokenCategory::UBar, UBar => TokenCategory::UBar,
@ -234,16 +235,16 @@ impl TokenKind {
pub const fn precedence(&self) -> Option<usize> { pub const fn precedence(&self) -> Option<usize> {
let prec = match self { let prec = match self {
Dot | DblColon => 200, // . Dot | DblColon => 200, // .
Pow => 190, // ** Pow => 190, // **
PrePlus | PreMinus | PreBitNot => 180, // (unary) + - * ~ PrePlus | PreMinus | PreBitNot | RefOp | RefMutOp => 180, // (unary) + - * ~ ref ref!
Star | Slash | FloorDiv | Mod | CrossOp | DotOp => 170, // * / // % cross dot Star | Slash | FloorDiv | Mod | CrossOp | DotOp => 170, // * / // % cross dot
Plus | Minus => 160, // + - Plus | Minus => 160, // + -
Shl | Shr => 150, // << >> Shl | Shr => 150, // << >>
BitAnd => 140, // && BitAnd => 140, // &&
BitXor => 130, // ^^ BitXor => 130, // ^^
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
@ -372,6 +373,16 @@ impl Token {
Self::from_str(TokenKind::Symbol, cont) Self::from_str(TokenKind::Symbol, cont)
} }
#[inline]
pub fn symbol_with_line(cont: &str, line: usize) -> Self {
Token {
kind: TokenKind::Symbol,
content: Str::rc(cont),
lineno: line,
col_begin: 0,
}
}
pub const fn static_symbol(s: &'static str) -> Self { pub const fn static_symbol(s: &'static str) -> Self {
Token { Token {
kind: TokenKind::Symbol, kind: TokenKind::Symbol,

View file

@ -1,6 +1,6 @@
[package] [package]
name = "erg_type" name = "erg_type"
version = "0.3.2" version = "0.4.0-beta.1"
description = "APIs for Erg types" description = "APIs for Erg types"
authors = ["Shunsuke Shibayama <sbym1346@gmail.com>"] authors = ["Shunsuke Shibayama <sbym1346@gmail.com>"]
license = "MIT OR Apache-2.0" license = "MIT OR Apache-2.0"
@ -18,7 +18,7 @@ simplified_chinese = [ "erg_common/simplified_chinese" ]
traditional_chinese = [ "erg_common/traditional_chinese" ] traditional_chinese = [ "erg_common/traditional_chinese" ]
[dependencies] [dependencies]
erg_common = { version = "0.3.2", path = "../erg_common" } erg_common = { version = "0.4.0-beta.1", path = "../erg_common" }
[lib] [lib]
path = "lib.rs" path = "lib.rs"

View file

@ -21,25 +21,25 @@ pub fn named_free_var(name: Str, level: usize, constraint: Constraint) -> Type {
} }
pub fn array(elem_t: Type, len: TyParam) -> Type { pub fn array(elem_t: Type, len: TyParam) -> Type {
poly_class("Array", vec![TyParam::t(elem_t), len]) poly("Array", vec![TyParam::t(elem_t), len])
} }
pub fn array_mut(elem_t: Type, len: TyParam) -> Type { pub fn array_mut(elem_t: Type, len: TyParam) -> Type {
poly_class("Array!", vec![TyParam::t(elem_t), len]) poly("Array!", vec![TyParam::t(elem_t), len])
} }
pub fn dict(k_t: Type, v_t: Type) -> Type { pub fn dict(k_t: Type, v_t: Type) -> Type {
poly_class("Dict", vec![TyParam::t(k_t), TyParam::t(v_t)]) poly("Dict", vec![TyParam::t(k_t), TyParam::t(v_t)])
} }
pub fn tuple(args: Vec<Type>) -> Type { pub fn tuple(args: Vec<Type>) -> Type {
let name = format!("Tuple{}", args.len()); let name = format!("Tuple{}", args.len());
poly_class(name, args.into_iter().map(TyParam::t).collect()) poly(name, args.into_iter().map(TyParam::t).collect())
} }
#[inline] #[inline]
pub fn range(t: Type) -> Type { pub fn range(t: Type) -> Type {
poly_class("Range", vec![TyParam::t(t)]) poly("Range", vec![TyParam::t(t)])
} }
pub fn enum_t(s: Set<ValueObj>) -> Type { pub fn enum_t(s: Set<ValueObj>) -> Type {
@ -91,23 +91,26 @@ pub fn int_interval<P: Into<TyParam>, Q: Into<TyParam>>(op: IntervalOp, l: P, r:
} }
pub fn iter(t: Type) -> Type { pub fn iter(t: Type) -> Type {
poly_class("Iter", vec![TyParam::t(t)]) poly("Iter", vec![TyParam::t(t)])
} }
pub fn ref_(t: Type) -> Type { pub fn ref_(t: Type) -> Type {
Type::Ref(Box::new(t)) Type::Ref(Box::new(t))
} }
pub fn ref_mut(t: Type) -> Type { pub fn ref_mut(before: Type, after: Option<Type>) -> Type {
Type::RefMut(Box::new(t)) Type::RefMut {
before: Box::new(before),
after: after.map(Box::new),
}
} }
pub fn option(t: Type) -> Type { pub fn option(t: Type) -> Type {
poly_class("Option", vec![TyParam::t(t)]) poly("Option", vec![TyParam::t(t)])
} }
pub fn option_mut(t: Type) -> Type { pub fn option_mut(t: Type) -> Type {
poly_class("Option!", vec![TyParam::t(t)]) poly("Option!", vec![TyParam::t(t)])
} }
pub fn subr_t( pub fn subr_t(
@ -207,13 +210,14 @@ pub fn proc2(l: Type, r: Type, return_t: Type) -> Type {
pub fn fn_met( pub fn fn_met(
self_t: Type, self_t: Type,
non_default_params: Vec<ParamTy>, mut non_default_params: Vec<ParamTy>,
var_params: Option<ParamTy>, var_params: Option<ParamTy>,
default_params: Vec<ParamTy>, default_params: Vec<ParamTy>,
return_t: Type, return_t: Type,
) -> Type { ) -> Type {
non_default_params.insert(0, ParamTy::kw(Str::ever("self"), self_t));
Type::Subr(SubrType::new( Type::Subr(SubrType::new(
SubrKind::FuncMethod(Box::new(self_t)), SubrKind::Func,
non_default_params, non_default_params,
var_params, var_params,
default_params, default_params,
@ -236,15 +240,15 @@ pub fn fn1_met(self_t: Type, input_t: Type, return_t: Type) -> Type {
} }
pub fn pr_met( pub fn pr_met(
self_before: Type, self_t: Type,
self_after: Option<Type>, mut non_default_params: Vec<ParamTy>,
non_default_params: Vec<ParamTy>,
var_params: Option<ParamTy>, var_params: Option<ParamTy>,
default_params: Vec<ParamTy>, default_params: Vec<ParamTy>,
return_t: Type, return_t: Type,
) -> Type { ) -> Type {
non_default_params.insert(0, ParamTy::kw(Str::ever("self"), self_t));
Type::Subr(SubrType::new( Type::Subr(SubrType::new(
SubrKind::pr_met(self_before, self_after), SubrKind::Proc,
non_default_params, non_default_params,
var_params, var_params,
default_params, default_params,
@ -252,14 +256,13 @@ pub fn pr_met(
)) ))
} }
pub fn pr0_met(self_before: Type, self_after: Option<Type>, return_t: Type) -> Type { pub fn pr0_met(self_t: Type, return_t: Type) -> Type {
pr_met(self_before, self_after, vec![], None, vec![], return_t) pr_met(self_t, vec![], None, vec![], return_t)
} }
pub fn pr1_met(self_before: Type, self_after: Option<Type>, input_t: Type, return_t: Type) -> Type { pub fn pr1_met(self_t: Type, input_t: Type, return_t: Type) -> Type {
pr_met( pr_met(
self_before, self_t,
self_after,
vec![ParamTy::anonymous(input_t)], vec![ParamTy::anonymous(input_t)],
None, None,
vec![], vec![],
@ -286,13 +289,8 @@ pub fn callable(param_ts: Vec<Type>, return_t: Type) -> Type {
} }
#[inline] #[inline]
pub fn class<S: Into<Str>>(name: S) -> Type { pub fn mono<S: Into<Str>>(name: S) -> Type {
Type::MonoClass(name.into()) Type::Mono(name.into())
}
#[inline]
pub fn trait_<S: Into<Str>>(name: S) -> Type {
Type::MonoTrait(name.into())
} }
#[inline] #[inline]
@ -301,16 +299,8 @@ pub fn mono_q<S: Into<Str>>(name: S) -> Type {
} }
#[inline] #[inline]
pub fn poly_class<S: Into<Str>>(name: S, params: Vec<TyParam>) -> Type { pub fn poly<S: Into<Str>>(name: S, params: Vec<TyParam>) -> Type {
Type::PolyClass { Type::Poly {
name: name.into(),
params,
}
}
#[inline]
pub fn poly_trait<S: Into<Str>>(name: S, params: Vec<TyParam>) -> Type {
Type::PolyTrait {
name: name.into(), name: name.into(),
params, params,
} }

View file

@ -107,23 +107,38 @@ impl LimitedDisplay for Constraint {
sup, sup,
cyclicity, cyclicity,
} => match (sub == &Type::Never, sup == &Type::Obj) { } => match (sub == &Type::Never, sup == &Type::Obj) {
(true, true) => write!(f, ": Type (:> Never, <: Obj)"), (true, true) => {
write!(f, ": Type")?;
if cfg!(feature = "debug") {
write!(f, "(:> Never, <: Obj)")?;
}
Ok(())
}
(true, false) => { (true, false) => {
write!(f, "<: ")?; write!(f, "<: ")?;
sup.limited_fmt(f, limit - 1)?; sup.limited_fmt(f, limit - 1)?;
write!(f, "(cyclicity: {cyclicity:?})") if cfg!(feature = "debug") {
write!(f, "(cyclicity: {cyclicity:?})")?;
}
Ok(())
} }
(false, true) => { (false, true) => {
write!(f, ":> ")?; write!(f, ":> ")?;
sub.limited_fmt(f, limit - 1)?; sub.limited_fmt(f, limit - 1)?;
write!(f, "(cyclicity: {cyclicity:?})") if cfg!(feature = "debug") {
write!(f, "(cyclicity: {cyclicity:?})")?;
}
Ok(())
} }
(false, false) => { (false, false) => {
write!(f, ":> ")?; write!(f, ":> ")?;
sub.limited_fmt(f, limit - 1)?; sub.limited_fmt(f, limit - 1)?;
write!(f, ", <: ")?; write!(f, ", <: ")?;
sup.limited_fmt(f, limit - 1)?; sup.limited_fmt(f, limit - 1)?;
write!(f, "(cyclicity: {cyclicity:?})") if cfg!(feature = "debug") {
write!(f, "(cyclicity: {cyclicity:?})")?;
}
Ok(())
} }
}, },
Self::TypeOf(t) => { Self::TypeOf(t) => {
@ -136,7 +151,7 @@ impl LimitedDisplay for Constraint {
} }
impl Constraint { impl Constraint {
pub const fn sandwiched(sub: Type, sup: Type, cyclicity: Cyclicity) -> Self { pub const fn new_sandwiched(sub: Type, sup: Type, cyclicity: Cyclicity) -> Self {
Self::Sandwiched { Self::Sandwiched {
sub, sub,
sup, sup,
@ -144,20 +159,20 @@ impl Constraint {
} }
} }
pub fn type_of(t: Type) -> Self { pub fn new_type_of(t: Type) -> Self {
if t == Type::Type { if t == Type::Type {
Self::sandwiched(Type::Never, Type::Obj, Not) Self::new_sandwiched(Type::Never, Type::Obj, Not)
} else { } else {
Self::TypeOf(t) Self::TypeOf(t)
} }
} }
pub const fn subtype_of(sup: Type, cyclicity: Cyclicity) -> Self { pub const fn new_subtype_of(sup: Type, cyclicity: Cyclicity) -> Self {
Self::sandwiched(Type::Never, sup, cyclicity) Self::new_sandwiched(Type::Never, sup, cyclicity)
} }
pub const fn supertype_of(sub: Type, cyclicity: Cyclicity) -> Self { pub const fn new_supertype_of(sub: Type, cyclicity: Cyclicity) -> Self {
Self::sandwiched(sub, Type::Obj, cyclicity) Self::new_sandwiched(sub, Type::Obj, cyclicity)
} }
pub const fn is_uninited(&self) -> bool { pub const fn is_uninited(&self) -> bool {
@ -171,6 +186,17 @@ impl Constraint {
} }
} }
pub fn lift(&self) {
match self {
Self::Sandwiched { sub, sup, .. } => {
sub.lift();
sup.lift();
}
Self::TypeOf(t) => t.lift(),
Self::Uninited => {}
}
}
pub fn get_type(&self) -> Option<&Type> { pub fn get_type(&self) -> Option<&Type> {
match self { match self {
Self::TypeOf(ty) => Some(ty), Self::TypeOf(ty) => Some(ty),
@ -183,28 +209,28 @@ impl Constraint {
} }
} }
pub fn get_sub_type(&self) -> Option<&Type> { pub fn get_sub(&self) -> Option<&Type> {
match self { match self {
Self::Sandwiched { sub, .. } => Some(sub), Self::Sandwiched { sub, .. } => Some(sub),
_ => None, _ => None,
} }
} }
pub fn get_super_type(&self) -> Option<&Type> { pub fn get_super(&self) -> Option<&Type> {
match self { match self {
Self::Sandwiched { sup, .. } => Some(sup), Self::Sandwiched { sup, .. } => Some(sup),
_ => None, _ => None,
} }
} }
pub fn get_sub_sup_type(&self) -> Option<(&Type, &Type)> { pub fn get_sub_sup(&self) -> Option<(&Type, &Type)> {
match self { match self {
Self::Sandwiched { sub, sup, .. } => Some((sub, sup)), Self::Sandwiched { sub, sup, .. } => Some((sub, sup)),
_ => None, _ => None,
} }
} }
pub fn get_super_type_mut(&mut self) -> Option<&mut Type> { pub fn get_super_mut(&mut self) -> Option<&mut Type> {
match self { match self {
Self::Sandwiched { sup, .. } => Some(sup), Self::Sandwiched { sup, .. } => Some(sup),
_ => None, _ => None,
@ -250,7 +276,11 @@ impl<T: LimitedDisplay> LimitedDisplay for FreeKind<T> {
return write!(f, "..."); return write!(f, "...");
} }
match self { match self {
Self::Linked(t) | Self::UndoableLinked { t, .. } => t.limited_fmt(f, limit), Self::Linked(t) | Self::UndoableLinked { t, .. } => {
write!(f, "(")?;
t.limited_fmt(f, limit)?;
write!(f, ")")
}
Self::NamedUnbound { Self::NamedUnbound {
name, name,
lev, lev,
@ -258,7 +288,11 @@ impl<T: LimitedDisplay> LimitedDisplay for FreeKind<T> {
} => { } => {
write!(f, "?{name}(")?; write!(f, "?{name}(")?;
constraint.limited_fmt(f, limit - 1)?; constraint.limited_fmt(f, limit - 1)?;
write!(f, ")[{lev}]") write!(f, ")")?;
if cfg!(feature = "debug") {
write!(f, "[{lev}]")?;
}
Ok(())
} }
Self::Unbound { Self::Unbound {
id, id,
@ -267,7 +301,11 @@ impl<T: LimitedDisplay> LimitedDisplay for FreeKind<T> {
} => { } => {
write!(f, "?{id}(")?; write!(f, "?{id}(")?;
constraint.limited_fmt(f, limit - 1)?; constraint.limited_fmt(f, limit - 1)?;
write!(f, ")[{lev}]") write!(f, ")")?;
if cfg!(feature = "debug") {
write!(f, "[{lev}]")?;
}
Ok(())
} }
} }
} }
@ -417,13 +455,17 @@ impl<T: Clone + HasLevel> Free<T> {
pub fn lift(&self) { pub fn lift(&self) {
match &mut *self.borrow_mut() { match &mut *self.borrow_mut() {
FreeKind::Unbound { lev, .. } | FreeKind::NamedUnbound { lev, .. } => { FreeKind::Unbound {
lev, constraint, ..
}
| FreeKind::NamedUnbound {
lev, constraint, ..
} => {
*lev += 1; *lev += 1;
constraint.lift();
} }
FreeKind::Linked(t) | FreeKind::UndoableLinked { t, .. } => { FreeKind::Linked(t) | FreeKind::UndoableLinked { t, .. } => {
if let Some(lev) = t.level() { t.lift();
t.update_level(lev + 1);
}
} }
} }
} }
@ -495,23 +537,22 @@ impl<T: Clone + HasLevel> Free<T> {
}) })
} }
pub fn type_of(&self) -> Option<Type> { pub fn get_type(&self) -> Option<Type> {
self.borrow() self.borrow()
.constraint() .constraint()
.and_then(|c| c.get_type().cloned()) .and_then(|c| c.get_type().cloned())
} }
pub fn crack_subtype(&self) -> Option<Type> { pub fn get_sup(&self) -> Option<Type> {
self.borrow() self.borrow()
.constraint() .constraint()
.and_then(|c| c.get_super_type().cloned()) .and_then(|c| c.get_super().cloned())
} }
pub fn crack_bound_types(&self) -> Option<(Type, Type)> { pub fn get_bound_types(&self) -> Option<(Type, Type)> {
self.borrow().constraint().and_then(|c| { self.borrow()
c.get_sub_sup_type() .constraint()
.map(|(sub, sup)| (sub.clone(), sup.clone())) .and_then(|c| c.get_sub_sup().map(|(sub, sup)| (sub.clone(), sup.clone())))
})
} }
pub fn is_unbound(&self) -> bool { pub fn is_unbound(&self) -> bool {
@ -542,7 +583,7 @@ impl<T: Clone + HasLevel> Free<T> {
matches!( matches!(
&*self.borrow(), &*self.borrow(),
FreeKind::Unbound { constraint, .. } FreeKind::Unbound { constraint, .. }
| FreeKind::NamedUnbound { constraint, .. } if constraint.get_sub_type().is_some() | FreeKind::NamedUnbound { constraint, .. } if constraint.get_sub().is_some()
) )
} }
@ -550,7 +591,7 @@ impl<T: Clone + HasLevel> Free<T> {
matches!( matches!(
&*self.borrow(), &*self.borrow(),
FreeKind::Unbound { constraint, .. } FreeKind::Unbound { constraint, .. }
| FreeKind::NamedUnbound { constraint, .. } if constraint.get_super_type().is_some() | FreeKind::NamedUnbound { constraint, .. } if constraint.get_super().is_some()
) )
} }
@ -558,12 +599,15 @@ impl<T: Clone + HasLevel> Free<T> {
matches!( matches!(
&*self.borrow(), &*self.borrow(),
FreeKind::Unbound { constraint, .. } FreeKind::Unbound { constraint, .. }
| FreeKind::NamedUnbound { constraint, .. } if constraint.get_sub_sup_type().is_some() | FreeKind::NamedUnbound { constraint, .. } if constraint.get_sub_sup().is_some()
) )
} }
pub fn is_linked(&self) -> bool { pub fn is_linked(&self) -> bool {
matches!(&*self.borrow(), FreeKind::Linked(_)) matches!(
&*self.borrow(),
FreeKind::Linked(_) | FreeKind::UndoableLinked { .. }
)
} }
pub fn unbound_name(&self) -> Option<Str> { pub fn unbound_name(&self) -> Option<Str> {

File diff suppressed because it is too large Load diff

View file

@ -448,12 +448,12 @@ impl TyParam {
} }
pub fn free_var(level: usize, t: Type) -> Self { pub fn free_var(level: usize, t: Type) -> Self {
let constraint = Constraint::type_of(t); let constraint = Constraint::new_type_of(t);
Self::FreeVar(FreeTyParam::new_unbound(level, constraint)) Self::FreeVar(FreeTyParam::new_unbound(level, constraint))
} }
pub fn named_free_var(name: Str, level: usize, t: Type) -> Self { pub fn named_free_var(name: Str, level: usize, t: Type) -> Self {
let constraint = Constraint::type_of(t); let constraint = Constraint::new_type_of(t);
Self::FreeVar(FreeTyParam::new_named_unbound(name, level, constraint)) Self::FreeVar(FreeTyParam::new_named_unbound(name, level, constraint))
} }

View file

@ -17,11 +17,92 @@ use erg_common::{fmt_iter, impl_display_from_debug, switch_lang};
use erg_common::{RcArray, Str}; use erg_common::{RcArray, Str};
use crate::codeobj::CodeObj; use crate::codeobj::CodeObj;
use crate::constructors::{array, class, poly_class, refinement, tuple}; use crate::constructors::{array, mono, poly, refinement, tuple};
use crate::free::fresh_varname; use crate::free::fresh_varname;
use crate::typaram::TyParam; use crate::typaram::TyParam;
use crate::{ConstSubr, HasType, Predicate, Type}; use crate::{ConstSubr, HasType, Predicate, Type};
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub enum TypeKind {
Class,
Subclass,
Trait,
Subtrait,
StructuralTrait,
}
/// Class
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct GenTypeObj {
pub kind: TypeKind,
pub t: Type, // andやorが入る可能性あり
pub require_or_sup: Box<TypeObj>,
pub impls: Option<Box<TypeObj>>,
pub additional: Option<Box<TypeObj>>,
}
impl fmt::Display for GenTypeObj {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "<{:?} {}>", self.kind, self.t)
}
}
impl GenTypeObj {
pub fn new(
kind: TypeKind,
t: Type,
require_or_sup: TypeObj,
impls: Option<TypeObj>,
additional: Option<TypeObj>,
) -> Self {
Self {
kind,
t,
require_or_sup: Box::new(require_or_sup),
impls: impls.map(Box::new),
additional: additional.map(Box::new),
}
}
pub fn meta_type(&self) -> Type {
match self.kind {
TypeKind::Class | TypeKind::Subclass => Type::Class,
TypeKind::Trait | TypeKind::Subtrait | TypeKind::StructuralTrait => Type::Trait,
}
}
}
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub enum TypeObj {
Builtin(Type),
Generated(GenTypeObj),
}
impl fmt::Display for TypeObj {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
TypeObj::Builtin(t) => write!(f, "{t}"),
TypeObj::Generated(t) => write!(f, "{t}"),
}
}
}
impl TypeObj {
pub const fn typ(&self) -> &Type {
match self {
TypeObj::Builtin(t) => t,
TypeObj::Generated(t) => &t.t,
}
}
pub fn contains_intersec(&self, other: &Type) -> bool {
match self {
TypeObj::Builtin(t) => t.contains_intersec(other),
TypeObj::Generated(t) => t.t.contains_intersec(other),
}
}
}
/// 値オブジェクト /// 値オブジェクト
/// コンパイル時評価ができ、シリアライズも可能 /// コンパイル時評価ができ、シリアライズも可能
#[derive(Clone, PartialEq, Default)] #[derive(Clone, PartialEq, Default)]
@ -37,7 +118,7 @@ pub enum ValueObj {
Record(Dict<Field, ValueObj>), Record(Dict<Field, ValueObj>),
Code(Box<CodeObj>), Code(Box<CodeObj>),
Subr(ConstSubr), Subr(ConstSubr),
Type(Box<Type>), Type(TypeObj),
None, None,
Ellipsis, Ellipsis,
NotImplemented, NotImplemented,
@ -92,7 +173,7 @@ impl fmt::Debug for ValueObj {
} }
write!(f, "}}") write!(f, "}}")
} }
Self::Subr(subr) => write!(f, "{subr:?}"), Self::Subr(subr) => write!(f, "{subr}"),
Self::Type(t) => write!(f, "{t}"), Self::Type(t) => write!(f, "{t}"),
Self::None => write!(f, "None"), Self::None => write!(f, "None"),
Self::Ellipsis => write!(f, "Ellipsis"), Self::Ellipsis => write!(f, "Ellipsis"),
@ -262,8 +343,24 @@ impl HasType for ValueObj {
} }
impl ValueObj { impl ValueObj {
pub fn t(t: Type) -> Self { pub fn builtin_t(t: Type) -> Self {
ValueObj::Type(Box::new(t)) ValueObj::Type(TypeObj::Builtin(t))
}
pub fn gen_t(
kind: TypeKind,
t: Type,
require_or_sup: TypeObj,
impls: Option<TypeObj>,
additional: Option<TypeObj>,
) -> Self {
ValueObj::Type(TypeObj::Generated(GenTypeObj::new(
kind,
t,
require_or_sup,
impls,
additional,
)))
} }
pub fn is_num(&self) -> bool { pub fn is_num(&self) -> bool {
@ -274,6 +371,10 @@ impl ValueObj {
} }
} }
pub const fn is_type(&self) -> bool {
matches!(self, Self::Type(_))
}
pub const fn is_mut(&self) -> bool { pub const fn is_mut(&self) -> bool {
matches!(self, Self::Mut(_)) matches!(self, Self::Mut(_))
} }
@ -376,20 +477,24 @@ impl ValueObj {
Self::Record(rec) => { Self::Record(rec) => {
Type::Record(rec.iter().map(|(k, v)| (k.clone(), v.class())).collect()) Type::Record(rec.iter().map(|(k, v)| (k.clone(), v.class())).collect())
} }
Self::Subr(_) => todo!(), Self::Subr(subr) => subr.class(),
Self::Type(_) => Type::Type, Self::Type(t_obj) => match t_obj {
// TODO: builtin
TypeObj::Builtin(_t) => Type::Type,
TypeObj::Generated(gen_t) => gen_t.meta_type(),
},
Self::None => Type::NoneType, Self::None => Type::NoneType,
Self::Ellipsis => Type::Ellipsis, Self::Ellipsis => Type::Ellipsis,
Self::NotImplemented => Type::NotImplemented, Self::NotImplemented => Type::NotImplemented,
Self::Inf => Type::Inf, Self::Inf => Type::Inf,
Self::NegInf => Type::NegInf, Self::NegInf => Type::NegInf,
Self::Mut(m) => match &*m.borrow() { Self::Mut(m) => match &*m.borrow() {
Self::Int(_) => class("Int!"), Self::Int(_) => mono("Int!"),
Self::Nat(_) => class("Nat!"), Self::Nat(_) => mono("Nat!"),
Self::Float(_) => class("Float!"), Self::Float(_) => mono("Float!"),
Self::Str(_) => class("Str!"), Self::Str(_) => mono("Str!"),
Self::Bool(_) => class("Bool!"), Self::Bool(_) => mono("Bool!"),
Self::Array(arr) => poly_class( Self::Array(arr) => poly(
"Array!", "Array!",
vec![ vec![
TyParam::t(arr.iter().next().unwrap().class()), TyParam::t(arr.iter().next().unwrap().class()),
@ -641,6 +746,26 @@ impl ValueObj {
_ => None, _ => None,
} }
} }
pub fn try_get_attr(&self, attr: &Field) -> Option<Self> {
match self {
Self::Type(typ) => match typ {
TypeObj::Builtin(builtin) => todo!("{builtin}{attr}"),
TypeObj::Generated(gen) => match &gen.t {
Type::Record(rec) => {
let t = rec.get(attr)?;
Some(ValueObj::builtin_t(t.clone()))
}
_ => None,
},
},
Self::Record(rec) => {
let v = rec.get(attr)?;
Some(v.clone())
}
_ => None,
}
}
} }
pub mod value_set { pub mod value_set {

View file

@ -15,10 +15,10 @@ A: Erg code is transpiled into Python bytecode. That is, it runs on the same int
We have been influenced by more languages than we can count on both hands, but Python, Rust, Nim, and Haskell have been the strongest influences. We have been influenced by more languages than we can count on both hands, but Python, Rust, Nim, and Haskell have been the strongest influences.
We inherited many semantics from Python, expression-oriented and trait from Rust, procedures from Nim, and functional programming-related features from Haskell. We inherited many semantics from Python, expression-oriented and trait from Rust, procedures from Nim, and functional programming-related features from Haskell.
## Languages that can call Python include Julia. Why did you create Erg? ## There are already languages that can call Python, such as Julia. Why did you create Erg?
A: One of the motivations for Erg's design was to have a language that is easy to use, yet has a powerful type system. That is, a language with type inference, Kind, dependent types, etc. A: One of the motivations for Erg's design was to have a language that is easy to use, yet has a powerful type system. That is a language with type inference, dependent types, etc.
Julia can be typed, but it is really a dynamically typed language and does not have the compile-time error detection benefits of statically typed languages. Julia can be typed, but it is really a dynamically typed language and does not have the advantage of perfect compile-time type error detection like statically typed languages.
## Erg supports multiple styles of programming, including functional and object-oriented programming. Isn't this contrary to Python's "There should be one --and preferably only one-- obvious way to do it."? ## Erg supports multiple styles of programming, including functional and object-oriented programming. Isn't this contrary to Python's "There should be one --and preferably only one-- obvious way to do it."?

View file

@ -227,9 +227,9 @@ print! {i = 1}.bar # <method bar>
C.new({i = 1}).bar # <method bar> C.new({i = 1}).bar # <method bar>
``` ```
## Difference from data class ## Difference from Data Class
There are two types of classes: regular classes, which are record classes through `Class`, and data classes, which inherit (`Inherit`) from record classes. There are two types of classes: regular classes, which are generated with `Class(record)`, and data classes, which are generated with `Inherit(record)`.
The data class inherits the functionality of the record class and has features such as decomposition assignment, `==` and `hash` implemented by default, etc. On the other hand, the data class has its own equivalence relation and format display. The data class inherits the functionality of the record class and has features such as decomposition assignment, `==` and `hash` implemented by default, etc. On the other hand, the data class has its own equivalence relation and format display.
On the other hand, if you want to define your own equivalence relations or formatting displays, you should use the normal class. On the other hand, if you want to define your own equivalence relations or formatting displays, you should use the normal class.
@ -241,9 +241,9 @@ print! c # <C object>
c == d # TypeError: `==` is not implemented for `C` c == d # TypeError: `==` is not implemented for `C`
D = Inherit {i = Int} D = Inherit {i = Int}
e = D.new {i = 1} e = D::{i = 1} # same as `e = D.new {i = 1}`
f = D.new {i = 2} f = D::{i = 2}
print! e # D{i = 1} print! e # D(i=1)
assert e ! = f assert e ! = f
``` ```

View file

@ -1,6 +1,6 @@
# Erg FAQ # Erg FAQ
[![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/faq_general.md%26commit_hash%3Deccd113c1512076c367fb87ea73406f91ff83ba7)](https://gezf7g7pd5.execute-api.ap-northeast-1.amazonaws.com/default/source_up_to_date?owner=erg-lang&repos=erg&ref=main&path=doc/EN/faq_general.md&commit_hash=eccd113c1512076c367fb87ea73406f91ff83ba7) [![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/faq_general.md%26commit_hash%3D521426cba21ed8b6eae5aff965dd14ef99af1228)](https://gezf7g7pd5.execute-api.ap-northeast-1.amazonaws.com/default/source_up_to_date?owner=erg-lang&repos=erg&ref=main&path=doc/EN/faq_general.md&commit_hash=521426cba21ed8b6eae5aff965dd14ef99af1228)
このFAQは一般のErg入門者向けです。 このFAQは一般のErg入門者向けです。
個別の(よくある)技術的な問題については[こちら](./faq_technical.md)を、文法の決定経緯(なぜこのような文法になったのか)などについては 個別の(よくある)技術的な問題については[こちら](./faq_technical.md)を、文法の決定経緯(なぜこのような文法になったのか)などについては

View file

@ -1,6 +1,6 @@
# Erg常见问题 # Erg常见问题
[![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/faq_general.md%26commit_hash%3Deccd113c1512076c367fb87ea73406f91ff83ba7)](https://gezf7g7pd5.execute-api.ap-northeast-1.amazonaws.com/default/source_up_to_date?owner=erg-lang&repos=erg&ref=main&path=doc/EN/faq_general.md&commit_hash=eccd113c1512076c367fb87ea73406f91ff83ba7) [![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/faq_general.md%26commit_hash%3D521426cba21ed8b6eae5aff965dd14ef99af1228)](https://gezf7g7pd5.execute-api.ap-northeast-1.amazonaws.com/default/source_up_to_date?owner=erg-lang&repos=erg&ref=main&path=doc/EN/faq_general.md&commit_hash=521426cba21ed8b6eae5aff965dd14ef99af1228)
此常见问题解答适用于一般 Erg 初学者。 此常见问题解答适用于一般 Erg 初学者。
对于个别(常见)技术问题,请参阅 [此处](./faq_technical.md) 了解个别(常见)技术问题,以及 对于个别(常见)技术问题,请参阅 [此处](./faq_technical.md) 了解个别(常见)技术问题,以及
@ -17,7 +17,7 @@ A: Erg 代码被转译成 Python 字节码。也就是说,它运行在与 Pyth
我们受到的语言多于我们双手所能指望的数量,但 Python、Rust、Nim 和 Haskell 的影响最大。 我们受到的语言多于我们双手所能指望的数量,但 Python、Rust、Nim 和 Haskell 的影响最大。
我们从 Python 继承了许多语义,从 Rust 继承了面向表达式和 trait从 Nim 继承了过程,从 Haskell 继承了函数式编程相关的特性。 我们从 Python 继承了许多语义,从 Rust 继承了面向表达式和 trait从 Nim 继承了过程,从 Haskell 继承了函数式编程相关的特性。
## 可以调用 Python 的语言包括 Julia。你为什么创建 Erg ## 已经有一些语言可以调用Python比如Julia。为什么要创建Erg
Erg 设计的动机之一是拥有一种易于使用且具有强大类型系统的语言。即具有类型推断、Kind、依赖类型等的语言。 Erg 设计的动机之一是拥有一种易于使用且具有强大类型系统的语言。即具有类型推断、Kind、依赖类型等的语言。
Julia 是可以有类型的,但它确实是一种动态类型语言,不具备静态类型语言的编译时错误检测优势。 Julia 是可以有类型的,但它确实是一种动态类型语言,不具备静态类型语言的编译时错误检测优势。

View file

@ -1,6 +1,6 @@
# Erg常見問題 # Erg常見問題
[![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/faq_general.md%26commit_hash%3Deccd113c1512076c367fb87ea73406f91ff83ba7)](https://gezf7g7pd5.execute-api.ap-northeast-1.amazonaws.com/default/source_up_to_date?owner=erg-lang&repos=erg&ref=main&path=doc/EN/faq_general.md&commit_hash=eccd113c1512076c367fb87ea73406f91ff83ba7) [![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/faq_general.md%26commit_hash%3D521426cba21ed8b6eae5aff965dd14ef99af1228)](https://gezf7g7pd5.execute-api.ap-northeast-1.amazonaws.com/default/source_up_to_date?owner=erg-lang&repos=erg&ref=main&path=doc/EN/faq_general.md&commit_hash=521426cba21ed8b6eae5aff965dd14ef99af1228)
此常見問題解答適用於一般 Erg 初學者。 此常見問題解答適用於一般 Erg 初學者。
對於個別(常見)技術問題,請參閱 [此處](./faq_technical.md) 了解個別(常見)技術問題,以及 對於個別(常見)技術問題,請參閱 [此處](./faq_technical.md) 了解個別(常見)技術問題,以及
@ -17,7 +17,7 @@ A: Erg 代碼被轉譯成 Python 字節碼。也就是說,它運行在與 Pyth
我們受到的語言多于我們雙手所能指望的數量,但 Python、Rust、Nim 和 Haskell 的影響最大。 我們受到的語言多于我們雙手所能指望的數量,但 Python、Rust、Nim 和 Haskell 的影響最大。
我們從 Python 繼承了許多語義,從 Rust 繼承了面向表達式和 trait從 Nim 繼承了過程,從 Haskell 繼承了函數式編程相關的特性。 我們從 Python 繼承了許多語義,從 Rust 繼承了面向表達式和 trait從 Nim 繼承了過程,從 Haskell 繼承了函數式編程相關的特性。
## 可以調用 Python 的語言包括 Julia。你為什么創建 Erg ## 已經有一些語言可以調用Python比如Julia。為什麼要創建Erg
Erg 設計的動機之一是擁有一種易于使用且具有強大類型系統的語言。即具有類型推斷、Kind、依賴類型等的語言。 Erg 設計的動機之一是擁有一種易于使用且具有強大類型系統的語言。即具有類型推斷、Kind、依賴類型等的語言。
Julia 是可以有類型的,但它確實是一種動態類型語言,不具備靜態類型語言的編譯時錯誤檢測優勢。 Julia 是可以有類型的,但它確實是一種動態類型語言,不具備靜態類型語言的編譯時錯誤檢測優勢。

View file

@ -1,7 +1,7 @@
Point = Class {x = Int; y = Int}, Impl := Add() and Eq() Point = Class {x = Int; y = Int}, Impl := Add() and Eq()
Point. Point.
new x, y = Self::__new__ {x; y} new x, y = Self::__new__ {x; y}
norm &self = self::x**2 + self::y**2 norm self = self::x**2 + self::y**2
@Impl Add() @Impl Add()
`+` self, other = `+` self, other =
Self.new(self::x + other::x, self::y + other::y) Self.new(self::x + other::x, self::y + other::y)

View file

@ -1,17 +1,25 @@
# Inheritance is prohibited by default. Remove this decorator and check for errors.
@Inheritable @Inheritable
Point2D = Class {x = Int; y = Int} Point2D = Class {x = Int; y = Int}
Point2D::
one = 1
Point2D. Point2D.
new x, y = Self::__new__ {x = x; y = y} zero = Point2D::one - 1
norm ref self = self::x**2 + self::y**2 norm self = self::x**2 + self::y**2
Point3D = Inherit Point2D, Additional := {z = Int} Point3D = Inherit Point2D, Additional := {z = Int}
Point3D. Point3D.
# Overloading is prohibited by default. Remove this decorator and check for errors.
@Override @Override
new x, y, z = Self::__new__ {x = x; y = y; z = z} new x, y, z =
Point3D::__new__ {x; y; z}
@Override @Override
norm ref self = self::x**2 + self::y**2 + self::z**2 norm self = self::x**2 + self::y**2 + self::z**2
UnpackPoint2D = Class {x = Int; y = Int}, Impl := Unpack # `Point2D::__new__` is private, use `Point2D.new` instead
p = Point2D.new {x = 1; y = 2}
p = UnpackPoint2D::{x = 1; y = 2} print! p, p.norm()
UnpackPoint2D::{x = x; y = x} = p print! Point2D.zero
# print! Point2D::one # cannot access private variables
q = Point3D.new 1, 2, 3
print! q, q.norm()

5
examples/unpack.er Normal file
View file

@ -0,0 +1,5 @@
UnpackPoint2D = Class {x = Int; y = Int}, Impl := Unpack
q = UnpackPoint2D::{x = 1; y = 2}
UnpackPoint2D::{x; y} = q
print! x, y