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]]
name = "erg"
version = "0.3.2"
version = "0.4.0-beta.1"
dependencies = [
"erg_common",
"erg_compiler",
@ -25,14 +25,14 @@ dependencies = [
[[package]]
name = "erg_common"
version = "0.3.2"
version = "0.4.0-beta.1"
dependencies = [
"atty",
]
[[package]]
name = "erg_compiler"
version = "0.3.2"
version = "0.4.0-beta.1"
dependencies = [
"erg_common",
"erg_parser",
@ -41,14 +41,14 @@ dependencies = [
[[package]]
name = "erg_parser"
version = "0.3.2"
version = "0.4.0-beta.1"
dependencies = [
"erg_common",
]
[[package]]
name = "erg_type"
version = "0.3.2"
version = "0.4.0-beta.1"
dependencies = [
"erg_common",
]

View file

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

View file

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

View file

@ -1,6 +1,6 @@
[package]
name = "erg_common"
version = "0.3.2"
version = "0.4.0-beta.1"
description = "A common components library of Erg"
authors = ["Shunsuke Shibayama <sbym1346@gmail.com>"]
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)
}
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]
pub fn contains_key<Q: ?Sized>(&self, k: &Q) -> bool
where

View file

@ -35,6 +35,10 @@ pub enum ErrorKind {
PurityError,
HasEffect,
MoveError,
NotConstExpr,
InheritanceError,
VisibilityError,
DummyError,
/* compile warnings */
AttributeWarning = 60,
CastWarning,
@ -201,9 +205,9 @@ impl From<&str> for ErrorKind {
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum Location {
RangePair {
ln_begin: usize,
ln_first: (usize, usize),
col_first: (usize, usize),
ln_end: usize,
ln_second: (usize, usize),
col_second: (usize, usize),
},
Range {
@ -238,16 +242,19 @@ impl Location {
pub fn pair(lhs: Self, rhs: Self) -> Self {
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()),
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()),
}
}
pub const fn ln_begin(&self) -> Option<usize> {
match self {
Self::RangePair { ln_begin, .. }
Self::RangePair {
ln_first: (ln_begin, _),
..
}
| Self::Range { ln_begin, .. }
| Self::LineRange(ln_begin, _)
| Self::Line(ln_begin) => Some(*ln_begin),
@ -257,7 +264,10 @@ impl Location {
pub const fn ln_end(&self) -> Option<usize> {
match self {
Self::RangePair { ln_end, .. }
Self::RangePair {
ln_second: (_, ln_end),
..
}
| Self::Range { ln_end, .. }
| Self::LineRange(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 {
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 {
@ -339,6 +359,41 @@ impl ErrorCore {
pub const VBAR_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:
/// ```console
/// Error[#{.errno}]: File {file}, line {.loc (as line)}, in {.caused_by}
@ -418,13 +473,15 @@ pub trait ErrorDisplay {
Location::Range {
ln_begin, ln_end, ..
} if ln_begin == ln_end => format!(", line {ln_begin}"),
Location::RangePair {
ln_begin, ln_end, ..
}
| Location::Range {
Location::Range {
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::Unknown => "".to_string(),
};
@ -442,33 +499,37 @@ pub trait ErrorDisplay {
fn format_code_and_pointer(&self) -> String {
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 {
ln_begin,
col_begin,
ln_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 {
vec![self.input().reread()]
} else {
self.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()));
}
pointer += &"^".repeat(cmp::max(1, codes[i].len()));
res += &format!(
"{lineno}{VBAR_UNICODE} {code}\n{pointer}\n",
code = codes[i]
@ -476,9 +537,6 @@ pub trait ErrorDisplay {
}
res + RESET
}
Location::LineRange(_begin, _end) => {
todo!()
}
Location::Line(lineno) => {
let code = if self.input() == &Input::REPL {
self.input().reread()

View file

@ -87,6 +87,9 @@ macro_rules! enum_unwrap {
($ex: expr, $Enum: path :( $Cons: path :(_) ) $(,)*) => {{
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}
($ex: expr, $Enum: path {$($fields: ident $(,)*)*}) => {{
if let $Enum{$($fields,)*} = $ex { ($($fields,)*) } else { $crate::switch_unreachable!() }

View file

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

View file

@ -119,6 +119,13 @@ pub trait Stream<T>: Sized {
fn take_all(&mut self) -> Vec<T> {
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]
@ -400,7 +407,10 @@ pub trait Locational {
fn ln_begin(&self) -> Option<usize> {
match self.loc() {
Location::RangePair { ln_begin, .. }
Location::RangePair {
ln_first: (ln_begin, _),
..
}
| Location::Range { ln_begin, .. }
| Location::LineRange(ln_begin, _) => Some(ln_begin),
Location::Line(lineno) => Some(lineno),
@ -410,7 +420,10 @@ pub trait Locational {
fn ln_end(&self) -> Option<usize> {
match self.loc() {
Location::RangePair { ln_end, .. }
Location::RangePair {
ln_second: (_, ln_end),
..
}
| Location::Range { ln_end, .. }
| Location::LineRange(_, ln_end) => Some(ln_end),
Location::Line(lineno) => Some(lineno),

View file

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

View file

@ -1,6 +1,6 @@
[package]
name = "erg_compiler"
version = "0.3.2"
version = "0.4.0-beta.1"
description = "Centimetre: the Erg compiler"
authors = ["Shunsuke Shibayama <sbym1346@gmail.com>"]
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" ]
[dependencies]
erg_common = { version = "0.3.2", path = "../erg_common" }
erg_parser = { version = "0.3.2", path = "../erg_parser" }
erg_type = { version = "0.3.2", path = "../erg_type" }
erg_common = { version = "0.4.0-beta.1", path = "../erg_common" }
erg_parser = { version = "0.4.0-beta.1", path = "../erg_parser" }
erg_type = { version = "0.4.0-beta.1", path = "../erg_type" }
[lib]
path = "lib.rs"

View file

@ -11,26 +11,39 @@ use erg_common::opcode::Opcode;
use erg_common::traits::{Locational, Stream};
use erg_common::Str;
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 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_type::free::fresh_varname;
use erg_type::value::TypeKind;
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::context::eval::eval_lit;
use crate::error::{CompileError, CompileErrors, CompileResult};
use crate::eval::eval_lit;
use crate::hir::AttrDef;
use crate::hir::Attribute;
use crate::hir::{
Accessor, Args, Array, Block, Call, DefBody, Expr, Local, Signature, SubrSignature, Tuple,
VarSignature, HIR,
Accessor, Args, Array, Block, Call, ClassDef, DefBody, Expr, Identifier, Literal, PosArg,
Signature, SubrSignature, Tuple, VarSignature, HIR,
};
use AccessKind::*;
fn is_python_special(name: &str) -> bool {
match name {
"__call__" | "__init__" => true,
_ => false,
}
}
fn is_python_global(name: &str) -> bool {
match name {
"ArithmeticError"
@ -196,6 +209,7 @@ fn convert_to_python_attr(class: &str, uniq_obj_name: Option<&str>, name: Str) -
("Array!", _, "push!") => Str::ever("append"),
("Complex" | "Real" | "Int" | "Nat" | "Float", _, "Real") => Str::ever("real"),
("Complex" | "Real" | "Int" | "Nat" | "Float", _, "Imag") => Str::ever("imag"),
(_, _, "__new__") => Str::ever("__call__"),
("StringIO!", _, "getvalue!") => Str::ever("getvalue"),
("Module", Some("importlib"), "reload!") => Str::ever("reload"),
("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 {
let mut name = convert_to_python_attr(class, uniq_obj_name, name).to_string();
fn escape_attr(class: &str, uniq_obj_name: Option<&str>, ident: Identifier) -> Str {
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_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 {
@ -247,7 +267,7 @@ fn escape_name(ident: Identifier) -> Str {
let mut name = convert_to_python_name(ident.name.into_token().content).to_string();
name = name.replace('!', "__erg_proc__");
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)
} else {
Str::from("::".to_string() + &name)
@ -312,7 +332,7 @@ impl_stream_for_wrapper!(CodeGenStack, CodeGenUnit);
pub struct CodeGenerator {
cfg: ErgConfig,
str_cache: CacheSet<str>,
namedtuple_loaded: bool,
prelude_loaded: bool,
unit_size: usize,
units: CodeGenStack,
pub(crate) errs: CompileErrors,
@ -323,7 +343,7 @@ impl CodeGenerator {
Self {
cfg,
str_cache: CacheSet::new(),
namedtuple_loaded: false,
prelude_loaded: false,
unit_size: 0,
units: CodeGenStack::empty(),
errs: CompileErrors::empty(),
@ -439,7 +459,7 @@ impl CodeGenerator {
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();
if let Some(idx) = self
.cur_block_codeobj()
@ -447,11 +467,7 @@ impl CodeGenerator {
.iter()
.position(|n| &**n == name)
{
if current_is_toplevel || !acc_kind.is_local() {
Some(Name::local(idx))
} else {
Some(Name::global(idx))
}
Some(Name::local(idx))
} else if let Some(idx) = self
.cur_block_codeobj()
.varnames
@ -497,9 +513,8 @@ impl CodeGenerator {
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 name = escape_name(ident);
match self.rec_search(&name) {
Some(st @ (StoreLoadKind::Local | StoreLoadKind::Global)) => {
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 {
let name = Str::rc(name.split('.').last().unwrap());
let name = escape_attr(class, uniq_obj_name, name);
fn register_attr(&mut self, name: Str) -> Name {
self.mut_cur_block_codeobj().names.push(name);
Name::local(self.cur_block_codeobj().names.len() - 1)
}
fn register_method(&mut self, class: &str, uniq_obj_name: Option<&str>, name: Str) -> Name {
let name = Str::rc(name.split('.').last().unwrap());
let name = escape_attr(class, uniq_obj_name, name);
fn register_method(&mut self, name: Str) -> Name {
self.mut_cur_block_codeobj().names.push(name);
Name::local(self.cur_block_codeobj().names.len() - 1)
}
fn emit_load_name_instr(&mut self, ident: Identifier) -> CompileResult<()> {
log!(info "entered {}", fn_name!());
let escaped = escape_name(ident);
let name = self
.local_search(ident.inspect(), Name)
.unwrap_or_else(|| self.register_name(ident));
.local_search(&escaped, Name)
.unwrap_or_else(|| self.register_name(escaped));
let instr = match name.kind {
StoreLoadKind::Fast | StoreLoadKind::FastConst => Opcode::LOAD_FAST,
StoreLoadKind::Global | StoreLoadKind::GlobalConst => Opcode::LOAD_GLOBAL,
@ -561,9 +574,11 @@ impl CodeGenerator {
}
fn emit_import_name_instr(&mut self, ident: Identifier) -> CompileResult<()> {
log!(info "entered {}", fn_name!());
let escaped = escape_name(ident);
let name = self
.local_search(ident.inspect(), Name)
.unwrap_or_else(|| self.register_name(ident));
.local_search(&escaped, Name)
.unwrap_or_else(|| self.register_name(escaped));
self.write_instr(IMPORT_NAME);
self.write_arg(name.idx as u8);
self.stack_dec(); // (level + from_list) -> module object
@ -571,9 +586,11 @@ impl CodeGenerator {
}
fn emit_import_from_instr(&mut self, ident: Identifier) -> CompileResult<()> {
log!(info "entered {}", fn_name!());
let escaped = escape_name(ident);
let name = self
.local_search(ident.inspect(), Name)
.unwrap_or_else(|| self.register_name(ident));
.local_search(&escaped, Name)
.unwrap_or_else(|| self.register_name(escaped));
self.write_instr(IMPORT_FROM);
self.write_arg(name.idx as u8);
// self.stack_inc(); (module object) -> attribute
@ -584,11 +601,13 @@ impl CodeGenerator {
&mut self,
class: &str,
uniq_obj_name: Option<&str>,
name: Str,
ident: Identifier,
) -> CompileResult<()> {
log!(info "entered {} ({class}{ident})", fn_name!());
let escaped = escape_attr(class, uniq_obj_name, ident);
let name = self
.local_search(&name, Attr)
.unwrap_or_else(|| self.register_attr(class, uniq_obj_name, name));
.local_search(&escaped, Attr)
.unwrap_or_else(|| self.register_attr(escaped));
let instr = match name.kind {
StoreLoadKind::Fast | StoreLoadKind::FastConst => Opcode::LOAD_FAST,
StoreLoadKind::Global | StoreLoadKind::GlobalConst => Opcode::LOAD_GLOBAL,
@ -604,11 +623,13 @@ impl CodeGenerator {
&mut self,
class: &str,
uniq_obj_name: Option<&str>,
name: Str,
ident: Identifier,
) -> CompileResult<()> {
log!(info "entered {} ({class}{ident})", fn_name!());
let escaped = escape_attr(class, uniq_obj_name, ident);
let name = self
.local_search(&name, Method)
.unwrap_or_else(|| self.register_method(class, uniq_obj_name, name));
.local_search(&escaped, Method)
.unwrap_or_else(|| self.register_method(escaped));
let instr = match name.kind {
StoreLoadKind::Fast | StoreLoadKind::FastConst => Opcode::LOAD_FAST,
StoreLoadKind::Global | StoreLoadKind::GlobalConst => Opcode::LOAD_GLOBAL,
@ -621,13 +642,21 @@ impl CodeGenerator {
}
fn emit_store_instr(&mut self, ident: Identifier, acc_kind: AccessKind) {
let name = self
.local_search(ident.inspect(), acc_kind)
.unwrap_or_else(|| self.register_name(ident));
log!(info "entered {} ({ident})", fn_name!());
let escaped = escape_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 {
StoreLoadKind::Fast => Opcode::STORE_FAST,
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::Local | StoreLoadKind::LocalConst => {
match acc_kind {
@ -641,6 +670,25 @@ impl CodeGenerator {
self.write_instr(instr);
self.write_arg(name.idx as u8);
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) {
@ -675,39 +723,68 @@ impl CodeGenerator {
.non_defaults
.iter()
.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(
params
.defaults
.iter()
.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()
}
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_arg(0);
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(sig.inspect().clone());
self.emit_load_const(ident.inspect().clone());
self.write_instr(Opcode::MAKE_FUNCTION);
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_arg(2);
self.stack_dec_n((1 + 2) - 1);
self.emit_store_instr(sig.ident, Name);
self.write_arg(2 + subclasses_len as u8);
self.stack_dec_n((1 + 2 + subclasses_len) - 1);
self.emit_store_instr(ident, Name);
self.stack_dec();
}
// NOTE: use `TypeVar`, `Generic` in `typing` module
// fn emit_poly_type_def(&mut self, sig: SubrSignature, body: DefBody) {}
fn emit_var_def(&mut self, sig: VarSignature, mut body: DefBody) {
if body.is_type() {
return self.emit_mono_type_def(sig, body);
fn emit_require_type(&mut self, kind: TypeKind, require_or_sup: Expr) -> usize {
log!(info "entered {} ({kind:?}, {require_or_sup})", fn_name!());
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 {
self.codegen_expr(body.block.remove(0));
} else {
@ -716,7 +793,8 @@ impl CodeGenerator {
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 mut opcode_flag = 0u8;
let params = self.gen_param_names(&sig.params);
@ -732,7 +810,11 @@ impl CodeGenerator {
self.write_arg(cellvars_len);
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_arg(opcode_flag);
// stack_dec: <code obj> + <name> -> <function>
@ -741,6 +823,7 @@ impl CodeGenerator {
}
fn emit_discard_instr(&mut self, mut args: Args) -> CompileResult<()> {
log!(info "entered {}", fn_name!());
while let Some(arg) = args.try_remove(0) {
self.codegen_expr(arg);
self.emit_pop_top();
@ -749,6 +832,7 @@ impl CodeGenerator {
}
fn emit_if_instr(&mut self, mut args: Args) -> CompileResult<()> {
log!(info "entered {}", fn_name!());
let cond = args.remove(0);
self.codegen_expr(cond);
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<()> {
log!(info "entered {}", fn_name!());
let iterable = args.remove(0);
self.codegen_expr(iterable);
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<()> {
log!(info "entered {}", fn_name!());
let expr = args.remove(0);
self.codegen_expr(expr);
let len = args.len();
@ -855,10 +941,11 @@ impl CodeGenerator {
}
fn emit_match_pattern(&mut self, pat: ParamPattern) -> CompileResult<Vec<usize>> {
log!(info "entered {}", fn_name!());
let mut pop_jump_points = vec![];
match pat {
ParamPattern::VarName(name) => {
let ident = Identifier::new(None, name);
let ident = Identifier::bare(None, name);
self.emit_store_instr(ident, AccessKind::Name);
}
ParamPattern::Lit(lit) => {
@ -908,19 +995,24 @@ impl CodeGenerator {
}
fn emit_call(&mut self, call: Call) {
log!(info "entered {} ({call})", fn_name!());
if let Some(method_name) = call.method_name {
self.emit_call_method(*call.obj, method_name, call.args);
} else {
match *call.obj {
Expr::Accessor(Accessor::Local(local)) => {
self.emit_call_local(local, call.args).unwrap()
Expr::Accessor(Accessor::Ident(ident)) if ident.vis().is_private() => {
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()[..] {
"assert" => self.emit_assert_instr(args),
"discard" => self.emit_discard_instr(args),
@ -928,54 +1020,50 @@ impl CodeGenerator {
"if" | "if!" => self.emit_if_instr(args),
"match" | "match!" => self.emit_match_instr(args, true),
_ => {
let name = VarName::new(local.name);
let ident = Identifier::new(None, name);
self.emit_load_name_instr(ident).unwrap_or_else(|e| {
self.emit_load_name_instr(local).unwrap_or_else(|e| {
self.errs.push(e);
});
let argc = args.len();
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);
self.emit_args(args, Name);
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 uniq_obj_name = obj.__name__().map(Str::rc);
self.codegen_expr(obj);
self.emit_load_method_instr(
&class,
uniq_obj_name.as_ref().map(|s| &s[..]),
method_name.content,
)
.unwrap_or_else(|err| {
self.errs.push(err);
});
self.emit_load_method_instr(&class, uniq_obj_name.as_ref().map(|s| &s[..]), method_name)
.unwrap_or_else(|err| {
self.errs.push(err);
});
self.emit_args(args, Method);
}
fn emit_args(&mut self, mut args: Args, kind: AccessKind) {
let argc = args.len();
let pos_len = args.pos_args.len();
let mut kws = Vec::with_capacity(args.kw_len());
while let Some(arg) = args.try_remove_pos(0) {
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) {
kws.push(ValueObj::Str(arg.keyword.content.clone()));
self.codegen_expr(arg.expr);
@ -984,18 +1072,49 @@ impl CodeGenerator {
let kws_tuple = ValueObj::from(kws);
self.emit_load_const(kws_tuple);
self.write_instr(CALL_FUNCTION_KW);
self.write_arg(argc as u8);
1
} 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
};
self.write_arg(argc as u8);
// (1 (method) + argc + kwsc) input objects -> 1 return object
// (1 (subroutine) + argc + kwsc) input objects -> 1 return object
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)
fn emit_assert_instr(&mut self, mut args: Args) -> CompileResult<()> {
log!(info "entered {}", fn_name!());
self.codegen_expr(args.remove(0));
let pop_jump_point = self.cur_block().lasti;
self.write_instr(Opcode::POP_JUMP_IF_TRUE);
@ -1016,6 +1135,7 @@ impl CodeGenerator {
}
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 {
let sd = self.cur_block().lasti - self.cur_block().prev_lasti;
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::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),
},
Expr::ClassDef(class) => self.emit_class_def(class),
Expr::AttrDef(attr) => self.emit_attr_def(attr),
// TODO:
Expr::Lambda(lambda) => {
let params = self.gen_param_names(&lambda.params);
@ -1193,20 +1315,6 @@ impl CodeGenerator {
},
Expr::Record(rec) => {
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
let ident = Identifier::private(Str::ever("#NamedTuple"));
self.emit_load_name_instr(ident).unwrap();
@ -1252,15 +1360,9 @@ impl CodeGenerator {
}
fn codegen_acc(&mut self, acc: Accessor) {
log!(info "entered {} ({acc})", fn_name!());
match acc {
Accessor::Local(local) => {
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));
Accessor::Ident(ident) => {
self.emit_load_name_instr(ident).unwrap_or_else(|err| {
self.errs.push(err);
});
@ -1268,15 +1370,27 @@ impl CodeGenerator {
Accessor::Attr(a) => {
let class = a.obj.ref_t().name();
let uniq_obj_name = a.obj.__name__().map(Str::rc);
self.codegen_expr(*a.obj);
self.emit_load_attr_instr(
&class,
uniq_obj_name.as_ref().map(|s| &s[..]),
a.name.content.clone(),
)
.unwrap_or_else(|err| {
self.errs.push(err);
});
// C = Class ...
// C.
// a = C.x
// ↓
// class C:
// a = x
if Some(&self.cur_block_codeobj().name[..]) != a.obj.__name__() {
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) => {
self.codegen_expr(*t_attr.obj);
@ -1297,6 +1411,7 @@ impl CodeGenerator {
/// forブロックなどで使う
fn codegen_frameless_block(&mut self, block: Block, params: Vec<Str>) {
log!(info "entered {}", fn_name!());
for param in params {
self.emit_store_instr(Identifier::private(param), Name);
}
@ -1311,23 +1426,50 @@ impl CodeGenerator {
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;
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.unit_size,
vec![],
Str::rc(self.cfg.input.enclosed_name()),
&name,
block[0].ln_begin().unwrap(),
firstlineno,
));
let mod_name = self.toplevel_block_codeobj().name.clone();
self.emit_load_const(mod_name);
self.emit_store_instr(Identifier::public("__module__"), Attr);
self.emit_load_const(name);
self.emit_store_instr(Identifier::public("__qualname__"), Attr);
// TODO: サブルーチンはT.subという書式でSTORE
for expr in block.into_iter() {
self.codegen_expr(expr);
self.emit_store_instr(Identifier::public("__module__"), Name);
self.emit_load_const(name.clone());
self.emit_store_instr(Identifier::public("__qualname__"), Name);
self.emit_init_method(&class.sig, class.__new__.clone());
if class.need_to_gen_new {
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
if self.cur_block().stack_len == 1 {
self.emit_pop_top();
@ -1366,7 +1508,102 @@ impl CodeGenerator {
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 {
log!(info "entered {}", fn_name!());
self.unit_size += 1;
let name = if let Some(name) = opt_name {
name
@ -1414,7 +1651,10 @@ impl CodeGenerator {
// end of flagging
let unit = self.units.pop().unwrap();
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 let Some(l) = self.mut_cur_block_codeobj().lnotab.last_mut() {
*l += ld as u8;
@ -1425,6 +1665,25 @@ impl CodeGenerator {
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 {
log!(info "the code-generating process has started.{RESET}");
self.unit_size += 1;
@ -1435,6 +1694,10 @@ impl CodeGenerator {
"<module>",
1,
));
if !self.prelude_loaded {
self.load_prelude();
self.prelude_loaded = true;
}
let mut print_point = 0;
if self.input().is_repl() {
print_point = self.cur_block().lasti;

View file

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

View file

@ -1,7 +1,7 @@
//! provides type-comparison
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::{Constraint, Cyclicity, FreeKind, FreeTyVar};
use erg_type::typaram::{TyParam, TyParamOrdering};
@ -50,9 +50,7 @@ impl Context {
pub(crate) fn eq_tp(&self, lhs: &TyParam, rhs: &TyParam) -> bool {
match (lhs, rhs) {
(TyParam::Type(lhs), TyParam::Type(rhs)) => {
return self.structural_same_type_of(lhs, rhs)
}
(TyParam::Type(lhs), TyParam::Type(rhs)) => return self.same_type_of(lhs, rhs),
(TyParam::Mono(l), TyParam::Mono(r)) => {
if let (Some(l), Some(r)) = (self.rec_get_const_obj(l), self.rec_get_const_obj(r)) {
return l == r;
@ -61,6 +59,23 @@ impl Context {
(TyParam::MonoQVar(name), _other) | (_other, TyParam::MonoQVar(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 {
name: ln,
@ -80,19 +95,21 @@ impl Context {
}
(TyParam::FreeVar(fv), other) | (other, TyParam::FreeVar(fv)) => match &*fv.borrow() {
FreeKind::Linked(t) | FreeKind::UndoableLinked { t, .. } => {
return self.eq_tp(t, other)
return self.eq_tp(t, other);
}
FreeKind::Unbound { constraint, .. }
| FreeKind::NamedUnbound { constraint, .. } => {
let t = constraint.get_type().unwrap();
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.
@ -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) {
if lhs == rhs {
return (Absolutely, true);
}
match (lhs, rhs) {
// FIXME: Obj/Neverはクラス、Top/Bottomは構造型
(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, Nat)
| (Float | Ratio | Int, Int)
@ -164,14 +185,9 @@ impl Context {
),
(Type, Subr(subr)) => (
Absolutely,
subr.kind
.self_t()
.map(|t| self.supertype_of(&Type, t))
.unwrap_or(true)
&& subr
.non_default_params
.iter()
.all(|pt| self.supertype_of(&Type, &pt.typ()))
subr.non_default_params
.iter()
.all(|pt| self.supertype_of(&Type, &pt.typ()))
&& subr
.default_params
.iter()
@ -184,44 +200,30 @@ impl Context {
&& self.supertype_of(&Type, &subr.return_t),
),
(
Type::MonoClass(n),
Type::Mono(n),
Subr(SubrType {
kind: SubrKind::Func,
..
}),
) if &n[..] == "GenericFunc" => (Absolutely, true),
(
Type::MonoClass(n),
Type::Mono(n),
Subr(SubrType {
kind: SubrKind::Proc,
..
}),
) if &n[..] == "GenericProc" => (Absolutely, true),
(
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, .. })
(Type::Mono(l), Type::Poly { name: r, .. })
if &l[..] == "GenericArray" && &r[..] == "Array" =>
{
(Absolutely, true)
}
(Type::MonoClass(l), Type::PolyClass { name: r, .. })
(Type::Mono(l), Type::Poly { name: r, .. })
if &l[..] == "GenericDict" && &r[..] == "Dict" =>
{
(Absolutely, true)
}
(Type::MonoClass(l), Type::MonoClass(r))
(Type::Mono(l), Type::Mono(r))
if &l[..] == "GenericCallable"
&& (&r[..] == "GenericFunc"
|| &r[..] == "GenericProc"
@ -230,11 +232,11 @@ impl Context {
{
(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),
_ => (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),
_ => (Maybe, false),
}
@ -258,7 +260,7 @@ impl Context {
}
_ => {}
}
match self.trait_supertype_of(lhs, rhs) {
match self.traits_supertype_of(lhs, rhs) {
(Absolutely, judge) => {
self.register_cache(rhs, lhs, judge);
return judge;
@ -292,20 +294,19 @@ impl Context {
}
fn classes_supertype_of(&self, lhs: &Type, rhs: &Type) -> (Credibility, bool) {
if !lhs.is_class() || !rhs.is_class() {
return (Maybe, false);
}
for (rhs_sup, _) in self.rec_get_nominal_super_class_ctxs(rhs) {
match self.cheap_supertype_of(lhs, rhs_sup) {
(Absolutely, true) => {
return (Absolutely, true);
}
(Maybe, _) => {
if self.structural_supertype_of(lhs, rhs_sup) {
if let Some(sup_classes) = self.rec_get_nominal_super_class_ctxs(rhs) {
for (rhs_sup, _) in sup_classes {
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);
}
}
_ => {}
}
_ => {}
}
}
(Maybe, false)
@ -313,22 +314,21 @@ impl Context {
// e.g. Eq(Nat) :> Nat
// Nat.super_traits = [Add(Nat), Eq(Nat), ...]
fn trait_supertype_of(&self, lhs: &Type, rhs: &Type) -> (Credibility, bool) {
if !lhs.is_trait() {
return (Maybe, false);
}
for (rhs_sup, _) in self.rec_get_nominal_super_trait_ctxs(rhs) {
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) {
fn traits_supertype_of(&self, lhs: &Type, rhs: &Type) -> (Credibility, bool) {
if let Some(sup_traits) = self.rec_get_nominal_super_trait_ctxs(rhs) {
for (rhs_sup, _) in sup_traits {
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);
}
}
_ => {}
}
_ => {}
}
}
(Maybe, false)
@ -339,7 +339,7 @@ impl Context {
/// assert sup_conforms(?E(<: Eq(?R)), base: T, sup_trait: Eq(U))
/// ```
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);
let judge = self.supertype_of(&sup, sup_trait);
free.undo();
@ -349,7 +349,7 @@ impl Context {
/// assert!(sup_conforms(?E(<: Eq(?E)), {Nat, Eq(Nat)}))
/// assert!(sup_conforms(?E(<: Eq(?R)), {Nat, Eq(T)}))
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}");
free.forced_undoable_link(&inst_pair.sub_type);
log!(info "{free}");
@ -371,7 +371,7 @@ impl Context {
pub(crate) fn structural_supertype_of(&self, lhs: &Type, rhs: &Type) -> bool {
log!(info "structural_supertype_of:\nlhs: {lhs}\nrhs: {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 = || {
for lpt in ls.default_params.iter() {
if let Some(rpt) = rs
@ -388,9 +388,6 @@ impl Context {
}
true
};
if ls.kind.self_t().is_some() {
todo!("method type is not supported yet")
}
// () -> Never <: () -> Int <: () -> Object
// (Object) -> Int <: (Int) -> Int <: (Never) -> Int
ls.non_default_params.len() == rs.non_default_params.len()
@ -405,24 +402,20 @@ impl Context {
&& kw_check()
// contravariant
}
// RefMut, OptionMut are invariant
(Ref(lhs), Ref(rhs)) => self.supertype_of(lhs, rhs),
// ?T(<: Nat) !:> ?U(:> Int)
// ?T(<: Nat) :> ?U(<: Int) (?U can be smaller than ?T)
(FreeVar(lfv), FreeVar(rfv)) => {
match (lfv.crack_bound_types(), rfv.crack_bound_types()) {
(Some((_, l_sup)), Some((r_sub, _))) => self.supertype_of(&l_sup, &r_sub),
_ => {
if lfv.is_linked() {
self.supertype_of(&lfv.crack(), rhs)
} else if rfv.is_linked() {
self.supertype_of(lhs, &rfv.crack())
} else {
false
}
(FreeVar(lfv), FreeVar(rfv)) => match (lfv.get_bound_types(), rfv.get_bound_types()) {
(Some((_, l_sup)), Some((r_sub, _))) => self.supertype_of(&l_sup, &r_sub),
_ => {
if lfv.is_linked() {
self.supertype_of(&lfv.crack(), rhs)
} else if rfv.is_linked() {
self.supertype_of(lhs, &rfv.crack())
} else {
false
}
}
}
},
// 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
(FreeVar(lfv), rhs) => {
@ -496,7 +489,18 @@ impl Context {
}
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
// ({I: Int | I >= 0} :> {N: Int | N >= 0}) == true,
// ({I: Int | I >= 0} :> {I: Int | I >= 1}) == true,
@ -571,30 +575,18 @@ impl Context {
}
(_lhs, Not(_, _)) => todo!(),
(Not(_, _), _rhs) => todo!(),
// RefMut are invariant
(Ref(l), Ref(r)) => self.supertype_of(l, r),
// TはすべてのRef(T)のメソッドを持つので、Ref(T)のサブタイプ
// 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,
params: lparams,
},
PolyClass {
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 {
Poly {
name: rn,
params: rparams,
},
@ -619,15 +611,18 @@ impl Context {
pub(crate) fn cyclic_supertype_of(&self, lhs: &FreeTyVar, rhs: &Type) -> bool {
// if `rhs` is {S: Str | ... }, `defined_rhs` will be Str
let (defined_rhs, _) = self.rec_get_nominal_type_ctx(rhs).unwrap();
let super_traits = self.rec_get_nominal_super_trait_ctxs(rhs);
for (sup_trait, _) in super_traits.into_iter() {
if self.sup_conforms(lhs, defined_rhs, sup_trait) {
return true;
if let Some(super_traits) = self.rec_get_nominal_super_trait_ctxs(rhs) {
for (sup_trait, _) in super_traits {
if self.sup_conforms(lhs, defined_rhs, sup_trait) {
return true;
}
}
}
for (sup_class, _) in self.rec_get_nominal_super_class_ctxs(rhs) {
if self.cyclic_supertype_of(lhs, sup_class) {
return true;
if let Some(sup_classes) = self.rec_get_nominal_super_class_ctxs(rhs) {
for (sup_class, _) in sup_classes {
if self.cyclic_supertype_of(lhs, sup_class) {
return true;
}
}
}
false
@ -666,7 +661,7 @@ impl Context {
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)
}
@ -676,7 +671,7 @@ impl Context {
l.try_cmp(r).map(Into::into),
// TODO: 型を見て判断する
(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)
} else { Some(Any) }
},
@ -690,8 +685,8 @@ impl Context {
l @ (TyParam::FreeVar(_) | TyParam::Erased(_) | TyParam::MonoQVar(_)),
r @ (TyParam::FreeVar(_) | TyParam::Erased(_) | TyParam::MonoQVar(_)),
) /* if v.is_unbound() */ => {
let l_t = self.eval.get_tp_t(l, self).unwrap();
let r_t = self.eval.get_tp_t(r, self).unwrap();
let l_t = self.get_tp_t(l).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) {
Some(Any)
} else { Some(NotEqual) }
@ -702,7 +697,7 @@ impl Context {
// try_cmp((n: 2.._), 1) -> Some(Greater)
// try_cmp((n: -1.._), 1) -> Some(Any)
(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 sup = self.rec_sup(&t);
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 {
match (
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
/// ```python
/// assert is_super_pred({I >= 0}, {I == 0})
@ -888,7 +905,7 @@ impl Context {
#[inline]
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を実装しない

View file

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

View file

@ -10,7 +10,7 @@ impl Context {
if fv.is_linked() {
fv.crack().clone()
} else {
let (_sub, sup) = fv.crack_bound_types().unwrap();
let (_sub, sup) = fv.get_bound_types().unwrap();
sup
}
} 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 {
pub(crate) fn init_py_importlib_mod() -> Self {
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
}
}

View file

@ -1,7 +1,7 @@
use erg_common::vis::Visibility;
use erg_common::Str;
use erg_type::constructors::{class, pr0_met};
use erg_type::constructors::{mono, pr0_met, ref_};
use erg_type::Type;
use Type::*;
@ -14,13 +14,13 @@ impl Context {
pub(crate) fn init_py_io_mod() -> Self {
let mut io = Context::module("io".into(), 15);
let mut string_io = Context::mono_class(Str::ever("StringIO!"), vec![Obj], vec![], 0);
string_io.register_impl(
string_io.register_builtin_impl(
"getvalue!",
pr0_met(class("StringIO!"), None, Str),
pr0_met(ref_(mono("StringIO!")), Str),
Immutable,
Public,
);
io.register_type(class("StringIO!"), string_io, Const);
io.register_builtin_type(mono("StringIO!"), string_io, Const);
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_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 Type::*;
@ -15,13 +15,13 @@ use Visibility::*;
impl Context {
pub(crate) fn init_py_random_mod() -> Self {
let mut random = Context::module("random".into(), 10);
random.register_impl(
random.register_builtin_impl(
"seed!",
proc(
vec![],
None,
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),
],
NoneType,
@ -29,19 +29,19 @@ impl Context {
Immutable,
Public,
);
random.register_impl(
random.register_builtin_impl(
"randint!",
nd_proc(vec![param_t("a", Int), param_t("b", Int)], None, Int),
Immutable,
Public,
);
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,
mono_q("T"),
);
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
}
}

View file

@ -1,7 +1,7 @@
use erg_common::vis::Visibility;
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 Type::*;
@ -14,7 +14,7 @@ impl Context {
pub(crate) fn init_py_socket_mod() -> Self {
let mut socket = Context::module("socket".into(), 15);
let mut sock = Context::mono_class(Str::ever("Socket!"), vec![Obj], vec![], 0);
sock.register_impl(
sock.register_builtin_impl(
"new",
func(
vec![],
@ -25,12 +25,12 @@ impl Context {
param_t("proto", Int),
param_t("fileno", option(Int)),
],
class("Socket!"),
mono("Socket!"),
),
Immutable,
Public,
);
socket.register_type(class("Socket!"), sock, Const);
socket.register_builtin_type(mono("Socket!"), sock, Const);
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 {
pub(crate) fn init_py_time_mod() -> Self {
let mut time = Context::module("time".into(), 15);
time.register_impl("sleep!", proc1(Float, NoneType), Immutable, Public);
time.register_impl("time!", proc0(Float), Immutable, Public);
time.register_builtin_impl("sleep!", proc1(Float, NoneType), Immutable, Public);
time.register_builtin_impl("time!", proc0(Float), Immutable, Public);
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
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::set::Set;
use erg_common::traits::Locational;
@ -11,16 +11,14 @@ use erg_common::{enum_unwrap, fmt_option, fmt_slice, log, set};
use Type::*;
use ast::VarName;
use erg_parser::ast;
use erg_parser::ast::{self, Identifier};
use erg_parser::token::Token;
use erg_type::constructors::{
class, func, mono_proj, poly_class, ref_, ref_mut, refinement, subr_t,
};
use erg_type::constructors::{func, mono, mono_proj, poly, ref_, ref_mut, refinement, subr_t};
use erg_type::free::Constraint;
use erg_type::typaram::TyParam;
use erg_type::value::ValueObj;
use erg_type::{HasType, ParamTy, SubrKind, SubrType, TyBound, Type};
use erg_type::value::{GenTypeObj, TypeObj, ValueObj};
use erg_type::{HasType, ParamTy, TyBound, Type};
use crate::context::instantiate::ConstTemplate;
use crate::context::{Context, ContextKind, RegistrationMode, TraitInstance, Variance};
@ -72,6 +70,18 @@ impl Context {
})
.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(
@ -81,17 +91,17 @@ impl Context {
namespace: &Str,
) -> TyCheckResult<&Context> {
match obj {
hir::Expr::Accessor(hir::Accessor::Local(name)) => {
hir::Expr::Accessor(hir::Accessor::Ident(ident)) => {
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)
} else {
Err(TyCheckError::no_var_error(
line!() as usize,
obj.loc(),
namespace.clone(),
name.inspect(),
self.get_similar_name(name.inspect()),
ident.inspect(),
self.get_similar_name(ident.inspect()),
))
}
} else {
@ -119,9 +129,9 @@ impl Context {
pos_arg.loc(),
self.caused_by(),
"match",
&class("LambdaFunc"),
&mono("LambdaFunc"),
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()) {
return Some(ctx.name.clone());
}
if let Some((_, ctx)) = self.rec_get_type(name.inspect()) {
return Some(ctx.name.clone());
}
None
}
pub(crate) fn rec_get_var_t(
&self,
name: &Token,
vis: Visibility,
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,
))
}
pub(crate) fn rec_get_var_t(&self, ident: &Identifier, namespace: &Str) -> TyCheckResult<Type> {
if let Some(vi) = self.get_current_scope_var(&ident.inspect()[..]) {
self.validate_visibility(ident, vi, namespace)?;
Ok(vi.t())
} else {
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(
line!() as usize,
name.loc(),
ident.loc(),
namespace.clone(),
name.inspect(),
self.get_similar_name(name.inspect()),
ident.inspect(),
self.get_similar_name(ident.inspect()),
))
}
}
@ -222,43 +221,48 @@ impl Context {
pub(crate) fn rec_get_attr_t(
&self,
obj: &hir::Expr,
name: &Token,
ident: &Identifier,
namespace: &Str,
) -> TyCheckResult<Type> {
let self_t = obj.t();
match self_t {
Type => todo!(),
Type::Record(rec) => {
// REVIEW: `rec.get(name.inspect())` returns None (Borrow<Str> is implemented for Field). Why?
if let Some(attr) = rec.get(&Field::new(Public, name.inspect().clone())) {
return Ok(attr.clone());
} else {
let t = Type::Record(rec);
return Err(TyCheckError::no_attr_error(
line!() as usize,
name.loc(),
namespace.clone(),
&t,
name.inspect(),
self.get_similar_attr(&t, name.inspect()),
));
let name = ident.name.token();
match self.get_attr_t_from_attributive_t(obj, &self_t, ident, namespace) {
Ok(t) => {
return Ok(t);
}
Err(e) if e.core.kind == ErrorKind::DummyError => {}
Err(e) => {
return Err(e);
}
}
if let Some(singular_ctx) = self.rec_get_singular_ctx(obj) {
match singular_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);
}
}
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) {
if let Ok(t) = ctx.rec_get_var_t(name, Public, namespace) {
return Ok(t);
for (_, ctx) in self
.rec_get_nominal_super_type_ctxs(&self_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
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 {
Err(TyCheckError::no_attr_error(
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全体の型を返す
fn search_callee_t(
&self,
obj: &hir::Expr,
method_name: &Option<Token>,
method_name: &Option<Identifier>,
namespace: &Str,
) -> TyCheckResult<Type> {
if let Some(method_name) = method_name.as_ref() {
for (_, ctx) in self.rec_get_nominal_super_type_ctxs(obj.ref_t()) {
if let Some(vi) = ctx.locals.get(method_name.inspect()) {
return Ok(vi.t());
} else if let Some(vi) = ctx.decls.get(method_name.inspect()) {
for (_, ctx) in self
.rec_get_nominal_super_type_ctxs(obj.ref_t())
.ok_or_else(|| todo!())?
{
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());
}
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(vi) = ctx.locals.get(method_name.inspect()) {
return Ok(vi.t());
} else if let Some(vi) = ctx.decls.get(method_name.inspect()) {
if let Some(singular_ctx) = self.rec_get_singular_ctx(obj) {
if let Some(vi) = singular_ctx
.locals
.get(method_name.inspect())
.or_else(|| singular_ctx.decls.get(method_name.inspect()))
{
self.validate_visibility(method_name, vi, namespace)?;
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(
line!() as usize,
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(
&self,
op: &Token,
@ -325,14 +453,17 @@ impl Context {
erg_common::debug_power_assert!(args.len() == 2);
let cont = binop_to_dname(op.inspect());
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 op = hir::Expr::Accessor(hir::Accessor::local(symbol, t));
let t = self.rec_get_var_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)
.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 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()で上書きする
let core = ErrorCore::new(
e.core.errno,
@ -354,13 +485,16 @@ impl Context {
erg_common::debug_power_assert!(args.len() == 1);
let cont = unaryop_to_dname(op.inspect());
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 op = hir::Expr::Accessor(hir::Accessor::local(symbol, t));
let t = self.rec_get_var_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)
.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 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(
e.core.errno,
e.core.kind,
@ -374,15 +508,17 @@ impl Context {
/// 可変依存型の変更を伝搬させる
fn propagate(&self, t: &Type, callee: &hir::Expr) -> TyCheckResult<()> {
if let Type::Subr(SubrType {
kind: SubrKind::ProcMethod {
after: Some(after), ..
},
..
}) = t
{
log!(info "{}, {}", callee.ref_t(), after);
self.reunify(callee.ref_t(), after, Some(callee.loc()), None)?;
if let Type::Subr(subr) = t {
if let Some(after) = subr.self_t().and_then(|self_t| {
if let RefMut { after, .. } = self_t {
after.as_ref()
} else {
None
}
}) {
log!(info "{}, {}", callee.ref_t(), after);
self.reunify(callee.ref_t(), after, Some(callee.loc()), None)?;
}
}
Ok(())
}
@ -415,14 +551,14 @@ impl Context {
}
);
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);
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_params = params.clone();
let maybe_trait = Type::PolyTrait { name, params };
let maybe_trait = Type::Poly { name, params };
let mut min = Type::Obj;
for pair in self.rec_get_trait_impls(&t_name) {
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 {
Ok(min)
}
@ -491,9 +627,14 @@ impl Context {
let new_t = self.resolve_trait(*t)?;
Ok(ref_(new_t))
}
Type::RefMut(t) => {
let new_t = self.resolve_trait(*t)?;
Ok(ref_mut(new_t))
Type::RefMut { before, after } => {
let new_before = self.resolve_trait(*before)?;
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::And(_, _) | Type::Or(_, _) | Type::Not(_, _) => todo!(),
@ -511,15 +652,25 @@ impl Context {
fn substitute_call(
&self,
obj: &hir::Expr,
method_name: &Option<Token>,
method_name: &Option<Identifier>,
instance: &Type,
pos_args: &[hir::PosArg],
kw_args: &[hir::KwArg],
) -> TyCheckResult<()> {
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) => {
let callee = if let Some(name) = method_name {
let attr = hir::Attribute::new(obj.clone(), name.clone(), Type::Ellipsis);
let callee = if let Some(ident) = method_name {
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));
acc
} else {
@ -540,12 +691,34 @@ impl Context {
));
}
let mut passed_params = set! {};
if pos_args.len() >= subr.non_default_params.len() {
let (non_default_args, var_args) =
pos_args.split_at(subr.non_default_params.len());
for (nd_arg, nd_param) in
non_default_args.iter().zip(subr.non_default_params.iter())
let non_default_params_len = if method_name.is_some() {
subr.non_default_params.len() - 1
} else {
subr.non_default_params.len()
};
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(
&callee,
&nd_arg.expr,
@ -609,7 +782,7 @@ impl Context {
log!(err "semi-unification failed with {callee}\n{arg_t} !<: {param_t}");
log!(err "errno: {}", e.core.errno);
// 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("");
TyCheckError::type_mismatch_error(
line!() as usize,
@ -650,7 +823,7 @@ impl Context {
log!(err "semi-unification failed with {callee}\n{arg_t} !<: {param_t}");
log!(err "errno: {}", e.core.errno);
// 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("");
TyCheckError::type_mismatch_error(
line!() as usize,
@ -693,7 +866,7 @@ impl Context {
log!(err "semi-unification failed with {callee}\n{arg_t} !<: {}", pt.typ());
log!(err "errno: {}", e.core.errno);
// 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);
TyCheckError::type_mismatch_error(
line!() as usize,
@ -720,21 +893,23 @@ impl Context {
pub(crate) fn get_call_t(
&self,
obj: &hir::Expr,
method_name: &Option<Token>,
method_name: &Option<Identifier>,
pos_args: &[hir::PosArg],
kw_args: &[hir::KwArg],
namespace: &Str,
) -> TyCheckResult<Type> {
match obj {
hir::Expr::Accessor(hir::Accessor::Local(local)) if &local.inspect()[..] == "match" => {
return self.get_match_call_t(pos_args, kw_args)
hir::Expr::Accessor(hir::Accessor::Ident(local))
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)?;
log!(
"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)?;
log!(
@ -744,7 +919,8 @@ impl Context {
);
self.substitute_call(obj, method_name, &instance, pos_args, kw_args)?;
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");
self.propagate(&res, obj)?;
log!(info "Propagated:\nres: {res}\n");
@ -777,7 +953,10 @@ impl Context {
namespace: &Str,
) -> TyCheckResult<ValueObj> {
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) {
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> {
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) {
return Some(name);
}
@ -943,49 +1122,40 @@ impl Context {
pub(crate) fn rec_get_nominal_super_trait_ctxs<'a>(
&'a self,
t: &Type,
) -> impl Iterator<Item = (&'a Type, &'a Context)> {
if let Some((_ctx_t, ctx)) = self.rec_get_nominal_type_ctx(t) {
ctx.super_traits.iter().map(|sup| {
let (_t, sup_ctx) = self.rec_get_nominal_type_ctx(sup).unwrap();
(sup, sup_ctx)
})
} else {
todo!("{t} has no trait, or not a nominal type")
}
) -> Option<impl Iterator<Item = (&'a Type, &'a Context)>> {
let (_ctx_t, ctx) = self.rec_get_nominal_type_ctx(t)?;
Some(ctx.super_traits.iter().map(|sup| {
let (_t, sup_ctx) = self.rec_get_nominal_type_ctx(sup).unwrap();
(sup, sup_ctx)
}))
}
pub(crate) fn rec_get_nominal_super_class_ctxs<'a>(
&'a self,
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
// 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) {
// 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 | ...})
ctx.super_classes.iter().map(|sup| {
let (_t, sup_ctx) = self.rec_get_nominal_type_ctx(sup).unwrap();
(sup, sup_ctx)
})
} else {
todo!("{t} has no class, or not a nominal type")
}
let (_ctx_t, ctx) = self.rec_get_nominal_type_ctx(t)?;
// t: {S: Str | ...} => ctx.super_traits: [Eq(Str), Mul(Nat), ...]
// => return: [(Str, Eq(Str)), (Str, Mul(Nat)), ...] (the content of &'a Type isn't {S: Str | ...})
Some(ctx.super_classes.iter().map(|sup| {
let (_t, sup_ctx) = self.rec_get_nominal_type_ctx(sup).unwrap();
(sup, sup_ctx)
}))
}
pub(crate) fn rec_get_nominal_super_type_ctxs<'a>(
&'a self,
t: &Type,
) -> impl Iterator<Item = (&'a Type, &'a Context)> {
if let Some((t, ctx)) = self.rec_get_nominal_type_ctx(t) {
vec![(t, ctx)].into_iter().chain(
ctx.super_classes
.iter()
.chain(ctx.super_traits.iter())
.map(|sup| self.rec_get_nominal_type_ctx(&sup).unwrap()),
)
} else {
todo!("{t} not found")
}
) -> Option<impl Iterator<Item = (&'a Type, &'a Context)>> {
let (t, ctx) = self.rec_get_nominal_type_ctx(t)?;
let sups = ctx
.super_classes
.iter()
.chain(ctx.super_traits.iter())
.map(|sup| self.rec_get_nominal_type_ctx(&sup).unwrap());
Some(vec![(t, ctx)].into_iter().chain(sups))
}
pub(crate) fn rec_get_nominal_type_ctx<'a>(
@ -993,32 +1163,52 @@ impl Context {
typ: &Type,
) -> Option<(&'a Type, &'a Context)> {
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) => {
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(_) => {
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: _ } => {
if let Some((t, ctx)) = self.poly_classes.get(name) {
Type::Poly { name, params: _ } => {
if let Some((t, ctx)) = self.rec_get_poly_type(name) {
return Some((t, ctx));
}
}
Type::PolyTrait { name, params: _ } => {
if let Some((t, ctx)) = self.poly_traits.get(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);
}
}
Type::Record(rec) if rec.values().all(|attr| self.supertype_of(&Type, attr)) => {
return self.rec_get_nominal_type_ctx(&Type)
}
}*/
// FIXME: `F()`などの場合、実際は引数が省略されていても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));
}
}
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 {
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> {
match obj.ref_t() {
// TODO: attr
Type::Module => self.rec_get_mod(&obj.var_full_name()?),
Type::Class => todo!(),
Type::Module => self.rec_get_mod(&obj.show_acc()?),
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::Refinement(refine) => {
self.rec_get_nominal_type_ctx(&refine.t).map(|(_, ctx)| ctx)
}
_ => None,
}
}
@ -1073,8 +1334,14 @@ impl Context {
// rec_get_const_localとは違い、位置情報を持たないしエラーとならない
pub(crate) fn rec_get_const_obj(&self, name: &str) -> Option<&ValueObj> {
if let Some(val) = self.consts.get(name) {
Some(val)
} else if let Some(outer) = &self.outer {
return Some(val);
}
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)
} else {
None
@ -1083,12 +1350,123 @@ impl Context {
pub(crate) fn rec_get_const_param_defaults(&self, name: &str) -> Option<&Vec<ConstTemplate>> {
if let Some(impls) = self.const_param_defaults.get(name) {
return Some(impls);
}
if let Some(outer) = &self.outer {
Some(impls)
} else if let Some(outer) = &self.outer {
outer.rec_get_const_param_defaults(name)
} else {
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::Str;
use erg_common::{assume_unreachable, enum_unwrap, set, try_map};
use erg_type::free::{Constraint, Cyclicity, FreeTyVar};
use TyParamOrdering::*;
use Type::*;
use ast::{
ParamSignature, ParamTySpec, PreDeclTypeSpec, SimpleTypeSpec, SubrKindSpec, TypeBoundSpec,
TypeBoundSpecs, TypeSpec,
ParamSignature, ParamTySpec, PreDeclTypeSpec, SimpleTypeSpec, TypeBoundSpec, TypeBoundSpecs,
TypeSpec,
};
use erg_parser::ast;
use erg_parser::token::TokenKind;
use erg_type::constructors::*;
use erg_type::free::{Constraint, Cyclicity, FreeTyVar};
use erg_type::typaram::{IntervalOp, TyParam, TyParamOrdering};
use erg_type::value::ValueObj;
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::error::TyCheckResult;
use crate::eval::eval_lit;
use crate::hir;
use RegistrationMode::*;
@ -78,16 +78,16 @@ impl TyVarContext {
) -> TyParam {
match ct {
ConstTemplate::Obj(o) => match o {
ValueObj::Type(t) if t.is_mono_q() => {
if &t.name()[..] == "Self" {
let constraint = Constraint::type_of(Type);
ValueObj::Type(t) if t.typ().is_mono_q() => {
if &t.typ().name()[..] == "Self" {
let constraint = Constraint::new_type_of(Type);
let t = named_free_var(Str::rc(var_name), self.level, constraint);
TyParam::t(t)
} else {
todo!()
}
}
ValueObj::Type(t) => TyParam::t(*t.clone()),
ValueObj::Type(t) => TyParam::t(t.typ().clone()),
v => TyParam::Value(v.clone()),
},
ConstTemplate::App { .. } => {
@ -105,7 +105,7 @@ impl TyVarContext {
) -> Type {
if let Some(temp_defaults) = ctx.rec_get_const_param_defaults(&name) {
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));
let defined_params_len = ctx.params.len();
let given_params_len = params.len();
@ -130,9 +130,9 @@ impl TyVarContext {
self.push_or_init_typaram(&tp.tvar_name().unwrap(), &tp);
inst_defaults.push(tp);
}
poly_trait(name, [inst_non_defaults, inst_defaults].concat())
poly(name, [inst_non_defaults, inst_defaults].concat())
} else {
poly_trait(
poly(
name,
params
.into_iter()
@ -154,23 +154,22 @@ impl TyVarContext {
match bound {
TyBound::Sandwiched { sub, mid, sup } => {
let sub_instance = match sub {
Type::PolyTrait { name, params } => {
Type::Poly { name, params } => {
self.instantiate_poly(mid.name(), &name, params, ctx)
}
Type::PolyClass { .. } => todo!(),
Type::MonoProj { lhs, rhs } => mono_proj(self.instantiate_qvar(*lhs), rhs),
sub => sub,
};
let sup_instance = match sup {
Type::PolyTrait { name, params } => {
Type::Poly { name, params } => {
self.instantiate_poly(mid.name(), &name, params, ctx)
}
Type::PolyClass { .. } => todo!(),
Type::MonoProj { lhs, rhs } => mono_proj(self.instantiate_qvar(*lhs), rhs),
sup => sup,
};
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(
&name,
&named_free_var(name.clone(), self.level, constraint),
@ -178,13 +177,12 @@ impl TyVarContext {
}
TyBound::Instance { name, t } => {
let t = match t {
Type::PolyClass { .. } => todo!(),
Type::PolyTrait { name, params } => {
Type::Poly { name, params } => {
self.instantiate_poly(name.clone(), &name, params, ctx)
}
t => t,
};
let constraint = Constraint::type_of(t.clone());
let constraint = Constraint::new_type_of(t.clone());
// TODO: type-like types
if t == Type {
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) {
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)) {
(true, true) => Cyclicity::Both,
// T <: Super
@ -377,7 +375,7 @@ impl Context {
let spec_t = if let Some(s) = t_spec {
self.instantiate_typespec(s, mode)?
} 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 {
self.sub_unify(&eval_t, &spec_t, None, t_spec.map(|s| s.loc()), None)?;
@ -428,7 +426,7 @@ impl Context {
} else {
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 {
self.sub_unify(
@ -465,7 +463,7 @@ impl Context {
} else {
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);
Ok(array(t, len))
} 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 => {
// FIXME: kw args
let params = simple.args.pos_args().map(|arg| match &arg.expr {
@ -523,7 +521,7 @@ impl Context {
}
});
// 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,
) -> TyCheckResult<Type> {
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!(),
}
}
@ -608,9 +606,9 @@ impl Context {
_ => assume_unreachable!(),
};
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.eval.eval_tp(&r, self)?;
let r = self.eval_tp(&r)?;
if let Some(Greater) = self.rec_try_cmp(&l, &r) {
panic!("{l}..{r} is not a valid interval type (should be lhs <= rhs)")
}
@ -632,7 +630,11 @@ impl Context {
.collect();
let return_t = self.instantiate_typespec(&subr.return_t, mode)?;
Ok(subr_t(
self.instantiate_subr_kind(&subr.kind)?,
if subr.arrow.is(TokenKind::FuncArrow) {
SubrKind::Func
} else {
SubrKind::Proc
},
non_defaults,
var_args,
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(
&self,
bound: &TypeBoundSpec,
@ -759,23 +744,6 @@ impl Context {
Type::Refinement(refine)
}
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() {
*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);
subr_t(
kind,
subr.kind,
subr.non_default_params,
subr.var_params.map(|p| *p),
subr.default_params,
@ -805,25 +773,24 @@ impl Context {
let t = Self::instantiate_t(*t, tv_ctx);
ref_(t)
}
RefMut(t) => {
let t = Self::instantiate_t(*t, tv_ctx);
ref_mut(t)
RefMut { before, after } => {
let before = Self::instantiate_t(*before, tv_ctx);
let after = if let Some(after) = after {
Some(Self::instantiate_t(*after, tv_ctx))
} else {
None
};
ref_mut(before, after)
}
MonoProj { lhs, rhs } => {
let lhs = Self::instantiate_t(*lhs, tv_ctx);
mono_proj(lhs, rhs)
}
PolyClass { name, mut params } => {
Poly { name, mut params } => {
for param in params.iter_mut() {
*param = Self::instantiate_tp(mem::take(param), tv_ctx);
}
poly_class(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)
poly(name, params)
}
Quantified(_) => {
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 t = Self::instantiate_t(*quant.unbound_callable, &mut tv_ctx);
match &t {
Type::Subr(subr) => match subr.kind.self_t() {
Some(l) => {
self.unify(l, callee.ref_t(), None, Some(callee.loc()))?;
Type::Subr(subr) => match subr.self_t() {
Some(self_t) => {
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.
pub mod cache;
pub mod compare;
pub mod eval;
pub mod hint;
pub mod initialize;
pub mod inquire;
@ -33,7 +34,6 @@ use erg_parser::token::Token;
use crate::context::instantiate::ConstTemplate;
use crate::error::{TyCheckError, TyCheckErrors, TyCheckResult};
use crate::eval::Evaluator;
use crate::varinfo::{Mutability, ParamIdx, VarInfo, VarKind};
use Mutability::*;
use Visibility::*;
@ -85,7 +85,7 @@ pub enum TyParamIdx {
impl TyParamIdx {
pub fn search(search_from: &Type, target: &Type) -> Option<Self> {
match search_from {
Type::PolyClass { params, .. } => {
Type::Poly { params, .. } => {
for (i, tp) in params.iter().enumerate() {
match tp {
TyParam::Type(t) if t.as_ref() == target => return Some(Self::Nth(i)),
@ -193,6 +193,7 @@ pub enum ContextKind {
Func,
Proc,
Class,
MethodDefs,
Trait,
StructuralTrait,
Patch(Type),
@ -203,6 +204,24 @@ pub enum ContextKind {
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: サブルーチンまたは定数式、前方参照できる
/// Normal: 前方参照できない
@ -215,7 +234,7 @@ pub enum RegistrationMode {
/// Represents the context of the current scope
///
/// Recursive functions/methods are highlighted with the prefix `rec_`, as performance may be significantly degraded.
#[derive(Debug)]
#[derive(Debug, Clone)]
pub struct Context {
pub(crate) name: Str,
pub(crate) kind: ContextKind,
@ -231,8 +250,9 @@ pub struct Context {
// patchによってsuper class/traitになったものはここに含まれない
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
// specialized contexts, If self is a type
pub(crate) specializations: Vec<(Type, Context)>,
// method definitions, if the context is a type
// specializations are included and needs to be separated out
pub(crate) methods_list: Vec<(Type, Context)>,
/// K: method name, V: impl patch
/// Provided methods can switch implementations on a scope-by-scope basis
/// K: メソッド名, V: それを実装するパッチたち
@ -254,15 +274,12 @@ pub struct Context {
pub(crate) params: Vec<(Option<VarName>, VarInfo)>,
pub(crate) locals: Dict<VarName, VarInfo>,
pub(crate) consts: Dict<VarName, ValueObj>,
pub(crate) eval: Evaluator,
// {"Nat": ctx, "Int": ctx, ...}
pub(crate) mono_types: Dict<VarName, (Type, Context)>,
// Implementation Contexts for Polymorphic Types
// Vec<TyParam> are specialization parameters
// 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)>,
// Traits cannot be specialized
pub(crate) poly_traits: Dict<VarName, (Type, Context)>,
pub(crate) poly_types: Dict<VarName, (Type, Context)>,
// patches can be accessed like normal records
// but when used as a fallback to a type, values are traversed instead of accessing by keys
pub(crate) patches: Dict<VarName, Context>,
@ -296,9 +313,8 @@ impl fmt::Display for Context {
.field("decls", &self.decls)
.field("locals", &self.params)
.field("consts", &self.consts)
.field("eval", &self.eval)
.field("mono_types", &self.mono_types)
.field("poly_types", &self.poly_classes)
.field("poly_types", &self.poly_types)
.field("patches", &self.patches)
.field("mods", &self.mods)
.finish()
@ -345,12 +361,12 @@ impl Context {
let idx = ParamIdx::Nth(idx);
let kind = VarKind::parameter(id, idx, param.default_info);
// 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));
} else {
let idx = ParamIdx::Nth(idx);
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));
}
}
@ -362,7 +378,7 @@ impl Context {
outer: outer.map(Box::new),
super_classes,
super_traits,
specializations: vec![],
methods_list: vec![],
const_param_defaults: Dict::default(),
method_impl_patches: Dict::default(),
trait_impls: Dict::default(),
@ -370,10 +386,8 @@ impl Context {
decls: Dict::default(),
locals: Dict::with_capacity(capacity),
consts: Dict::default(),
eval: Evaluator::default(),
mono_types: Dict::default(),
poly_classes: Dict::default(),
poly_traits: Dict::default(),
poly_types: Dict::default(),
mods: Dict::default(),
patches: Dict::default(),
_nlocals: 0,
@ -476,6 +490,20 @@ impl Context {
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]
pub fn poly_patch<S: Into<Str>>(
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]
pub fn caused_by(&self) -> Str {
self.name.clone()
@ -532,7 +574,7 @@ impl Context {
Ok(())
}
pub(crate) fn pop(&mut self) -> Result<(), TyCheckErrors> {
pub(crate) fn pop(&mut self) -> Result<Context, TyCheckErrors> {
let mut uninited_errs = TyCheckErrors::empty();
for (name, vi) in self.decls.iter() {
uninited_errs.push(TyCheckError::uninitialized_error(
@ -544,12 +586,14 @@ impl Context {
));
}
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);
if !uninited_errs.is_empty() {
Err(uninited_errs)
} else {
Ok(())
Ok(ctx)
}
} else {
Err(TyCheckErrors::from(TyCheckError::checker_bug(

View file

@ -1,20 +1,20 @@
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::Str;
use erg_common::{enum_unwrap, get_hash, log, set};
use erg_type::free::HasLevel;
use ast::{DefId, VarName};
use ast::{DefId, Identifier, VarName};
use erg_parser::ast;
use erg_type::constructors::{enum_t, func, proc};
use erg_type::value::ValueObj;
use erg_type::constructors::{enum_t, func, func1, proc, ref_, ref_mut};
use erg_type::value::{GenTypeObj, TypeKind, TypeObj, ValueObj};
use erg_type::{HasType, ParamTy, SubrType, TyBound, Type};
use Type::*;
use crate::context::{Context, DefaultInfo, RegistrationMode};
use crate::context::{Context, DefaultInfo, RegistrationMode, TraitInstance};
use crate::error::readable_name;
use crate::error::{TyCheckError, TyCheckResult};
use crate::hir;
@ -24,7 +24,8 @@ use RegistrationMode::*;
use Visibility::*;
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, _)| {
maybe_name
.as_ref()
@ -34,9 +35,9 @@ impl Context {
{
return true;
}
if recursive {
if is_const {
if let Some(outer) = &self.outer {
outer.registered(name, recursive)
outer.registered(name, is_const)
} else {
false
}
@ -45,7 +46,7 @@ impl Context {
}
}
fn declare_var(
fn _declare_var(
&mut self,
sig: &ast::VarSignature,
opt_t: Option<Type>,
@ -54,30 +55,22 @@ impl Context {
let muty = Mutability::from(&sig.inspect().unwrap()[..]);
match &sig.pat {
ast::VarPattern::Ident(ident) => {
if sig.t_spec.is_none() && opt_t.is_none() {
Err(TyCheckError::no_type_spec_error(
if self.registered(ident.inspect(), ident.is_const()) {
return Err(TyCheckError::duplicate_decl_error(
line!() as usize,
sig.loc(),
self.caused_by(),
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!(),
}
@ -102,7 +95,17 @@ impl Context {
));
}
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) {
return Err(TyCheckError::duplicate_decl_error(
line!() as usize,
@ -122,6 +125,10 @@ impl Context {
body_t: &Type,
id: DefId,
) -> TyCheckResult<()> {
// already defined as const
if sig.is_const() {
return Ok(());
}
let ident = match &sig.pat {
ast::VarPattern::Ident(ident) => ident,
_ => todo!(),
@ -141,7 +148,7 @@ impl Context {
// something to do?
}
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);
Ok(())
}
@ -156,18 +163,29 @@ impl Context {
opt_decl_t: Option<&ParamTy>,
) -> TyCheckResult<()> {
match &sig.pat {
ast::ParamPattern::Lit(_) => Ok(()),
ast::ParamPattern::Discard(_token) => Ok(()),
ast::ParamPattern::VarName(v) => {
if self.registered(v.inspect(), v.inspect().is_uppercase()) {
ast::ParamPattern::VarName(name) => {
if self.registered(name.inspect(), name.is_const()) {
Err(TyCheckError::reassign_error(
line!() as usize,
v.loc(),
name.loc(),
self.caused_by(),
v.inspect(),
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 idx = if let Some(outer) = outer {
ParamIdx::nested(outer, nth)
} else {
@ -178,16 +196,101 @@ impl Context {
} else {
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((
Some(v.clone()),
VarInfo::new(spec_t, Immutable, Private, kind),
Some(name.clone()),
VarInfo::new(spec_t, Immutable, Private, kind, None),
));
Ok(())
}
}
ast::ParamPattern::Lit(_) => Ok(()),
_ => unreachable!(),
ast::ParamPattern::Ref(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_(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,
body_t: &Type,
) -> TyCheckResult<()> {
// already defined as const
if sig.is_const() {
return Ok(());
}
let muty = if sig.ident.is_const() {
Mutability::Const
} 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(
line!() as usize,
name.loc(),
@ -307,48 +414,263 @@ impl Context {
));
}
}
// TODO: visibility
let vi = VarInfo::new(found_t, muty, Private, VarKind::Defined(id));
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(
found_t,
muty,
sig.ident.vis(),
VarKind::Defined(id),
Some(comptime_decos),
);
log!(info "Registered {}::{name}: {}", self.name, &vi.t);
self.params.push((Some(name.clone()), vi));
self.locals.insert(name.clone(), vi);
Ok(())
}
}
// 再帰サブルーチン/型の推論を可能にするため、予め登録しておく
pub(crate) fn preregister(&mut self, block: &[ast::Expr]) -> TyCheckResult<()> {
// To allow forward references and recursive definitions
pub(crate) fn preregister(&mut self, block: &ast::Block) -> TyCheckResult<()> {
for expr in block.iter() {
if let ast::Expr::Def(def) = expr {
let id = Some(def.body.id);
let eval_body_t = || {
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)?;
}
_ => {}
match expr {
ast::Expr::Def(def) => {
self.preregister_def(def)?;
}
ast::Expr::ClassDef(class_def) => {
self.preregister_def(&class_def.def)?;
}
_ => {}
}
}
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(
&mut self,
var_name: &VarName,

View file

@ -2,7 +2,7 @@
use erg_common::Str;
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::{Predicate, TyBound, Type};
use Type::*;
@ -28,7 +28,7 @@ impl Context {
}
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) {
Ok(Nat) => Ok(()),
Ok(other) => {
@ -46,7 +46,7 @@ impl Context {
pub fn test_resolve_trait_inner1(&self) -> Result<(), ()> {
let name = Str::ever("Add");
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;
for pair in self.rec_get_trait_impls(&name) {
if self.rec_supertype_of(&pair.sup_trait, &maybe_trait) {
@ -62,7 +62,7 @@ impl Context {
pub fn test_instantiation_and_generalization(&self) -> Result<(), ()> {
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 bounds = set! {bound};
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::typaram::TyParam;
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::error::{TyCheckError, TyCheckResult};
@ -118,22 +118,6 @@ impl Context {
_ => assume_unreachable!(),
},
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| {
*nd_param.typ_mut() =
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);
subr_t(
kind,
subr.kind,
subr.non_default_params,
subr.var_params.map(|x| *x),
subr.default_params,
@ -157,20 +141,20 @@ impl Context {
}
Callable { .. } => todo!(),
Ref(t) => ref_(self.generalize_t_inner(*t, bounds, lazy_inits)),
RefMut(t) => ref_mut(self.generalize_t_inner(*t, bounds, lazy_inits)),
PolyClass { name, mut params } => {
let params = params
.iter_mut()
.map(|p| self.generalize_tp(mem::take(p), bounds, lazy_inits))
.collect::<Vec<_>>();
poly_class(name, params)
RefMut { before, after } => {
let after = if let Some(after) = after {
Some(self.generalize_t_inner(*after, bounds, lazy_inits))
} else {
None
};
ref_mut(self.generalize_t_inner(*before, bounds, lazy_inits), after)
}
PolyTrait { name, mut params } => {
Poly { name, mut params } => {
let params = params
.iter_mut()
.map(|p| self.generalize_tp(mem::take(p), bounds, lazy_inits))
.collect::<Vec<_>>();
poly_trait(name, params)
poly(name, params)
}
// REVIEW: その他何でもそのまま通していいのか?
other => other,
@ -246,13 +230,13 @@ impl Context {
if cyclic.is_cyclic() {
return Err(TyCheckError::dummy_infer_error(fn_name!(), line!()));
}
Ok(Constraint::sandwiched(
Ok(Constraint::new_sandwiched(
self.deref_tyvar(sub)?,
self.deref_tyvar(sup)?,
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!(),
}
}
@ -269,7 +253,7 @@ impl Context {
// ?T(:> Never, <: Nat)[n] => Nat
Type::FreeVar(fv) if fv.constraint_is_sandwiched() => {
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) {
self.unify(sub_t, super_t, None, None)?;
let t = if sub_t == &Never {
@ -280,7 +264,7 @@ impl Context {
drop(constraint);
fv.link(&t);
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 {
super_t.clone()
} else {
@ -313,32 +297,14 @@ impl Context {
let t = fv.unwrap_linked();
self.deref_tyvar(t)
}
Type::PolyClass { name, mut params } => {
Type::Poly { name, mut params } => {
for param in params.iter_mut() {
*param = self.deref_tp(mem::take(param))?;
}
Ok(Type::PolyClass { 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 };
let t = Type::Poly { name, params };
self.resolve_trait(t)
}
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() {
*param.typ_mut() = self.deref_tyvar(mem::take(param.typ_mut()))?;
}
@ -355,9 +321,14 @@ impl Context {
let t = self.deref_tyvar(*t)?;
Ok(ref_(t))
}
Type::RefMut(t) => {
let t = self.deref_tyvar(*t)?;
Ok(ref_mut(t))
Type::RefMut { before, after } => {
let before = self.deref_tyvar(*before)?;
let after = if let Some(after) = after {
Some(self.deref_tyvar(*after)?)
} else {
None
};
Ok(ref_mut(before, after))
}
Type::Callable { .. } => todo!(),
Type::Record(mut rec) => {
@ -400,7 +371,7 @@ impl Context {
self.deref_expr_t(&mut subscr.obj)?;
self.deref_expr_t(&mut subscr.index)?;
}
hir::Accessor::Local(_) | hir::Accessor::Public(_) => {}
hir::Accessor::Ident(_) => {}
}
Ok(())
}
@ -490,6 +461,29 @@ impl Context {
}
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)) => {
match &*fv.borrow() {
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 { .. } => {}
} // &fv is dropped
@ -534,11 +528,11 @@ impl Context {
.get_type()
.unwrap()
.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) {
// 外部未連携型変数の場合、linkしないで制約を弱めるだけにする(see compiler/inference.md)
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(
fv.borrow().constraint().unwrap(),
&new_constraint,
@ -553,7 +547,7 @@ impl Context {
} else if allow_divergence
&& (self.eq_tp(tp, &TyParam::value(Inf))
|| 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);
Ok(())
@ -730,7 +724,7 @@ impl Context {
(Type::FreeVar(fv), t) | (t, Type::FreeVar(fv)) => {
match &mut *fv.borrow_mut() {
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 {
lev, constraint, ..
@ -740,7 +734,7 @@ impl Context {
} => {
t.update_level(*lev);
// 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))
if self.rec_subtype_of(sup, t) {
@ -751,7 +745,7 @@ impl Context {
}
}
} // &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)
// fv == ?T(: Type)の場合は?T(<: U)にする
if fv.level() < Some(self.level) {
@ -794,10 +788,7 @@ impl Context {
let lhs_t = self.into_refinement(l.clone());
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) => {
if let (Some(l), Some(r)) = (ls.kind.self_t(), rs.kind.self_t()) {
self.unify(l, r, lhs_loc, rhs_loc)?;
}
(Type::Subr(ls), Type::Subr(rs)) if ls.kind == rs.kind => {
for (l, r) in ls
.non_default_params
.iter()
@ -821,18 +812,38 @@ impl Context {
}
self.unify(&ls.return_t, &rs.return_t, lhs_loc, rhs_loc)
}
(Type::Ref(l), Type::Ref(r)) | (Type::RefMut(l), Type::RefMut(r)) => {
self.unify(l, r, lhs_loc, rhs_loc)
(Type::Ref(l), Type::Ref(r)) => 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:
(Type::Ref(l), r) | (Type::RefMut(l), r) => self.unify(l, r, lhs_loc, rhs_loc),
(l, Type::Ref(r)) | (l, Type::RefMut(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)) => 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,
params: lps,
},
Type::PolyClass {
Type::Poly {
name: rn,
params: rps,
},
@ -852,32 +863,7 @@ impl Context {
}
Ok(())
}
(
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) => {
(Type::Poly { name: _, params: _ }, _r) => {
todo!()
}
(l, r) => Err(TyCheckError::unification_error(
@ -908,50 +894,44 @@ impl Context {
(l, Type::FreeVar(fv)) if fv.is_linked() => {
self.reunify(l, &fv.crack(), bef_loc, aft_loc)
}
(Type::Ref(l), Type::Ref(r)) | (Type::RefMut(l), Type::RefMut(r)) => {
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::Ref(l), Type::Ref(r)) => self.reunify(l, r, bef_loc, aft_loc),
(
Type::PolyClass {
name: ln,
params: lps,
Type::RefMut {
before: lbefore,
after: lafter,
},
Type::PolyClass {
name: rn,
params: rps,
Type::RefMut {
before: rbefore,
after: rafter,
},
) => {
if ln != rn {
let before_t = poly_class(ln.clone(), lps.clone());
return Err(TyCheckError::re_unification_error(
line!() as usize,
&before_t,
after_t,
bef_loc,
aft_loc,
self.caused_by(),
));
}
for (l, r) in lps.iter().zip(rps.iter()) {
self.reunify_tp(l, r)?;
self.reunify(lbefore, rbefore, bef_loc, aft_loc)?;
match (lafter, rafter) {
(Some(lafter), Some(rafter)) => {
self.reunify(lafter, rafter, bef_loc, aft_loc)?;
}
(None, None) => {}
_ => todo!(),
}
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,
params: lps,
},
Type::PolyTrait {
Type::Poly {
name: rn,
params: rps,
},
) => {
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(
line!() as usize,
&before_t,
@ -987,7 +967,7 @@ impl Context {
/// sub_unify({I: Int | I == 0}, ?T(<: Ord)): (/* OK */)
/// sub_unify(Int, ?T(:> Nat)): (?T :> Int)
/// 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 */)
/// ```
pub(crate) fn sub_unify(
@ -1029,20 +1009,29 @@ impl Context {
// 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[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) */)
(Type::FreeVar(lfv), Type::FreeVar(rfv))
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 (rsub, rsup) = rfv.crack_bound_types().unwrap();
let (rsub, rsup) = rfv.get_bound_types().unwrap();
let r_cyc = rfv.cyclicity();
let cyclicity = l_cyc.combine(r_cyc);
let new_constraint = if let Some(min) = self.min(&lsup, &rsup) {
Constraint::sandwiched(self.rec_union(&lsub, &rsub), min.clone(), cyclicity)
let intersec = self.rec_intersection(&lsup, &rsup);
let new_constraint = if intersec != Type::Never {
Constraint::new_sandwiched(self.rec_union(&lsub, &rsub), intersec, cyclicity)
} 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() {
lfv.update_constraint(new_constraint);
@ -1067,7 +1056,7 @@ impl Context {
// sub = max(l, sub) if max exists
// * sub_unify(Nat, ?T(:> Int, <: _)): (/* OK */)
// * 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_unify(Str, ?T(:> Int, <: Obj)): (?T(:> Str or Int, <: Obj))
// * 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) {
*constraint =
Constraint::sandwiched(new_sub.clone(), mem::take(sup), *cyclicity);
Constraint::new_sandwiched(new_sub.clone(), mem::take(sup), *cyclicity);
} else {
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) */)
Constraint::TypeOf(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 {
todo!()
}
@ -1138,16 +1127,16 @@ impl Context {
}
if let Some(new_sup) = self.rec_min(sup, maybe_sup) {
*constraint =
Constraint::sandwiched(mem::take(sub), new_sup.clone(), *cyclicity);
Constraint::new_sandwiched(mem::take(sub), new_sup.clone(), *cyclicity);
} else {
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))
Constraint::TypeOf(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 {
todo!()
}
@ -1159,6 +1148,23 @@ impl Context {
return Ok(());
}
(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)) => {
for lpt in lsub.default_params.iter() {
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)?;
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!(),
(Refinement(_), Refinement(_)) => todo!(),

View file

@ -9,7 +9,7 @@ use erg_common::Str;
use Visibility::*;
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)]
enum BlockKind {
@ -84,6 +84,12 @@ impl SideEffectChecker {
Expr::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) => {
for parg in call.args.pos_args.iter() {
self.check_expr(&parg.expr);
@ -174,6 +180,31 @@ impl SideEffectChecker {
Expr::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でも関数呼び出しなら副作用なし
Expr::Call(call) => {
if (self.is_procedural(&call.obj)
@ -228,10 +259,10 @@ impl SideEffectChecker {
Expr::Lambda(lambda) => lambda.is_procedural(),
// 引数がproceduralでも関数呼び出しなら副作用なし
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
Expr::Accessor(Accessor::Attr(attr)) => attr.name.is_procedural(),
Expr::Accessor(Accessor::Attr(attr)) => attr.ident.is_procedural(),
Expr::Accessor(_) => todo!(),
_ => false,
}

View file

@ -255,6 +255,10 @@ impl TyCheckError {
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 {
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(
errno: usize,
loc: Location,
@ -521,10 +549,10 @@ impl TyCheckError {
TypeError,
loc,
switch_lang!(
"japanese" => format!("{name}の型が違います。\n予期した型: {GREEN}{expect}{RESET}\n与えられた型: {RED}{found}{RESET}"),
"simplified_chinese" => format!("{name}的类型不匹配:\n预期:{GREEN}{expect}{RESET}\n但找到:{RED}{found}{RESET}"),
"traditional_chinese" => format!("{name}的類型不匹配:\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}"),
"japanese" => format!("{YELLOW}{name}{RESET}の型が違います。\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!("{YELLOW}{name}{RESET}的類型不匹配:\n預期:{GREEN}{expect}{RESET}\n但找到:{RED}{found}{RESET}"),
"english" => format!("the type of {YELLOW}{name}{RESET} is mismatched:\nexpected: {GREEN}{expect}{RESET}\nbut found: {RED}{found}{RESET}"),
),
hint,
),
@ -657,10 +685,10 @@ impl TyCheckError {
AssignError,
loc,
switch_lang!(
"japanese" => format!("定数{name}には再代入できません"),
"simplified_chinese" => format!("不能为不可变变量{name}分配两次"),
"traditional_chinese" => format!("不能為不可變變量{name}分配兩次"),
"english" => format!("cannot assign twice to the immutable variable {name}"),
"japanese" => format!("変数{name}に再代入されています"),
"simplified_chinese" => format!("不能为变量{name}分配两次"),
"traditional_chinese" => format!("不能為變量{name}分配兩次"),
"english" => format!("cannot assign twice to the variable {name}"),
),
None,
),
@ -1006,7 +1034,7 @@ passed keyword args: {RED}{kw_args_len}{RESET}"
Self::new(
ErrorCore::new(
errno,
NameError,
VisibilityError,
loc,
switch_lang!(
"japanese" => format!("{RED}{name}{RESET}{visibility}変数です"),
@ -1019,6 +1047,79 @@ passed keyword args: {RED}{kw_args_len}{RESET}"
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)]

View file

@ -11,16 +11,16 @@ use erg_common::{
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_type::constructors::{array, tuple};
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 crate::context::eval::type_from_token_kind;
use crate::error::readable_name;
use crate::eval::type_from_token_kind;
#[derive(Debug, Clone)]
pub struct Literal {
@ -119,6 +119,7 @@ impl KwArg {
#[derive(Debug, Clone)]
pub struct Args {
pub pos_args: Vec<PosArg>,
pub var_args: Option<Box<PosArg>>,
pub kw_args: Vec<KwArg>,
paren: Option<(Token, Token)>,
}
@ -128,6 +129,10 @@ impl NestedDisplay for Args {
if !self.pos_args.is_empty() {
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() {
fmt_lines(self.kw_args.iter(), f, level)?;
}
@ -139,6 +144,7 @@ impl From<Vec<Expr>> for Args {
fn from(exprs: Vec<Expr>) -> Self {
Self {
pos_args: exprs.into_iter().map(PosArg::new).collect(),
var_args: None,
kw_args: Vec::new(),
paren: None,
}
@ -167,30 +173,33 @@ impl Locational for Args {
// impl_stream!(Args, KwArg, kw_args);
impl Args {
pub const fn new(
pub fn new(
pos_args: Vec<PosArg>,
var_args: Option<PosArg>,
kw_args: Vec<KwArg>,
paren: Option<(Token, Token)>,
) -> Self {
Self {
pos_args,
var_args: var_args.map(Box::new),
kw_args,
paren,
}
}
pub const fn empty() -> Self {
Self::new(vec![], vec![], None)
pub fn empty() -> Self {
Self::new(vec![], None, vec![], None)
}
#[inline]
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]
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]
@ -243,86 +252,89 @@ impl Args {
.map(|a| &a.expr)
}
}
}
/// represents local variables
#[derive(Debug, Clone)]
pub struct Local {
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__})")
pub fn remove_left_or_key(&mut self, key: &str) -> Option<Expr> {
if !self.pos_args.is_empty() {
Some(self.pos_args.remove(0).expr)
} else {
"".to_string()
};
write!(f, "{} (: {}){}", self.name.content, self.t, __name__)
}
}
impl_display_from_nested!(Local);
impl_t!(Local);
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 }
if let Some(pos) = self
.kw_args
.iter()
.position(|arg| &arg.keyword.inspect()[..] == key)
{
Some(self.kw_args.remove(pos).expr)
} else {
None
}
}
}
// &strにするとクローンしたいときにアロケーションコストがかかるので&Strのままで
#[inline]
pub fn inspect(&self) -> &Str {
&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__})")
pub fn get_left_or_key(&self, key: &str) -> Option<&Expr> {
if !self.pos_args.is_empty() {
Some(&self.pos_args.get(0)?.expr)
} else {
"".to_string()
};
write!(f, ".{} (: {}){}", self.name.content, self.t, __name__)
if let Some(pos) = self
.kw_args
.iter()
.position(|arg| &arg.keyword.inspect()[..] == key)
{
Some(&self.kw_args.get(pos)?.expr)
} else {
None
}
}
}
}
impl_display_from_nested!(Public);
impl_t!(Public);
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct Identifier {
pub dot: Option<Token>,
pub name: VarName,
pub __name__: Option<Str>,
pub t: Type,
}
impl Locational for Public {
#[inline]
impl NestedDisplay for Identifier {
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 {
Location::concat(&self.dot, &self.name)
if let Some(dot) = &self.dot {
Location::concat(dot, &self.name)
} else {
self.name.loc()
}
}
}
impl Public {
pub const fn new(dot: Token, name: Token, __name__: Option<Str>, t: Type) -> Self {
impl From<&Identifier> for Field {
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 {
dot,
name,
@ -331,39 +343,75 @@ impl Public {
}
}
// &strにするとクローンしたいときにアロケーションコストがかかるので&Strのままで
#[inline]
pub fn inspect(&self) -> &Str {
&self.name.content
pub fn public(name: &'static str) -> Self {
Self::bare(
Some(Token::from_str(TokenKind::Dot, ".")),
VarName::from_static(name),
)
}
pub const fn __name__(&self) -> Option<&Str> {
self.__name__.as_ref()
pub fn private(name: Str) -> Self {
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)]
pub struct Attribute {
pub obj: Box<Expr>,
pub name: Token,
pub ident: Identifier,
t: Type,
}
impl NestedDisplay for Attribute {
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_locational!(Attribute, obj, name);
impl_locational!(Attribute, obj, ident);
impl_t!(Attribute);
impl Attribute {
pub fn new(obj: Expr, name: Token, t: Type) -> Self {
pub fn new(obj: Expr, ident: Identifier, t: Type) -> Self {
Self {
obj: Box::new(obj),
name,
ident,
t,
}
}
@ -426,55 +474,64 @@ impl Subscript {
#[derive(Debug, Clone)]
pub enum Accessor {
Local(Local),
Public(Public),
Ident(Identifier),
Attr(Attribute),
TupleAttr(TupleAttribute),
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_locational_for_enum!(Accessor; Local, Public, Attr, TupleAttr, Subscr);
impl_t_for_enum!(Accessor; Local, Public, Attr, TupleAttr, Subscr);
impl_locational_for_enum!(Accessor; Ident, Attr, TupleAttr, Subscr);
impl_t_for_enum!(Accessor; Ident, Attr, TupleAttr, Subscr);
impl Accessor {
pub const fn local(symbol: Token, t: Type) -> Self {
Self::Local(Local::new(symbol, None, t))
pub fn private_with_line(name: Str, line: usize) -> Self {
Self::Ident(Identifier::private_with_line(name, line))
}
pub const fn public(dot: Token, name: Token, t: Type) -> Self {
Self::Public(Public::new(dot, name, None, t))
pub fn public_with_line(name: Str, line: usize) -> Self {
Self::Ident(Identifier::public_with_line(Token::dummy(), name, line))
}
pub fn attr(obj: Expr, name: Token, t: Type) -> Self {
Self::Attr(Attribute::new(obj, name, t))
pub const fn private(name: Token, t: Type) -> Self {
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 {
Self::Subscr(Subscript::new(obj, index, t))
}
pub fn var_full_name(&self) -> Option<String> {
pub fn show(&self) -> String {
match self {
Self::Local(local) => Some(readable_name(local.inspect()).to_string()),
Self::Attr(attr) => attr
.obj
.var_full_name()
.map(|n| n + "." + readable_name(attr.name.inspect())),
Self::TupleAttr(t_attr) => t_attr
.obj
.var_full_name()
.map(|n| n + "." + t_attr.index.token.inspect()),
Self::Subscr(_) | Self::Public(_) => todo!(),
Self::Ident(ident) => readable_name(ident.inspect()).to_string(),
Self::Attr(attr) => {
attr.obj
.show_acc()
.unwrap_or_else(|| attr.obj.ref_t().to_string())
+ "." // TODO: visibility
+ readable_name(attr.ident.inspect())
}
Self::TupleAttr(t_attr) => {
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> {
match self {
Self::Local(local) => local.__name__().map(|s| &s[..]),
Self::Public(public) => public.__name__().map(|s| &s[..]),
Self::Ident(ident) => ident.__name__.as_ref().map(|s| &s[..]),
_ => 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 {
fn from(attrs: Vec<Def>) -> Self {
Self(attrs)
@ -695,10 +761,6 @@ impl From<Vec<Def>> for RecordAttrs {
}
impl RecordAttrs {
pub const fn new() -> Self {
Self(vec![])
}
pub fn len(&self) -> usize {
self.0.len()
}
@ -718,6 +780,10 @@ impl RecordAttrs {
pub fn push(&mut self, attr: Def) {
self.0.push(attr);
}
pub fn extend(&mut self, attrs: RecordAttrs) {
self.0.extend(attrs.0);
}
}
#[derive(Clone, Debug)]
@ -875,7 +941,7 @@ impl UnaryOp {
#[derive(Debug, Clone)]
pub struct Call {
pub obj: Box<Expr>,
pub method_name: Option<Token>,
pub method_name: Option<Identifier>,
pub args: Args,
/// 全体の型(引数自体の型は関係ない)、e.g. `abs(-1)` -> `Neg -> Nat`
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 {
writeln!(
f,
"({}){}(: {}):",
"({}){} (: {}):",
self.obj,
fmt_option!(pre ".", self.method_name),
fmt_option!(self.method_name),
self.sig_t
)?;
self.args.fmt_nest(f, level + 1)
@ -930,7 +996,7 @@ impl Locational for 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 {
obj: Box::new(obj),
method_name,
@ -941,7 +1007,7 @@ impl Call {
pub fn is_import_call(&self) -> bool {
self.obj
.var_full_name()
.show_acc()
.map(|s| &s[..] == "import" || &s[..] == "pyimport" || &s[..] == "py")
.unwrap_or(false)
}
@ -1002,6 +1068,7 @@ impl NestedDisplay for VarSignature {
impl_display_from_nested!(VarSignature);
impl_locational!(VarSignature, ident);
impl_t!(VarSignature);
impl VarSignature {
pub const fn new(ident: Identifier, t: Type) -> Self {
@ -1032,6 +1099,7 @@ impl NestedDisplay for SubrSignature {
impl_display_from_nested!(SubrSignature);
impl_locational!(SubrSignature, ident, params);
impl_t!(SubrSignature);
impl SubrSignature {
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_display_for_enum!(Signature; Var, Subr,);
impl_t_for_enum!(Signature; Var, Subr);
impl_locational_for_enum!(Signature; Var, Subr,);
impl Signature {
@ -1121,6 +1190,13 @@ impl Signature {
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
@ -1188,19 +1264,6 @@ impl DefBody {
pub const fn new(op: Token, block: Block, id: DefId) -> Self {
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)]
@ -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)]
pub enum Expr {
Lit(Literal),
@ -1259,12 +1471,14 @@ pub enum Expr {
Lambda(Lambda),
Decl(Decl),
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_locational_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);
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, ClassDef, AttrDef);
impl Expr {
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 {
Expr::Accessor(acc) => acc.var_full_name(),
Expr::Accessor(acc) => Some(acc.show()),
_ => None,
}
}
@ -1285,7 +1499,7 @@ impl Expr {
pub fn __name__(&self) -> Option<&str> {
match self {
Expr::Accessor(acc) => acc.__name__(),
_ => todo!(),
_ => None,
}
}
}

View file

@ -7,8 +7,8 @@ pub use compile::*;
mod codegen;
pub mod effectcheck;
pub mod error;
pub mod eval;
pub mod hir;
pub mod link;
pub mod lower;
pub use lower::ASTLowerer;
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::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::typaram::TyParam;
use erg_type::value::ValueObj;
use erg_type::value::{TypeObj, ValueObj};
use erg_type::{HasType, ParamTy, Type};
use crate::context::{Context, ContextKind, RegistrationMode};
use crate::error::{LowerError, LowerErrors, LowerResult, LowerWarnings};
use crate::hir;
use crate::hir::HIR;
use crate::varinfo::VarKind;
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
#[derive(Debug)]
pub struct ASTLowerer {
@ -137,7 +167,7 @@ impl ASTLowerer {
new_array.push(elem);
}
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 {
union
};
@ -162,11 +192,11 @@ impl ASTLowerer {
}
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 {
Some(v @ ValueObj::Nat(_)) => {
Ok(v @ ValueObj::Nat(_)) => {
if elem.ref_t().is_mut() {
poly_class(
poly(
"ArrayWithMutType!",
vec![TyParam::t(elem.t()), TyParam::Value(v)],
)
@ -174,9 +204,9 @@ impl ASTLowerer {
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() {
poly_class(
poly(
"ArrayWithMutTypeAndLength!",
vec![TyParam::t(elem.t()), TyParam::Value(v)],
)
@ -184,11 +214,11 @@ impl ASTLowerer {
array_mut(elem.t(), TyParam::Value(v))
}
}
Some(other) => todo!("{other} is not a Nat object"),
// TODO: [T; !_]
None => {
Ok(other) => todo!("{other} is not a Nat object"),
// REVIEW: is it ok to ignore the error?
Err(_e) => {
if elem.ref_t().is_mut() {
poly_class(
poly(
"ArrayWithMutType!",
vec![TyParam::t(elem.t()), TyParam::erased(Type::Nat)],
)
@ -217,13 +247,24 @@ impl ASTLowerer {
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!());
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)?;
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);
}
self.pop_append_errs();
@ -233,37 +274,16 @@ impl ASTLowerer {
fn lower_acc(&mut self, acc: ast::Accessor) -> LowerResult<hir::Accessor> {
log!(info "entered {}({acc})", fn_name!());
match acc {
ast::Accessor::Local(local) => {
// `match` is an untypable special form
// `match`は型付け不可能な特殊形式
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);
ast::Accessor::Ident(ident) => {
let ident = self.lower_ident(ident)?;
let acc = hir::Accessor::Ident(ident);
Ok(acc)
}
ast::Accessor::Attr(attr) => {
let obj = self.lower_expr(*attr.obj)?;
let t = self
.ctx
.rec_get_attr_t(&obj, &attr.name.symbol, &self.ctx.name)?;
let acc = hir::Accessor::Attr(hir::Attribute::new(obj, attr.name.symbol, t));
let t = self.ctx.rec_get_attr_t(&obj, &attr.ident, &self.ctx.name)?;
let ident = hir::Identifier::bare(attr.ident.dot, attr.ident.name);
let acc = hir::Accessor::Attr(hir::Attribute::new(obj, ident, t));
Ok(acc)
}
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> {
log!(info "entered {}({bin})", fn_name!());
let mut args = bin.args.into_iter();
@ -320,6 +355,7 @@ impl ASTLowerer {
let (pos_args, kw_args, paren) = call.args.deconstruct();
let mut hir_args = hir::Args::new(
Vec::with_capacity(pos_args.len()),
None,
Vec::with_capacity(kw_args.len()),
paren,
);
@ -330,14 +366,55 @@ impl ASTLowerer {
hir_args.push_kw(hir::KwArg::new(arg.keyword, self.lower_expr(arg.expr)?));
}
let obj = self.lower_expr(*call.obj)?;
let t = self.ctx.get_call_t(
let sig_t = self.ctx.get_call_t(
&obj,
&call.method_name,
&hir_args.pos_args,
&hir_args.kw_args,
&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
@ -358,12 +435,10 @@ impl ASTLowerer {
self.pop_append_errs();
e
})?;
self.ctx
.preregister(lambda.body.ref_payload())
.map_err(|e| {
self.pop_append_errs();
e
})?;
self.ctx.preregister(&lambda.body).map_err(|e| {
self.pop_append_errs();
e
})?;
let body = self.lower_block(lambda.body).map_err(|e| {
self.pop_append_errs();
e
@ -406,20 +481,24 @@ impl ASTLowerer {
fn lower_def(&mut self, def: ast::Def) -> LowerResult<hir::Def> {
log!(info "entered {}({})", fn_name!(), def.sig);
if let Some(name) = def.sig.name_as_str() {
self.ctx.grow(name, ContextKind::Instant, Private)?;
if def.body.block.len() >= 1 {
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 {
ast::Signature::Subr(sig) => self.lower_subr_def(sig, def.body),
ast::Signature::Var(sig) => self.lower_var_def(sig, def.body),
};
// TODO: Context上の関数に型境界情報を追加
self.pop_append_errs();
res
} else {
match def.sig {
ast::Signature::Subr(sig) => self.lower_subr_def(sig, def.body),
ast::Signature::Var(sig) => self.lower_var_def(sig, def.body),
}
return res;
}
match def.sig {
ast::Signature::Subr(sig) => self.lower_subr_def(sig, def.body),
ast::Signature::Var(sig) => self.lower_var_def(sig, def.body),
}
}
@ -429,7 +508,7 @@ impl ASTLowerer {
body: ast::DefBody,
) -> LowerResult<hir::Def> {
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 found_body_t = block.ref_t();
let opt_expect_body_t = self
@ -444,10 +523,14 @@ impl ASTLowerer {
_ => unreachable!(),
};
if let Some(expect_body_t) = opt_expect_body_t {
if let Err(e) =
self.return_t_check(sig.loc(), ident.inspect(), &expect_body_t, found_body_t)
{
self.errs.push(e);
// TODO: expect_body_t is smaller for constants
// TODO: 定数の場合、expect_body_tのほうが小さくなってしまう
if !sig.is_const() {
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;
@ -469,7 +552,8 @@ impl ASTLowerer {
}
_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);
Ok(hir::Def::new(hir::Signature::Var(sig), body))
}
@ -487,22 +571,20 @@ impl ASTLowerer {
.as_ref()
.unwrap()
.get_current_scope_var(sig.ident.inspect())
.unwrap_or_else(|| {
log!(info "{}\n", sig.ident.inspect());
log!(info "{}\n", self.ctx.outer.as_ref().unwrap());
panic!()
}) // FIXME: or instantiate
.unwrap()
.t
.clone();
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 found_body_t = block.ref_t();
let expect_body_t = t.return_t().unwrap();
if let Err(e) =
self.return_t_check(sig.loc(), sig.ident.inspect(), &expect_body_t, found_body_t)
{
self.errs.push(e);
if !sig.is_const() {
if let Err(e) =
self.return_t_check(sig.loc(), sig.ident.inspect(), &expect_body_t, found_body_t)
{
self.errs.push(e);
}
}
let id = body.id;
self.ctx
@ -510,11 +592,156 @@ impl ASTLowerer {
.as_mut()
.unwrap()
.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);
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)
// so turn off type checking (check=false)
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::UnaryOp(unary) => Ok(hir::Expr::UnaryOp(self.lower_unary(unary)?)),
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::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}"),
}
}
@ -548,7 +777,7 @@ impl ASTLowerer {
log!(info "the AST lowering process has started.");
log!(info "the type-checking process has started.");
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() {
match self.lower_expr(expr).and_then(|e| self.use_check(e, mode)) {
Ok(expr) => {

View file

@ -99,11 +99,12 @@ impl OwnershipChecker {
// TODO: referenced
Expr::Call(call) => {
let args_owns = call.signature_t().unwrap().args_ownership();
if let Some(ownership) = args_owns.self_ {
self.check_expr(&call.obj, ownership);
}
let (non_default_args, var_args) =
call.args.pos_args.split_at(args_owns.non_defaults.len());
let non_defaults_len = if call.method_name.is_some() {
args_owns.non_defaults.len() - 1
} else {
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
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) {
match acc {
Accessor::Local(local) => {
self.check_if_dropped(local.inspect(), local.loc());
Accessor::Ident(ident) => {
self.check_if_dropped(ident.inspect(), ident.loc());
if acc.ref_t().is_mut() && ownership.is_owned() {
log!(
"drop: {} (in {})",
local.inspect(),
local.ln_begin().unwrap_or(0)
ident.inspect(),
ident.ln_begin().unwrap_or(0)
);
self.drop(local.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());
self.drop(ident.inspect(), acc.loc());
}
}
Accessor::Attr(attr) => {

View file

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

View file

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

View file

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

View file

@ -6,15 +6,13 @@ use erg_common::error::Location;
use erg_common::set::Set as HashSet;
use erg_common::traits::{Locational, NestedDisplay, Stream};
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::{
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_locational_for_enum, impl_nested_display_for_chunk_enum, impl_nested_display_for_enum,
impl_stream, impl_stream_for_wrapper,
};
use erg_common::{fmt_vec_split_with, Str};
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)]
pub struct Attribute {
pub obj: Box<Expr>,
pub vis: Token,
pub name: Local,
pub ident: Identifier,
}
impl NestedDisplay for Attribute {
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_locational!(Attribute, obj, name);
impl_locational!(Attribute, obj, ident);
impl Attribute {
pub fn new(obj: Expr, vis: Token, name: Local) -> Self {
pub fn new(obj: Expr, ident: Identifier) -> Self {
Self {
obj: Box::new(obj),
vis,
name,
ident,
}
}
}
@ -384,28 +301,27 @@ impl Subscript {
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub enum Accessor {
Local(Local),
Public(Public),
Ident(Identifier),
Attr(Attribute),
TupleAttr(TupleAttribute),
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_locational_for_enum!(Accessor; Local, Public, Attr, TupleAttr, Subscr);
impl_locational_for_enum!(Accessor; Ident Attr, TupleAttr, Subscr);
impl Accessor {
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 {
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 {
Self::Attr(Attribute::new(obj, vis, name))
pub fn attr(obj: Expr, ident: Identifier) -> Self {
Self::Attr(Attribute::new(obj, ident))
}
pub fn tuple_attr(obj: Expr, index: Literal) -> Self {
@ -418,19 +334,17 @@ impl Accessor {
pub const fn name(&self) -> Option<&Str> {
match self {
Self::Local(local) => Some(local.inspect()),
Self::Public(local) => Some(local.inspect()),
Self::Ident(ident) => Some(ident.inspect()),
_ => None,
}
}
pub fn is_const(&self) -> bool {
match self {
Self::Local(local) => local.is_const(),
Self::Public(public) => public.is_const(),
Self::Ident(ident) => ident.is_const(),
Self::Subscr(subscr) => subscr.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 r_sqbr: Token,
pub elem: Box<Expr>,
pub generators: Vec<(Local, Expr)>,
pub generators: Vec<(Identifier, Expr)>,
pub guards: Vec<Expr>,
}
@ -524,7 +438,7 @@ impl ArrayComprehension {
l_sqbr: Token,
r_sqbr: Token,
elem: Expr,
generators: Vec<(Local, Expr)>,
generators: Vec<(Identifier, Expr)>,
guards: Vec<Expr>,
) -> Self {
Self {
@ -675,10 +589,18 @@ impl From<Vec<Def>> for RecordAttrs {
}
impl RecordAttrs {
pub const fn new(attrs: Vec<Def>) -> Self {
Self(attrs)
}
pub fn iter(&self) -> impl Iterator<Item = &Def> {
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> {
self.0.into_iter()
}
@ -714,12 +636,45 @@ impl NormalRecord {
/// e.g. {x; y; z} (syntax sugar of {x = x; y = y; z = z})
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct SimpleRecord {
pub struct ShortenedRecord {
pub l_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)]
pub struct NormalSet {
l_brace: Token,
@ -821,7 +776,7 @@ impl UnaryOp {
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct Call {
pub obj: Box<Expr>,
pub method_name: Option<Token>,
pub method_name: Option<Identifier>,
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 {
write!(f, "({})", self.obj)?;
if let Some(method_name) = self.method_name.as_ref() {
write!(f, ".{}", method_name.content)?;
write!(f, "{}", method_name)?;
}
writeln!(f, ":")?;
self.args.fmt_nest(f, level + 1)
@ -849,7 +804,7 @@ impl Locational for 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 {
obj: Box::new(obj),
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)]
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)]
pub struct SubrTypeSpec {
pub kind: SubrKindSpec,
pub lparen: Option<Token>,
pub non_defaults: Vec<ParamTySpec>,
pub var_args: Option<Box<ParamTySpec>>,
pub defaults: Vec<ParamTySpec>,
pub arrow: Token,
pub return_t: Box<TypeSpec>,
}
@ -1450,7 +1417,7 @@ impl fmt::Display for SubrTypeSpec {
fmt_vec(&self.non_defaults),
fmt_option!(pre "...", &self.var_args),
fmt_vec(&self.defaults),
self.kind.arrow(),
self.arrow.content,
self.return_t
)
}
@ -1469,19 +1436,19 @@ impl Locational for SubrTypeSpec {
impl SubrTypeSpec {
pub fn new(
kind: SubrKindSpec,
lparen: Option<Token>,
non_defaults: Vec<ParamTySpec>,
var_args: Option<ParamTySpec>,
defaults: Vec<ParamTySpec>,
arrow: Token,
return_t: TypeSpec,
) -> Self {
Self {
kind,
lparen,
non_defaults,
var_args: var_args.map(Box::new),
defaults,
arrow,
return_t: Box::new(return_t),
}
}
@ -1580,40 +1547,6 @@ impl TypeSpec {
pub const fn interval(op: Token, lhs: ConstExpr, rhs: ConstExpr) -> Self {
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)]
@ -1657,7 +1590,7 @@ impl Locational for TypeBoundSpecs {
/// デコレータは関数を返す関数オブジェクトならば何でも指定できる
/// e.g. @(x -> x)
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct Decorator(Expr);
pub struct Decorator(pub Expr);
impl Decorator {
pub const fn new(expr: Expr) -> Self {
@ -1760,15 +1693,17 @@ pub struct Identifier {
pub name: VarName,
}
impl fmt::Display for Identifier {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
impl NestedDisplay for Identifier {
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),
None => write!(f, "::{}", self.name),
}
}
}
impl_display_from_nested!(Identifier);
impl Locational for Identifier {
fn loc(&self) -> Location {
if let Some(dot) = &self.dot {
@ -1805,13 +1740,17 @@ impl Identifier {
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 {
self.name.is_const()
}
pub const fn vis(&self) -> Visibility {
match &self.dot {
Some(_dot) => Visibility::Public,
Some(_) => Visibility::Public,
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)]
pub struct VarRecordPattern {
l_brace: Token,
// TODO: レコード専用の構造体を作る
pub(crate) elems: Vars,
pub(crate) attrs: VarRecordAttrs,
r_brace: Token,
}
impl fmt::Display for VarRecordPattern {
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 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 {
l_brace,
elems,
attrs,
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)]
pub enum VarPattern {
Discard(Token),
@ -1943,6 +1946,8 @@ pub enum VarPattern {
Tuple(VarTuplePattern),
// e.g. `{name; age}`, `{_; [car, cdr]}`
Record(VarRecordPattern),
// e.g. `Data::{x, y}`
DataPack(VarDataPackPattern),
}
impl NestedDisplay for VarPattern {
@ -1953,12 +1958,13 @@ impl NestedDisplay for VarPattern {
Self::Array(a) => write!(f, "{}", a),
Self::Tuple(t) => write!(f, "{}", t),
Self::Record(r) => write!(f, "{}", r),
Self::DataPack(d) => write!(f, "{}", d),
}
}
}
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 {
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
pub fn is_procedural(&self) -> bool {
match self {
@ -2052,6 +2046,13 @@ impl VarSignature {
pub const fn vis(&self) -> Visibility {
self.pat.vis()
}
pub fn ident(&self) -> Option<&Identifier> {
match &self.pat {
VarPattern::Ident(ident) => Some(ident),
_ => None,
}
}
}
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
@ -2156,26 +2157,38 @@ impl ParamRecordPattern {
pub enum ParamPattern {
Discard(Token),
VarName(VarName),
// TODO: ConstField(),
// 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),
// TODO: ConstAttr(),
Lit(Literal),
Array(ParamArrayPattern),
Tuple(ParamTuplePattern),
Record(ParamRecordPattern),
// DataPack(ParamDataPackPattern),
Ref(VarName),
RefMut(VarName),
VarArgs(VarName),
}
impl_display_for_enum!(ParamPattern; Discard, VarName, VarArgsName, Lit, Array, Tuple, Record, Ref, RefMut, VarArgs);
impl_locational_for_enum!(ParamPattern; Discard, VarName, VarArgsName, Lit, Array, Tuple, Record, Ref, RefMut, VarArgs);
impl NestedDisplay for ParamPattern {
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 {
pub const fn inspect(&self) -> Option<&Str> {
match self {
Self::VarName(n) | Self::VarArgsName(n) => Some(n.inspect()),
Self::VarName(n) | Self::Ref(n) | Self::RefMut(n) => Some(n.inspect()),
_ => None,
}
}
@ -2187,7 +2200,7 @@ impl ParamPattern {
pub fn is_procedural(&self) -> bool {
match self {
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,
}
}
@ -2195,7 +2208,7 @@ impl ParamPattern {
pub fn is_const(&self) -> bool {
match self {
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,
}
}
@ -2289,7 +2302,11 @@ impl Locational for Params {
} else if !self.non_defaults.is_empty() {
Location::concat(&self.non_defaults[0], self.non_defaults.last().unwrap())
} 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() {
Location::concat(&self.defaults[0], self.defaults.last().unwrap())
} 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> {
match self {
Self::Var(v) => v.t_spec.as_ref(),
@ -2610,7 +2640,8 @@ pub struct Def {
impl NestedDisplay for Def {
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)
}
}
@ -2640,28 +2671,58 @@ impl Def {
/// f(a) = ...
/// ```
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct MethodDefs {
pub struct Methods {
pub class: TypeSpec,
pub vis: Token, // `.` or `::`
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 {
writeln!(f, "{}{}", self.class, self.vis)?;
writeln!(f, "{}{}", self.class, self.vis.content)?;
self.defs.fmt_nest(f, level + 1)
}
}
impl_display_from_nested!(MethodDefs);
impl_locational!(MethodDefs, class, defs);
impl_display_from_nested!(Methods);
impl_locational!(Methods, class, defs);
impl MethodDefs {
impl Methods {
pub const fn new(class: TypeSpec, vis: Token, defs: RecordAttrs) -> Self {
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(式)
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum Expr {
@ -2671,19 +2732,21 @@ pub enum Expr {
Tuple(Tuple),
Dict(Dict),
Set(Set),
Record(NormalRecord),
Record(Record),
BinOp(BinOp),
UnaryOp(UnaryOp),
Call(Call),
DataPack(DataPack),
Lambda(Lambda),
TypeAsc(TypeAscription),
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_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 {
pub fn is_match_call(&self) -> bool {
@ -2720,7 +2783,7 @@ impl Expr {
}
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct Module(Vec<Expr>);
pub struct Module(Block);
impl fmt::Display for Module {
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)]
pub struct AST {

View file

@ -11,17 +11,19 @@ use erg_common::Str;
use erg_common::{enum_unwrap, get_hash, set};
use crate::ast::{
Accessor, Args, Block, Call, Def, DefBody, DefId, Expr, Identifier, Lambda, LambdaSignature,
Literal, Local, Module, ParamPattern, ParamSignature, Params, PosArg, Signature, SubrSignature,
TypeBoundSpecs, TypeSpec, VarName, VarPattern, VarSignature,
Accessor, Args, Array, BinOp, Block, Call, DataPack, Def, DefBody, DefId, Expr, Identifier,
KwArg, Lambda, LambdaSignature, Literal, Methods, Module, NormalArray, NormalRecord,
NormalTuple, ParamPattern, ParamSignature, Params, PosArg, Record, RecordAttrs,
ShortenedRecord, Signature, SubrSignature, Tuple, TypeAscription, TypeBoundSpecs, TypeSpec,
UnaryOp, VarName, VarPattern, VarRecordAttr, VarSignature,
};
use crate::token::{Token, TokenKind};
#[derive(Debug, Clone, PartialEq, Eq)]
enum BufIndex<'s> {
enum BufIndex<'i> {
Array(usize),
Tuple(usize),
Record(&'s str),
Record(&'i Identifier),
}
#[derive(Debug)]
@ -46,7 +48,10 @@ impl Desugarer {
pub fn desugar(&mut self, module: Module) -> 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 {
@ -74,7 +79,7 @@ impl Desugarer {
} else {
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
let param = VarName::new(Token::new(
TokenKind::Symbol,
@ -160,6 +165,19 @@ impl Desugarer {
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] = l` -> `i = l[0]; j = l[1]`
/// `[i, [j, k]] = l` -> `i = l[0]; j = l[1][0]; k = l[1][1]`
@ -174,14 +192,8 @@ impl Desugarer {
body,
}) => match &v.pat {
VarPattern::Tuple(tup) => {
let buf_name = self.fresh_var_name();
let buf_sig = Signature::Var(VarSignature::new(
VarPattern::Ident(Identifier::private_with_line(
Str::rc(&buf_name),
v.ln_begin().unwrap(),
)),
v.t_spec,
));
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 (n, elem) in tup.elems.iter().enumerate() {
@ -194,14 +206,8 @@ impl Desugarer {
}
}
VarPattern::Array(arr) => {
let buf_name = self.fresh_var_name();
let buf_sig = Signature::Var(VarSignature::new(
VarPattern::Ident(Identifier::private_with_line(
Str::rc(&buf_name),
v.ln_begin().unwrap(),
)),
v.t_spec,
));
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 (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) => {
let def = Def::new(Signature::Var(v), body);
new.push(Expr::Def(def));
@ -243,14 +278,7 @@ impl Desugarer {
BufIndex::Array(n) => {
Accessor::subscr(obj, Expr::Lit(Literal::nat(n, sig.ln_begin().unwrap())))
}
BufIndex::Record(attr) => {
// TODO: visibility
Accessor::attr(
obj,
Token::from_str(TokenKind::Dot, "."),
Local::dummy_with_line(attr, sig.ln_begin().unwrap()),
)
}
BufIndex::Record(attr) => Accessor::attr(obj, attr.clone()),
};
let id = DefId(get_hash(&(&acc, buf_name)));
let block = Block::new(vec![Expr::Accessor(acc)]);
@ -258,14 +286,7 @@ impl Desugarer {
let body = DefBody::new(op, block, id);
match &sig.pat {
VarPattern::Tuple(tup) => {
let buf_name = self.fresh_var_name();
let buf_sig = Signature::Var(VarSignature::new(
VarPattern::Ident(Identifier::private_with_line(
Str::rc(&buf_name),
sig.ln_begin().unwrap(),
)),
None,
));
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 (n, elem) in tup.elems.iter().enumerate() {
@ -278,14 +299,7 @@ impl Desugarer {
}
}
VarPattern::Array(arr) => {
let buf_name = self.fresh_var_name();
let buf_sig = Signature::Var(VarSignature::new(
VarPattern::Ident(Identifier::private_with_line(
Str::rc(&buf_name),
sig.ln_begin().unwrap(),
)),
None,
));
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 (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) => {
let def = Def::new(Signature::Var(sig.clone()), body);
new_module.push(Expr::Def(def));
@ -306,21 +346,162 @@ impl Desugarer {
}
}
/// `F(I | I > 0)` -> `F(I: {I: Int | I > 0})`
fn desugar_refinement_pattern(&self, _mod: Module) -> Module {
todo!()
/// `{x; y}` -> `{x = x; y = y}`
fn desugar_shortened_record(&self, mut module: Module) -> Module {
let mut new = Module::with_capacity(module.len());
while let Some(chunk) = module.lpop() {
new.push(self.rec_desugar_shortened_record(chunk));
}
new
}
/// ```python
/// @deco
/// f x = ...
/// ```
/// ↓
/// ```python
/// _f x = ...
/// f = deco _f
/// ```
fn desugar_decorators(&self, _mod: Module) -> Module {
fn rec_desugar_shortened_record(&self, expr: Expr) -> Expr {
match expr {
Expr::Record(Record::Shortened(rec)) => {
let rec = self.desugar_shortened_record_inner(rec);
Expr::Record(Record::Normal(rec))
}
Expr::DataPack(pack) => {
if let Record::Shortened(rec) = pack.args {
let class = self.rec_desugar_shortened_record(*pack.class);
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!()
}
}

View file

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

View file

@ -56,7 +56,7 @@ pub enum ArrayInner {
WithLength(PosArg, Expr),
Comprehension {
elem: PosArg,
generators: Vec<(Local, Expr)>,
generators: Vec<(Identifier, Expr)>,
guards: Vec<Expr>,
},
}
@ -64,7 +64,7 @@ pub enum ArrayInner {
pub enum BraceContainer {
Set(Set),
Dict(Dict),
Record(NormalRecord),
Record(Record),
}
/// 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 {
let loc = self.peek().unwrap().loc();
log!(err "error caused by: {caused_by}");
@ -275,7 +269,10 @@ impl Parser {
Some(t) if t.is(EOF) => {
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!()
}
Some(_) => match self.try_reduce_chunk(true) {
@ -284,7 +281,7 @@ impl Parser {
}
Err(_) => {}
},
_ => switch_unreachable!(),
None => switch_unreachable!(),
}
}
self.level -= 1;
@ -306,29 +303,22 @@ impl Parser {
Some(t) if t.category_is(TC::Separator) => {
self.skip();
}
Some(t) => {
if t.is(Indent) {
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(Indent) => {
self.skip();
}
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!(),
}
}
@ -418,8 +408,8 @@ impl Parser {
let token = self.lpop();
match token.kind {
Symbol => {
let attr = Local::new(token);
acc = Accessor::attr(Expr::Accessor(acc), vis, attr);
let ident = Identifier::new(Some(vis), VarName::new(token));
acc = Accessor::attr(Expr::Accessor(acc), ident);
}
NatLit => {
let attr = Literal::from(token);
@ -444,9 +434,16 @@ impl Parser {
let token = self.lpop();
match token.kind {
Symbol => {
let attr = Local::new(token);
acc = Accessor::attr(Expr::Accessor(acc), vis, attr);
let ident = Identifier::new(None, VarName::new(token));
acc = Accessor::attr(Expr::Accessor(acc), ident);
}
// DataPack
LBrace => {
self.restore(token);
self.restore(vis);
break;
}
// MethodDefs
Newline => {
self.restore(token);
self.restore(vis);
@ -495,8 +492,8 @@ impl Parser {
fn validate_const_expr(&mut self, expr: Expr) -> ParseResult<ConstExpr> {
match expr {
Expr::Lit(l) => Ok(ConstExpr::Lit(l)),
Expr::Accessor(Accessor::Local(local)) => {
let local = ConstLocal::new(local.symbol);
Expr::Accessor(Accessor::Ident(local)) => {
let local = ConstLocal::new(local.name.into_token());
Ok(ConstExpr::Accessor(ConstAccessor::Local(local)))
}
// TODO: App, Array, Record, BinOp, UnaryOp,
@ -606,7 +603,11 @@ impl Parser {
{
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())
}
_ => None,
@ -743,8 +744,8 @@ impl Parser {
// TODO: type specification
debug_power_assert!(self.cur_is(Walrus));
self.skip();
let kw = if let Accessor::Local(n) = acc {
n.symbol
let kw = if let Accessor::Ident(n) = acc {
n.name.into_token()
} else {
self.next_expr();
self.level -= 1;
@ -788,8 +789,8 @@ impl Parser {
let acc = self.try_reduce_acc().map_err(|_| self.stack_dec())?;
debug_power_assert!(self.cur_is(Walrus));
self.skip();
let keyword = if let Accessor::Local(n) = acc {
n.symbol
let keyword = if let Accessor::Ident(n) = acc {
n.name.into_token()
} else {
self.next_expr();
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);
if self.cur_is(Indent) {
self.skip();
} else {
todo!()
}
while self.cur_is(Newline) {
self.skip();
}
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 mut defs = vec![first];
@ -841,13 +845,22 @@ impl Parser {
match self.peek() {
Some(t) if t.category_is(TC::Separator) => {
self.skip();
if self.cur_is(Dedent) {
self.skip();
break;
}
}
Some(t) if t.is(Dedent) => {
self.skip();
break;
}
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!());
defs.push(def);
match def {
Expr::Def(def) => {
defs.push(def);
}
other => {
self.errs
.push(ParseError::simple_syntax_error(0, other.loc()));
}
}
}
_ => todo!(),
}
@ -857,7 +870,7 @@ impl Parser {
.convert_rhs_to_type_spec(class)
.map_err(|_| self.stack_dec())?;
self.level -= 1;
Ok(MethodDefs::new(class, vis, defs))
Ok(Methods::new(class, vis, defs))
}
fn try_reduce_do_block(&mut self) -> ParseResult<Lambda> {
@ -967,10 +980,12 @@ impl Parser {
.transpose()
.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)));
} 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)));
}
}
@ -979,7 +994,25 @@ impl Parser {
let defs = self
.try_reduce_method_defs(maybe_class, vis)
.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 => {
self.restore(other);
@ -1007,10 +1040,12 @@ impl Parser {
.transpose()
.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)));
} 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)));
}
}
@ -1019,7 +1054,7 @@ impl Parser {
let defs = self
.try_reduce_method_defs(maybe_class, vis)
.map_err(|_| self.stack_dec())?;
return Ok(Expr::MethodDefs(defs));
return Ok(Expr::Methods(defs));
}
other => {
self.restore(other);
@ -1037,6 +1072,11 @@ impl Parser {
.map_err(|_| self.stack_dec())?;
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 {
break;
@ -1156,10 +1196,12 @@ impl Parser {
.transpose()
.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)));
} 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)));
}
}
@ -1179,6 +1221,12 @@ impl Parser {
.map_err(|_| self.stack_dec())?;
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 {
break;
@ -1340,8 +1388,8 @@ impl Parser {
if let Some(res) = self.opt_reduce_args() {
let args = res.map_err(|_| self.stack_dec())?;
let (obj, method_name) = match acc {
Accessor::Attr(attr) => (*attr.obj, Some(attr.name.symbol)),
Accessor::Local(local) => (Expr::Accessor(Accessor::Local(local)), None),
Accessor::Attr(attr) => (*attr.obj, Some(attr.ident)),
Accessor::Ident(ident) => (Expr::Accessor(Accessor::Ident(ident)), None),
_ => todo!(),
};
let call = Call::new(obj, method_name, args);
@ -1403,6 +1451,7 @@ impl Parser {
/// Set, Dict, Record
fn try_reduce_brace_container(&mut self) -> ParseResult<BraceContainer> {
debug_call_info!(self);
assert!(self.cur_is(LBrace));
let l_brace = self.lpop();
if self.cur_is(Newline) {
self.skip();
@ -1416,12 +1465,20 @@ impl Parser {
match first {
Expr::Def(def) => {
let record = self
.try_reduce_record(l_brace, def)
.try_reduce_normal_record(l_brace, def)
.map_err(|_| self.stack_dec())?;
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 => {
let set = self
.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);
let mut attrs = vec![first];
loop {
match self.peek() {
Some(t) if t.category_is(TC::Separator) => {
self.skip();
if self.cur_is(Dedent) {
self.skip();
if self.cur_is(RBrace) {
let r_brace = self.lpop();
self.level -= 1;
let attrs = RecordAttrs::from(attrs);
return Ok(NormalRecord::new(l_brace, r_brace, attrs));
} else {
todo!()
}
}
Some(t) if t.is(Dedent) => {
self.skip();
if self.cur_is(RBrace) {
let r_brace = self.lpop();
self.level -= 1;
let attrs = RecordAttrs::from(attrs);
return Ok(NormalRecord::new(l_brace, r_brace, attrs));
} 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) => {
let r_brace = self.lpop();
@ -1460,6 +1518,55 @@ impl Parser {
let attrs = RecordAttrs::from(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!(),
}
}
@ -1556,6 +1663,14 @@ impl Parser {
self.level -= 1;
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) => {
let tuple_pat = self
.convert_tuple_to_tuple_pat(tuple)
@ -1573,7 +1688,7 @@ impl Parser {
}
other => {
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);
Err(())
}
@ -1583,22 +1698,14 @@ impl Parser {
fn convert_accessor_to_var_sig(&mut self, _accessor: Accessor) -> ParseResult<VarSignature> {
debug_call_info!(self);
match _accessor {
Accessor::Local(local) => {
let pat = VarPattern::Ident(Identifier::new(None, VarName::new(local.symbol)));
self.level -= 1;
Ok(VarSignature::new(pat, None))
}
Accessor::Public(public) => {
let pat = VarPattern::Ident(Identifier::new(
Some(public.dot),
VarName::new(public.symbol),
));
Accessor::Ident(ident) => {
let pat = VarPattern::Ident(ident);
self.level -= 1;
Ok(VarSignature::new(pat, None))
}
other => {
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);
Err(())
}
@ -1610,12 +1717,54 @@ impl Parser {
todo!()
}
fn convert_record_to_record_pat(
&mut self,
_record: NormalRecord,
) -> ParseResult<VarRecordPattern> {
fn convert_record_to_record_pat(&mut self, record: Record) -> ParseResult<VarRecordPattern> {
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> {
@ -1675,7 +1824,7 @@ impl Parser {
.map_err(|_| self.stack_dec())?,
other => {
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);
return Err(());
}
@ -1691,13 +1840,10 @@ impl Parser {
fn convert_accessor_to_ident(&mut self, _accessor: Accessor) -> ParseResult<Identifier> {
debug_call_info!(self);
let ident = match _accessor {
Accessor::Local(local) => Identifier::new(None, VarName::new(local.symbol)),
Accessor::Public(public) => {
Identifier::new(Some(public.dot), VarName::new(public.symbol))
}
Accessor::Ident(ident) => ident,
other => {
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);
return Err(());
}
@ -1747,15 +1893,15 @@ impl Parser {
) -> ParseResult<ParamSignature> {
debug_call_info!(self);
match expr {
Expr::Accessor(Accessor::Local(local)) => {
if &local.inspect()[..] == "self" && !allow_self {
Expr::Accessor(Accessor::Ident(ident)) => {
if &ident.inspect()[..] == "self" && !allow_self {
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);
return Err(());
}
let name = VarName::new(local.symbol);
let pat = ParamPattern::VarName(name);
// FIXME deny: public
let pat = ParamPattern::VarName(ident.name);
let param = ParamSignature::new(pat, None, None);
self.level -= 1;
Ok(param)
@ -1800,45 +1946,36 @@ impl Parser {
self.level -= 1;
Ok(param)
}
Expr::Call(mut call) => match *call.obj {
Expr::Accessor(Accessor::Local(local)) => match &local.inspect()[..] {
"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::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 => {
Expr::UnaryOp(unary) => match unary.op.kind {
TokenKind::RefOp => {
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::Ref(var.name);
let param = ParamSignature::new(pat, None, None);
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);
Err(())
}
},
other => {
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);
Err(())
}
@ -1864,7 +2001,7 @@ impl Parser {
fn convert_record_to_param_record_pat(
&mut self,
_record: NormalRecord,
_record: Record,
) -> ParseResult<ParamRecordPattern> {
debug_call_info!(self);
todo!()
@ -1937,7 +2074,7 @@ impl Parser {
}
other => {
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);
Err(())
}
@ -1981,10 +2118,7 @@ impl Parser {
todo!()
}
fn convert_record_to_param_pat(
&mut self,
_record: NormalRecord,
) -> ParseResult<ParamRecordPattern> {
fn convert_record_to_param_pat(&mut self, _record: Record) -> ParseResult<ParamRecordPattern> {
debug_call_info!(self);
todo!()
}
@ -2038,10 +2172,9 @@ impl Parser {
) -> ParseResult<PreDeclTypeSpec> {
debug_call_info!(self);
let t_spec = match accessor {
Accessor::Local(local) => PreDeclTypeSpec::Simple(SimpleTypeSpec::new(
VarName::new(local.symbol),
ConstArgs::empty(),
)),
Accessor::Ident(ident) => {
PreDeclTypeSpec::Simple(SimpleTypeSpec::new(ident.name, ConstArgs::empty()))
}
other => todo!("{other}"),
};
self.level -= 1;

View file

@ -103,6 +103,10 @@ pub enum TokenKind {
DotOp,
/// `cross` (vector product)
CrossOp,
/// `ref` (special unary)
RefOp,
/// `ref!` (special unary)
RefMutOp,
/// =
Equal,
/// :=
@ -183,10 +187,8 @@ pub enum TokenCategory {
LambdaOp,
/// \n ;
Separator,
/// ^ (reserved)
Caret,
/// &
Amper,
/// ^ &
Reserved,
/// @
AtSign,
/// |
@ -210,7 +212,7 @@ impl TokenKind {
Symbol => TokenCategory::Symbol,
NatLit | IntLit | RatioLit | StrLit | BoolLit | NoneLit | EllipsisLit | NoImplLit
| InfLit => TokenCategory::Literal,
PrePlus | PreMinus | PreBitNot | Mutate => TokenCategory::UnaryOp,
PrePlus | PreMinus | PreBitNot | Mutate | RefOp | RefMutOp => TokenCategory::UnaryOp,
Try => TokenCategory::PostfixOp,
Comma | Colon | DblColon | SupertypeOf | SubtypeOf | Dot | Pipe | Walrus => {
TokenCategory::SpecialBinOp
@ -220,8 +222,7 @@ impl TokenKind {
Semi | Newline => TokenCategory::Separator,
LParen | LBrace | LSqBr | Indent => TokenCategory::LEnclosure,
RParen | RBrace | RSqBr | Dedent => TokenCategory::REnclosure,
Caret => TokenCategory::Caret,
Amper => TokenCategory::Amper,
Caret | Amper => TokenCategory::Reserved,
AtSign => TokenCategory::AtSign,
VBar => TokenCategory::VBar,
UBar => TokenCategory::UBar,
@ -234,16 +235,16 @@ impl TokenKind {
pub const fn precedence(&self) -> Option<usize> {
let prec = match self {
Dot | DblColon => 200, // .
Pow => 190, // **
PrePlus | PreMinus | PreBitNot => 180, // (unary) + - * ~
Star | Slash | FloorDiv | Mod | CrossOp | DotOp => 170, // * / // % cross dot
Plus | Minus => 160, // + -
Shl | Shr => 150, // << >>
BitAnd => 140, // &&
BitXor => 130, // ^^
BitOr => 120, // ||
Closed | LeftOpen | RightOpen | Open => 100, // range operators
Dot | DblColon => 200, // .
Pow => 190, // **
PrePlus | PreMinus | PreBitNot | RefOp | RefMutOp => 180, // (unary) + - * ~ ref ref!
Star | Slash | FloorDiv | Mod | CrossOp | DotOp => 170, // * / // % cross dot
Plus | Minus => 160, // + -
Shl | Shr => 150, // << >>
BitAnd => 140, // &&
BitXor => 130, // ^^
BitOr => 120, // ||
Closed | LeftOpen | RightOpen | Open => 100, // range operators
Less | Gre | LessEq | GreEq | DblEq | NotEq | InOp | NotInOp | IsOp | IsNotOp => 90, // < > <= >= == != in notin is isnot
AndOp => 80, // and
OrOp => 70, // or
@ -372,6 +373,16 @@ impl Token {
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 {
Token {
kind: TokenKind::Symbol,

View file

@ -1,6 +1,6 @@
[package]
name = "erg_type"
version = "0.3.2"
version = "0.4.0-beta.1"
description = "APIs for Erg types"
authors = ["Shunsuke Shibayama <sbym1346@gmail.com>"]
license = "MIT OR Apache-2.0"
@ -18,7 +18,7 @@ simplified_chinese = [ "erg_common/simplified_chinese" ]
traditional_chinese = [ "erg_common/traditional_chinese" ]
[dependencies]
erg_common = { version = "0.3.2", path = "../erg_common" }
erg_common = { version = "0.4.0-beta.1", path = "../erg_common" }
[lib]
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 {
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 {
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 {
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 {
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]
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 {
@ -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 {
poly_class("Iter", vec![TyParam::t(t)])
poly("Iter", vec![TyParam::t(t)])
}
pub fn ref_(t: Type) -> Type {
Type::Ref(Box::new(t))
}
pub fn ref_mut(t: Type) -> Type {
Type::RefMut(Box::new(t))
pub fn ref_mut(before: Type, after: Option<Type>) -> Type {
Type::RefMut {
before: Box::new(before),
after: after.map(Box::new),
}
}
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 {
poly_class("Option!", vec![TyParam::t(t)])
poly("Option!", vec![TyParam::t(t)])
}
pub fn subr_t(
@ -207,13 +210,14 @@ pub fn proc2(l: Type, r: Type, return_t: Type) -> Type {
pub fn fn_met(
self_t: Type,
non_default_params: Vec<ParamTy>,
mut non_default_params: Vec<ParamTy>,
var_params: Option<ParamTy>,
default_params: Vec<ParamTy>,
return_t: Type,
) -> Type {
non_default_params.insert(0, ParamTy::kw(Str::ever("self"), self_t));
Type::Subr(SubrType::new(
SubrKind::FuncMethod(Box::new(self_t)),
SubrKind::Func,
non_default_params,
var_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(
self_before: Type,
self_after: Option<Type>,
non_default_params: Vec<ParamTy>,
self_t: Type,
mut non_default_params: Vec<ParamTy>,
var_params: Option<ParamTy>,
default_params: Vec<ParamTy>,
return_t: Type,
) -> Type {
non_default_params.insert(0, ParamTy::kw(Str::ever("self"), self_t));
Type::Subr(SubrType::new(
SubrKind::pr_met(self_before, self_after),
SubrKind::Proc,
non_default_params,
var_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 {
pr_met(self_before, self_after, vec![], None, vec![], return_t)
pub fn pr0_met(self_t: Type, return_t: Type) -> Type {
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(
self_before,
self_after,
self_t,
vec![ParamTy::anonymous(input_t)],
None,
vec![],
@ -286,13 +289,8 @@ pub fn callable(param_ts: Vec<Type>, return_t: Type) -> Type {
}
#[inline]
pub fn class<S: Into<Str>>(name: S) -> Type {
Type::MonoClass(name.into())
}
#[inline]
pub fn trait_<S: Into<Str>>(name: S) -> Type {
Type::MonoTrait(name.into())
pub fn mono<S: Into<Str>>(name: S) -> Type {
Type::Mono(name.into())
}
#[inline]
@ -301,16 +299,8 @@ pub fn mono_q<S: Into<Str>>(name: S) -> Type {
}
#[inline]
pub fn poly_class<S: Into<Str>>(name: S, params: Vec<TyParam>) -> Type {
Type::PolyClass {
name: name.into(),
params,
}
}
#[inline]
pub fn poly_trait<S: Into<Str>>(name: S, params: Vec<TyParam>) -> Type {
Type::PolyTrait {
pub fn poly<S: Into<Str>>(name: S, params: Vec<TyParam>) -> Type {
Type::Poly {
name: name.into(),
params,
}

View file

@ -107,23 +107,38 @@ impl LimitedDisplay for Constraint {
sup,
cyclicity,
} => 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) => {
write!(f, "<: ")?;
sup.limited_fmt(f, limit - 1)?;
write!(f, "(cyclicity: {cyclicity:?})")
if cfg!(feature = "debug") {
write!(f, "(cyclicity: {cyclicity:?})")?;
}
Ok(())
}
(false, true) => {
write!(f, ":> ")?;
sub.limited_fmt(f, limit - 1)?;
write!(f, "(cyclicity: {cyclicity:?})")
if cfg!(feature = "debug") {
write!(f, "(cyclicity: {cyclicity:?})")?;
}
Ok(())
}
(false, false) => {
write!(f, ":> ")?;
sub.limited_fmt(f, limit - 1)?;
write!(f, ", <: ")?;
sup.limited_fmt(f, limit - 1)?;
write!(f, "(cyclicity: {cyclicity:?})")
if cfg!(feature = "debug") {
write!(f, "(cyclicity: {cyclicity:?})")?;
}
Ok(())
}
},
Self::TypeOf(t) => {
@ -136,7 +151,7 @@ impl LimitedDisplay for 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 {
sub,
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 {
Self::sandwiched(Type::Never, Type::Obj, Not)
Self::new_sandwiched(Type::Never, Type::Obj, Not)
} else {
Self::TypeOf(t)
}
}
pub const fn subtype_of(sup: Type, cyclicity: Cyclicity) -> Self {
Self::sandwiched(Type::Never, sup, cyclicity)
pub const fn new_subtype_of(sup: Type, cyclicity: Cyclicity) -> Self {
Self::new_sandwiched(Type::Never, sup, cyclicity)
}
pub const fn supertype_of(sub: Type, cyclicity: Cyclicity) -> Self {
Self::sandwiched(sub, Type::Obj, cyclicity)
pub const fn new_supertype_of(sub: Type, cyclicity: Cyclicity) -> Self {
Self::new_sandwiched(sub, Type::Obj, cyclicity)
}
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> {
match self {
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 {
Self::Sandwiched { sub, .. } => Some(sub),
_ => None,
}
}
pub fn get_super_type(&self) -> Option<&Type> {
pub fn get_super(&self) -> Option<&Type> {
match self {
Self::Sandwiched { sup, .. } => Some(sup),
_ => None,
}
}
pub fn get_sub_sup_type(&self) -> Option<(&Type, &Type)> {
pub fn get_sub_sup(&self) -> Option<(&Type, &Type)> {
match self {
Self::Sandwiched { sub, sup, .. } => Some((sub, sup)),
_ => None,
}
}
pub fn get_super_type_mut(&mut self) -> Option<&mut Type> {
pub fn get_super_mut(&mut self) -> Option<&mut Type> {
match self {
Self::Sandwiched { sup, .. } => Some(sup),
_ => None,
@ -250,7 +276,11 @@ impl<T: LimitedDisplay> LimitedDisplay for FreeKind<T> {
return write!(f, "...");
}
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 {
name,
lev,
@ -258,7 +288,11 @@ impl<T: LimitedDisplay> LimitedDisplay for FreeKind<T> {
} => {
write!(f, "?{name}(")?;
constraint.limited_fmt(f, limit - 1)?;
write!(f, ")[{lev}]")
write!(f, ")")?;
if cfg!(feature = "debug") {
write!(f, "[{lev}]")?;
}
Ok(())
}
Self::Unbound {
id,
@ -267,7 +301,11 @@ impl<T: LimitedDisplay> LimitedDisplay for FreeKind<T> {
} => {
write!(f, "?{id}(")?;
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) {
match &mut *self.borrow_mut() {
FreeKind::Unbound { lev, .. } | FreeKind::NamedUnbound { lev, .. } => {
FreeKind::Unbound {
lev, constraint, ..
}
| FreeKind::NamedUnbound {
lev, constraint, ..
} => {
*lev += 1;
constraint.lift();
}
FreeKind::Linked(t) | FreeKind::UndoableLinked { t, .. } => {
if let Some(lev) = t.level() {
t.update_level(lev + 1);
}
t.lift();
}
}
}
@ -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()
.constraint()
.and_then(|c| c.get_type().cloned())
}
pub fn crack_subtype(&self) -> Option<Type> {
pub fn get_sup(&self) -> Option<Type> {
self.borrow()
.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)> {
self.borrow().constraint().and_then(|c| {
c.get_sub_sup_type()
.map(|(sub, sup)| (sub.clone(), sup.clone()))
})
pub fn get_bound_types(&self) -> Option<(Type, Type)> {
self.borrow()
.constraint()
.and_then(|c| c.get_sub_sup().map(|(sub, sup)| (sub.clone(), sup.clone())))
}
pub fn is_unbound(&self) -> bool {
@ -542,7 +583,7 @@ impl<T: Clone + HasLevel> Free<T> {
matches!(
&*self.borrow(),
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!(
&*self.borrow(),
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!(
&*self.borrow(),
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 {
matches!(&*self.borrow(), FreeKind::Linked(_))
matches!(
&*self.borrow(),
FreeKind::Linked(_) | FreeKind::UndoableLinked { .. }
)
}
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 {
let constraint = Constraint::type_of(t);
let constraint = Constraint::new_type_of(t);
Self::FreeVar(FreeTyParam::new_unbound(level, constraint))
}
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))
}

View file

@ -17,11 +17,92 @@ use erg_common::{fmt_iter, impl_display_from_debug, switch_lang};
use erg_common::{RcArray, Str};
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::typaram::TyParam;
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)]
@ -37,7 +118,7 @@ pub enum ValueObj {
Record(Dict<Field, ValueObj>),
Code(Box<CodeObj>),
Subr(ConstSubr),
Type(Box<Type>),
Type(TypeObj),
None,
Ellipsis,
NotImplemented,
@ -92,7 +173,7 @@ impl fmt::Debug for ValueObj {
}
write!(f, "}}")
}
Self::Subr(subr) => write!(f, "{subr:?}"),
Self::Subr(subr) => write!(f, "{subr}"),
Self::Type(t) => write!(f, "{t}"),
Self::None => write!(f, "None"),
Self::Ellipsis => write!(f, "Ellipsis"),
@ -262,8 +343,24 @@ impl HasType for ValueObj {
}
impl ValueObj {
pub fn t(t: Type) -> Self {
ValueObj::Type(Box::new(t))
pub fn builtin_t(t: Type) -> Self {
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 {
@ -274,6 +371,10 @@ impl ValueObj {
}
}
pub const fn is_type(&self) -> bool {
matches!(self, Self::Type(_))
}
pub const fn is_mut(&self) -> bool {
matches!(self, Self::Mut(_))
}
@ -376,20 +477,24 @@ impl ValueObj {
Self::Record(rec) => {
Type::Record(rec.iter().map(|(k, v)| (k.clone(), v.class())).collect())
}
Self::Subr(_) => todo!(),
Self::Type(_) => Type::Type,
Self::Subr(subr) => subr.class(),
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::Ellipsis => Type::Ellipsis,
Self::NotImplemented => Type::NotImplemented,
Self::Inf => Type::Inf,
Self::NegInf => Type::NegInf,
Self::Mut(m) => match &*m.borrow() {
Self::Int(_) => class("Int!"),
Self::Nat(_) => class("Nat!"),
Self::Float(_) => class("Float!"),
Self::Str(_) => class("Str!"),
Self::Bool(_) => class("Bool!"),
Self::Array(arr) => poly_class(
Self::Int(_) => mono("Int!"),
Self::Nat(_) => mono("Nat!"),
Self::Float(_) => mono("Float!"),
Self::Str(_) => mono("Str!"),
Self::Bool(_) => mono("Bool!"),
Self::Array(arr) => poly(
"Array!",
vec![
TyParam::t(arr.iter().next().unwrap().class()),
@ -641,6 +746,26 @@ impl ValueObj {
_ => 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 {

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 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.
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.
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 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."?

View file

@ -227,9 +227,9 @@ print! {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.
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`
D = Inherit {i = Int}
e = D.new {i = 1}
f = D.new {i = 2}
print! e # D{i = 1}
e = D::{i = 1} # same as `e = D.new {i = 1}`
f = D::{i = 2}
print! e # D(i=1)
assert e ! = f
```

View file

@ -1,6 +1,6 @@
# 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_technical.md)を、文法の決定経緯(なぜこのような文法になったのか)などについては

View file

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

View file

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

View file

@ -1,7 +1,7 @@
Point = Class {x = Int; y = Int}, Impl := Add() and Eq()
Point.
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()
`+` self, other =
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
Point2D = Class {x = Int; y = Int}
Point2D::
one = 1
Point2D.
new x, y = Self::__new__ {x = x; y = y}
norm ref self = self::x**2 + self::y**2
zero = Point2D::one - 1
norm self = self::x**2 + self::y**2
Point3D = Inherit Point2D, Additional := {z = Int}
Point3D.
# Overloading is prohibited by default. Remove this decorator and check for errors.
@Override
new x, y, z = Self::__new__ {x = x; y = y; z = z}
new x, y, z =
Point3D::__new__ {x; y; z}
@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
p = UnpackPoint2D::{x = 1; y = 2}
UnpackPoint2D::{x = x; y = x} = p
# `Point2D::__new__` is private, use `Point2D.new` instead
p = Point2D.new {x = 1; y = 2}
print! p, p.norm()
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