mirror of
https://github.com/erg-lang/erg.git
synced 2025-09-30 12:51:10 +00:00
Merge branch 'class' into beta
This commit is contained in:
commit
2d365dce3b
15 changed files with 349 additions and 124 deletions
|
@ -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
|
||||
|
|
|
@ -203,9 +203,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 {
|
||||
|
@ -240,16 +240,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),
|
||||
|
@ -259,7 +262,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),
|
||||
|
@ -351,6 +357,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}
|
||||
|
@ -430,13 +471,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(),
|
||||
};
|
||||
|
@ -454,40 +497,27 @@ 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,
|
||||
} => {
|
||||
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()));
|
||||
}
|
||||
res += &format!(
|
||||
"{lineno}{VBAR_UNICODE} {code}\n{pointer}\n",
|
||||
code = codes[i]
|
||||
);
|
||||
}
|
||||
res + RESET
|
||||
}
|
||||
} => 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()]
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -407,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),
|
||||
|
@ -417,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),
|
||||
|
|
|
@ -32,7 +32,7 @@ use crate::error::{CompileError, CompileErrors, CompileResult};
|
|||
use crate::hir::AttrDef;
|
||||
use crate::hir::Attribute;
|
||||
use crate::hir::{
|
||||
Accessor, Args, Array, Block, Call, ClassDef, Def, DefBody, Expr, Literal, Local, Signature,
|
||||
Accessor, Args, Array, Block, Call, ClassDef, DefBody, Expr, Literal, Local, PosArg, Signature,
|
||||
SubrSignature, Tuple, VarSignature, HIR,
|
||||
};
|
||||
use AccessKind::*;
|
||||
|
@ -202,7 +202,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" | "__new__") => Str::ever("__call__"),
|
||||
(_, _, "__new__") => Str::ever("__call__"),
|
||||
("StringIO!", _, "getvalue!") => Str::ever("getvalue"),
|
||||
("Module", Some("importlib"), "reload!") => Str::ever("reload"),
|
||||
("Module", Some("random"), "randint!") => Str::ever("randint"),
|
||||
|
@ -446,7 +446,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()
|
||||
|
@ -454,11 +454,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))
|
||||
}
|
||||
} else if let Some(idx) = self
|
||||
.cur_block_codeobj()
|
||||
.varnames
|
||||
|
@ -667,6 +663,8 @@ impl CodeGenerator {
|
|||
}
|
||||
}
|
||||
|
||||
/// Ergの文法として、属性への代入は存在しない(必ずオブジェクトはすべての属性を初期化しなくてはならないため)
|
||||
/// この関数はPythonへ落とし込むときに使う
|
||||
fn store_acc(&mut self, acc: Accessor) {
|
||||
log!(info "entered {} ({acc})", fn_name!());
|
||||
match acc {
|
||||
|
@ -719,6 +717,11 @@ impl CodeGenerator {
|
|||
.non_defaults
|
||||
.iter()
|
||||
.map(|p| p.inspect().map(|s| &s[..]).unwrap_or("_"))
|
||||
.chain(if let Some(var_args) = ¶ms.var_args {
|
||||
vec![var_args.inspect().map(|s| &s[..]).unwrap_or("_")]
|
||||
} else {
|
||||
vec![]
|
||||
})
|
||||
.chain(
|
||||
params
|
||||
.defaults
|
||||
|
@ -783,7 +786,7 @@ 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;
|
||||
|
@ -800,7 +803,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>
|
||||
|
@ -989,12 +996,15 @@ impl CodeGenerator {
|
|||
Expr::Accessor(Accessor::Local(local)) => {
|
||||
self.emit_call_local(local, call.args).unwrap()
|
||||
}
|
||||
other => todo!("calling {other}"),
|
||||
other => {
|
||||
self.codegen_expr(other);
|
||||
self.emit_args(call.args, Name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn emit_call_local(&mut self, local: Local, mut args: Args) -> CompileResult<()> {
|
||||
fn emit_call_local(&mut self, local: Local, args: Args) -> CompileResult<()> {
|
||||
log!(info "entered {}", fn_name!());
|
||||
match &local.inspect()[..] {
|
||||
"assert" => self.emit_assert_instr(args),
|
||||
|
@ -1008,33 +1018,13 @@ impl CodeGenerator {
|
|||
self.emit_load_name_instr(ident).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: Token, args: Args) {
|
||||
log!(info "entered {}", fn_name!());
|
||||
if &method_name.inspect()[..] == "update!" {
|
||||
return self.emit_call_update(obj, args);
|
||||
|
@ -1050,11 +1040,29 @@ impl CodeGenerator {
|
|||
.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);
|
||||
|
@ -1063,13 +1071,27 @@ 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 {
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -1149,7 +1171,7 @@ 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),
|
||||
|
@ -1420,14 +1442,17 @@ impl CodeGenerator {
|
|||
let mod_name = self.toplevel_block_codeobj().name.clone();
|
||||
self.emit_load_const(mod_name);
|
||||
self.emit_store_instr(Identifier::public("__module__"), Name);
|
||||
self.emit_load_const(name);
|
||||
self.emit_load_const(name.clone());
|
||||
self.emit_store_instr(Identifier::public("__qualname__"), Name);
|
||||
self.emit_init_method(&class.sig, class.__new__.clone());
|
||||
if class.need_to_gen_new {
|
||||
self.emit_auto_new(&class.sig, class.__new__);
|
||||
self.emit_new_func(&class.sig, class.__new__);
|
||||
}
|
||||
// TODO: サブルーチンはT.subという書式でSTORE
|
||||
for def in class.private_methods.into_iter() {
|
||||
self.codegen_expr(Expr::Def(def));
|
||||
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();
|
||||
|
@ -1435,7 +1460,10 @@ impl CodeGenerator {
|
|||
}
|
||||
for mut def in class.public_methods.into_iter() {
|
||||
def.sig.ident_mut().dot = Some(Token::dummy());
|
||||
self.codegen_expr(Expr::Def(def));
|
||||
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();
|
||||
|
@ -1474,9 +1502,10 @@ impl CodeGenerator {
|
|||
unit.codeobj
|
||||
}
|
||||
|
||||
fn emit_auto_new(&mut self, sig: &Signature, __new__: Type) {
|
||||
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);
|
||||
|
@ -1484,7 +1513,7 @@ impl CodeGenerator {
|
|||
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 sig = Signature::Subr(SubrSignature::new(ident, params.clone(), __new__.clone()));
|
||||
let subr_sig = SubrSignature::new(ident, params.clone(), __new__.clone());
|
||||
let mut attrs = vec![];
|
||||
match __new__.non_default_params().unwrap()[0].typ() {
|
||||
// {x = Int; y = Int}
|
||||
|
@ -1519,8 +1548,49 @@ impl CodeGenerator {
|
|||
}
|
||||
let block = Block::new(attrs);
|
||||
let body = DefBody::new(Token::dummy(), block, DefId(0));
|
||||
let init_def = Def::new(sig, body.clone());
|
||||
self.codegen_expr(Expr::Def(init_def));
|
||||
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::local(
|
||||
Token::symbol_with_line(¶m_name[..], line),
|
||||
Type::Failure,
|
||||
)));
|
||||
let class = Expr::Accessor(Accessor::local(
|
||||
Token::symbol_with_line(class_name, line),
|
||||
Type::Failure,
|
||||
));
|
||||
let class_new = Expr::Accessor(Accessor::attr(
|
||||
class,
|
||||
Token::symbol_with_line("__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 {
|
||||
|
|
|
@ -80,6 +80,10 @@ impl Context {
|
|||
})
|
||||
}
|
||||
|
||||
pub(crate) fn get_local_kv(&self, name: &str) -> Option<(&VarName, &VarInfo)> {
|
||||
self.locals.get_key_value(name)
|
||||
}
|
||||
|
||||
fn get_context(
|
||||
&self,
|
||||
obj: &hir::Expr,
|
||||
|
|
|
@ -490,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,
|
||||
|
|
|
@ -508,6 +508,7 @@ impl Context {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
/// e.g. .new
|
||||
fn register_auto_impl(
|
||||
&mut self,
|
||||
name: &'static str,
|
||||
|
@ -524,6 +525,23 @@ impl Context {
|
|||
}
|
||||
}
|
||||
|
||||
/// 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}");
|
||||
|
@ -577,11 +595,13 @@ impl Context {
|
|||
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());
|
||||
ctx.register_auto_impl("__new__", new_t.clone(), Immutable, Private);
|
||||
methods.register_fixed_auto_impl("__new__", new_t.clone(), Immutable, Private);
|
||||
// 必要なら、ユーザーが独自に上書きする
|
||||
ctx.register_auto_impl("new", new_t, Immutable, Public);
|
||||
methods.register_auto_impl("new", new_t, Immutable, Public);
|
||||
ctx.method_defs.push((gen.t.clone(), methods));
|
||||
self.register_gen_mono_type(gen, ctx, Const);
|
||||
} else {
|
||||
todo!()
|
||||
|
@ -593,6 +613,7 @@ impl Context {
|
|||
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 {
|
||||
|
@ -607,9 +628,15 @@ impl Context {
|
|||
param_t.clone()
|
||||
};
|
||||
let new_t = func1(param_t, gen.t.clone());
|
||||
ctx.register_auto_impl("__new__", new_t.clone(), Immutable, Private);
|
||||
methods.register_fixed_auto_impl(
|
||||
"__new__",
|
||||
new_t.clone(),
|
||||
Immutable,
|
||||
Private,
|
||||
);
|
||||
// 必要なら、ユーザーが独自に上書きする
|
||||
ctx.register_auto_impl("new", new_t, Immutable, Public);
|
||||
methods.register_auto_impl("new", new_t, Immutable, Public);
|
||||
ctx.method_defs.push((gen.t.clone(), methods));
|
||||
self.register_gen_mono_type(gen, ctx, Const);
|
||||
} else {
|
||||
todo!("super class not found")
|
||||
|
|
|
@ -331,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,
|
||||
|
|
|
@ -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]
|
||||
|
@ -1338,7 +1347,7 @@ pub struct ClassDef {
|
|||
pub kind: TypeKind,
|
||||
pub sig: Signature,
|
||||
pub require_or_sup: Box<Expr>,
|
||||
/// The type of `new` and `__new__` that is automatically defined if not defined
|
||||
/// The type of `new` that is automatically defined if not defined
|
||||
pub need_to_gen_new: bool,
|
||||
pub __new__: Type,
|
||||
pub private_methods: RecordAttrs,
|
||||
|
|
|
@ -50,12 +50,12 @@ impl Linker {
|
|||
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 type_def = match new.remove(*pos) {
|
||||
Expr::ClassDef(type_def) => type_def,
|
||||
let mut class_def = match new.remove(*pos) {
|
||||
Expr::ClassDef(class_def) => class_def,
|
||||
_ => unreachable!(),
|
||||
};
|
||||
type_def.methods_list.push(methods);
|
||||
new.insert(*pos, Expr::ClassDef(type_def));
|
||||
class_def.methods_list.push(methods);
|
||||
new.insert(*pos, Expr::ClassDef(class_def));
|
||||
} else {
|
||||
log!("{}", simple.name.inspect());
|
||||
log!("{}", self.def_root_pos_map);
|
||||
|
|
|
@ -330,6 +330,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,
|
||||
);
|
||||
|
@ -368,7 +369,7 @@ impl ASTLowerer {
|
|||
&[],
|
||||
&self.ctx.name,
|
||||
)?;
|
||||
let args = hir::Args::new(args, vec![], None);
|
||||
let args = hir::Args::new(args, None, vec![], None);
|
||||
Ok(hir::Call::new(class, Some(method_name), args, sig_t))
|
||||
}
|
||||
|
||||
|
@ -570,10 +571,33 @@ impl ASTLowerer {
|
|||
}
|
||||
}
|
||||
match self.ctx.pop() {
|
||||
Ok(ctx) => {
|
||||
self.check_override(&class, &ctx);
|
||||
Ok(methods) => {
|
||||
self.check_override(&class, &methods);
|
||||
if let Some((_, class_root)) = self.ctx.rec_get_mut_nominal_type_ctx(&class) {
|
||||
class_root.method_defs.push((class, ctx));
|
||||
for (newly_defined_name, _vi) in methods.locals.iter() {
|
||||
for (_, already_defined_methods) in class_root.method_defs.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.method_defs.push((class, methods));
|
||||
} else {
|
||||
todo!()
|
||||
}
|
||||
|
@ -589,8 +613,11 @@ impl ASTLowerer {
|
|||
.unwrap();
|
||||
let type_obj = enum_unwrap!(self.ctx.rec_get_const_obj(hir_def.sig.ident().inspect()).unwrap(), ValueObj::Type:(TypeObj::Generated:(_)));
|
||||
// vi.t.non_default_params().unwrap()[0].typ().clone()
|
||||
let (__new__, need_to_gen_new) = if let Some(vi) = ctx.get_current_scope_var("new") {
|
||||
(vi.t.clone(), vi.kind == VarKind::Auto)
|
||||
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!()
|
||||
};
|
||||
|
|
|
@ -68,6 +68,7 @@ pub enum VarKind {
|
|||
default: DefaultInfo,
|
||||
},
|
||||
Auto,
|
||||
FixedAuto,
|
||||
DoesNotExist,
|
||||
Builtin,
|
||||
}
|
||||
|
|
|
@ -2236,9 +2236,6 @@ pub enum ParamPattern {
|
|||
// DataPack(ParamDataPackPattern),
|
||||
Ref(VarName),
|
||||
RefMut(VarName),
|
||||
// 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])
|
||||
VarArgs(VarName),
|
||||
}
|
||||
|
||||
impl NestedDisplay for ParamPattern {
|
||||
|
@ -2252,20 +2249,17 @@ impl NestedDisplay for ParamPattern {
|
|||
Self::Record(record) => write!(f, "{}", record),
|
||||
Self::Ref(var_name) => write!(f, "ref {}", var_name),
|
||||
Self::RefMut(var_name) => write!(f, "ref! {}", var_name),
|
||||
Self::VarArgs(var_name) => write!(f, "...{}", var_name),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl_display_from_nested!(ParamPattern);
|
||||
impl_locational_for_enum!(ParamPattern; Discard, VarName, Lit, Array, Tuple, Record, Ref, RefMut, VarArgs);
|
||||
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::VarArgs(n) | Self::Ref(n) | Self::RefMut(n) => {
|
||||
Some(n.inspect())
|
||||
}
|
||||
Self::VarName(n) | Self::Ref(n) | Self::RefMut(n) => Some(n.inspect()),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
@ -2277,9 +2271,7 @@ impl ParamPattern {
|
|||
pub fn is_procedural(&self) -> bool {
|
||||
match self {
|
||||
Self::Discard(_) => true,
|
||||
Self::VarName(n) | Self::VarArgs(n) | Self::Ref(n) | Self::RefMut(n) => {
|
||||
n.is_procedural()
|
||||
}
|
||||
Self::VarName(n) | Self::Ref(n) | Self::RefMut(n) => n.is_procedural(),
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
@ -2287,7 +2279,7 @@ impl ParamPattern {
|
|||
pub fn is_const(&self) -> bool {
|
||||
match self {
|
||||
Self::Discard(_) => true,
|
||||
Self::VarName(n) | Self::VarArgs(n) | Self::Ref(n) | Self::RefMut(n) => n.is_const(),
|
||||
Self::VarName(n) | Self::Ref(n) | Self::RefMut(n) => n.is_const(),
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
@ -2381,7 +2373,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 {
|
||||
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 {
|
||||
|
|
|
@ -7,9 +7,12 @@ Point3D = Inherit Point2D, Additional := {z = Int}
|
|||
Point3D.
|
||||
# Overloading is prohibited by default. Remove this decorator and check for errors.
|
||||
@Override
|
||||
new x, y, z = Point3D::__new__ {x; y; z}
|
||||
new x, y, z =
|
||||
Point3D::__new__ {x; y; z}
|
||||
@Override
|
||||
norm self = self::x**2 + self::y**2 + self::z**2
|
||||
|
||||
p = Point3D.new {x = 1; y = 2; z = 3}
|
||||
print! p.norm()
|
||||
p = Point2D.new {x = 1; y = 2}
|
||||
print! p, p.norm()
|
||||
q = Point3D.new 1, 2, 3
|
||||
print! q, q.norm()
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue