Merge branch 'class' into beta

This commit is contained in:
Shunsuke Shibayama 2022-09-09 14:18:44 +09:00
commit 2d365dce3b
15 changed files with 349 additions and 124 deletions

View file

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

View file

@ -203,9 +203,9 @@ impl From<&str> for ErrorKind {
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum Location { pub enum Location {
RangePair { RangePair {
ln_begin: usize, ln_first: (usize, usize),
col_first: (usize, usize), col_first: (usize, usize),
ln_end: usize, ln_second: (usize, usize),
col_second: (usize, usize), col_second: (usize, usize),
}, },
Range { Range {
@ -240,16 +240,19 @@ impl Location {
pub fn pair(lhs: Self, rhs: Self) -> Self { pub fn pair(lhs: Self, rhs: Self) -> Self {
Self::RangePair { Self::RangePair {
ln_begin: lhs.ln_begin().unwrap(), ln_first: (lhs.ln_begin().unwrap(), lhs.ln_end().unwrap()),
col_first: (lhs.col_begin().unwrap(), lhs.col_end().unwrap()), col_first: (lhs.col_begin().unwrap(), lhs.col_end().unwrap()),
ln_end: rhs.ln_end().unwrap(), ln_second: (rhs.ln_begin().unwrap(), rhs.ln_end().unwrap()),
col_second: (rhs.col_begin().unwrap(), rhs.col_end().unwrap()), col_second: (rhs.col_begin().unwrap(), rhs.col_end().unwrap()),
} }
} }
pub const fn ln_begin(&self) -> Option<usize> { pub const fn ln_begin(&self) -> Option<usize> {
match self { match self {
Self::RangePair { ln_begin, .. } Self::RangePair {
ln_first: (ln_begin, _),
..
}
| Self::Range { ln_begin, .. } | Self::Range { ln_begin, .. }
| Self::LineRange(ln_begin, _) | Self::LineRange(ln_begin, _)
| Self::Line(ln_begin) => Some(*ln_begin), | Self::Line(ln_begin) => Some(*ln_begin),
@ -259,7 +262,10 @@ impl Location {
pub const fn ln_end(&self) -> Option<usize> { pub const fn ln_end(&self) -> Option<usize> {
match self { match self {
Self::RangePair { ln_end, .. } Self::RangePair {
ln_second: (_, ln_end),
..
}
| Self::Range { ln_end, .. } | Self::Range { ln_end, .. }
| Self::LineRange(ln_end, _) | Self::LineRange(ln_end, _)
| Self::Line(ln_end) => Some(*ln_end), | Self::Line(ln_end) => Some(*ln_end),
@ -351,6 +357,41 @@ impl ErrorCore {
pub const VBAR_UNICODE: &str = ""; pub const VBAR_UNICODE: &str = "";
pub const VBAR_BREAK_UNICODE: &str = "·"; pub const VBAR_BREAK_UNICODE: &str = "·";
fn format_code_and_pointer<E: ErrorDisplay + ?Sized>(
e: &E,
ln_begin: usize,
ln_end: usize,
col_begin: usize,
col_end: usize,
) -> String {
let codes = if e.input() == &Input::REPL {
vec![e.input().reread()]
} else {
e.input().reread_lines(ln_begin, ln_end)
};
let mut res = CYAN.to_string();
let final_step = ln_end - ln_begin;
for (i, lineno) in (ln_begin..=ln_end).enumerate() {
let mut pointer = " ".repeat(lineno.to_string().len() + 2); // +2 means `| `
if i == 0 && i == final_step {
pointer += &" ".repeat(col_begin);
pointer += &"^".repeat(cmp::max(1, col_end - col_begin));
} else if i == 0 {
pointer += &" ".repeat(col_begin);
pointer += &"^".repeat(cmp::max(1, codes[i].len() - col_begin));
} else if i == final_step {
pointer += &"^".repeat(col_end);
} else {
pointer += &"^".repeat(cmp::max(1, codes[i].len()));
}
res += &format!(
"{lineno}{VBAR_UNICODE} {code}\n{pointer}\n",
code = codes[i]
);
}
res + RESET
}
/// format: /// format:
/// ```console /// ```console
/// Error[#{.errno}]: File {file}, line {.loc (as line)}, in {.caused_by} /// Error[#{.errno}]: File {file}, line {.loc (as line)}, in {.caused_by}
@ -430,13 +471,15 @@ pub trait ErrorDisplay {
Location::Range { Location::Range {
ln_begin, ln_end, .. ln_begin, ln_end, ..
} if ln_begin == ln_end => format!(", line {ln_begin}"), } if ln_begin == ln_end => format!(", line {ln_begin}"),
Location::RangePair { Location::Range {
ln_begin, ln_end, ..
}
| Location::Range {
ln_begin, ln_end, .. ln_begin, ln_end, ..
} }
| Location::LineRange(ln_begin, ln_end) => format!(", line {ln_begin}..{ln_end}"), | Location::LineRange(ln_begin, ln_end) => format!(", line {ln_begin}..{ln_end}"),
Location::RangePair {
ln_first: (l1, l2),
ln_second: (l3, l4),
..
} => format!(", line {l1}..{l2}, {l3}..{l4}"),
Location::Line(lineno) => format!(", line {lineno}"), Location::Line(lineno) => format!(", line {lineno}"),
Location::Unknown => "".to_string(), Location::Unknown => "".to_string(),
}; };
@ -454,40 +497,27 @@ pub trait ErrorDisplay {
fn format_code_and_pointer(&self) -> String { fn format_code_and_pointer(&self) -> String {
match self.core().loc { match self.core().loc {
Location::RangePair { .. } => todo!(), Location::RangePair {
ln_first,
col_first,
ln_second,
col_second,
} => {
format_code_and_pointer(self, ln_first.0, ln_first.1, col_first.0, col_first.1)
+ &format_code_and_pointer(
self,
ln_second.0,
ln_second.1,
col_second.0,
col_second.1,
)
}
Location::Range { Location::Range {
ln_begin, ln_begin,
col_begin, col_begin,
ln_end, ln_end,
col_end, col_end,
} => { } => format_code_and_pointer(self, ln_begin, ln_end, col_begin, col_end),
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
}
Location::LineRange(ln_begin, ln_end) => { Location::LineRange(ln_begin, ln_end) => {
let codes = if self.input() == &Input::REPL { let codes = if self.input() == &Input::REPL {
vec![self.input().reread()] vec![self.input().reread()]

View file

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

View file

@ -407,7 +407,10 @@ pub trait Locational {
fn ln_begin(&self) -> Option<usize> { fn ln_begin(&self) -> Option<usize> {
match self.loc() { match self.loc() {
Location::RangePair { ln_begin, .. } Location::RangePair {
ln_first: (ln_begin, _),
..
}
| Location::Range { ln_begin, .. } | Location::Range { ln_begin, .. }
| Location::LineRange(ln_begin, _) => Some(ln_begin), | Location::LineRange(ln_begin, _) => Some(ln_begin),
Location::Line(lineno) => Some(lineno), Location::Line(lineno) => Some(lineno),
@ -417,7 +420,10 @@ pub trait Locational {
fn ln_end(&self) -> Option<usize> { fn ln_end(&self) -> Option<usize> {
match self.loc() { match self.loc() {
Location::RangePair { ln_end, .. } Location::RangePair {
ln_second: (_, ln_end),
..
}
| Location::Range { ln_end, .. } | Location::Range { ln_end, .. }
| Location::LineRange(_, ln_end) => Some(ln_end), | Location::LineRange(_, ln_end) => Some(ln_end),
Location::Line(lineno) => Some(lineno), Location::Line(lineno) => Some(lineno),

View file

@ -32,7 +32,7 @@ use crate::error::{CompileError, CompileErrors, CompileResult};
use crate::hir::AttrDef; use crate::hir::AttrDef;
use crate::hir::Attribute; use crate::hir::Attribute;
use crate::hir::{ 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, SubrSignature, Tuple, VarSignature, HIR,
}; };
use AccessKind::*; 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"), ("Array!", _, "push!") => Str::ever("append"),
("Complex" | "Real" | "Int" | "Nat" | "Float", _, "Real") => Str::ever("real"), ("Complex" | "Real" | "Int" | "Nat" | "Float", _, "Real") => Str::ever("real"),
("Complex" | "Real" | "Int" | "Nat" | "Float", _, "Imag") => Str::ever("imag"), ("Complex" | "Real" | "Int" | "Nat" | "Float", _, "Imag") => Str::ever("imag"),
(_, _, "new" | "__new__") => Str::ever("__call__"), (_, _, "__new__") => Str::ever("__call__"),
("StringIO!", _, "getvalue!") => Str::ever("getvalue"), ("StringIO!", _, "getvalue!") => Str::ever("getvalue"),
("Module", Some("importlib"), "reload!") => Str::ever("reload"), ("Module", Some("importlib"), "reload!") => Str::ever("reload"),
("Module", Some("random"), "randint!") => Str::ever("randint"), ("Module", Some("random"), "randint!") => Str::ever("randint"),
@ -446,7 +446,7 @@ impl CodeGenerator {
self.stack_inc(); self.stack_inc();
} }
fn local_search(&self, name: &str, acc_kind: AccessKind) -> Option<Name> { fn local_search(&self, name: &str, _acc_kind: AccessKind) -> Option<Name> {
let current_is_toplevel = self.cur_block() == self.toplevel_block(); let current_is_toplevel = self.cur_block() == self.toplevel_block();
if let Some(idx) = self if let Some(idx) = self
.cur_block_codeobj() .cur_block_codeobj()
@ -454,11 +454,7 @@ impl CodeGenerator {
.iter() .iter()
.position(|n| &**n == name) .position(|n| &**n == name)
{ {
if current_is_toplevel || !acc_kind.is_local() { Some(Name::local(idx))
Some(Name::local(idx))
} else {
Some(Name::global(idx))
}
} else if let Some(idx) = self } else if let Some(idx) = self
.cur_block_codeobj() .cur_block_codeobj()
.varnames .varnames
@ -667,6 +663,8 @@ impl CodeGenerator {
} }
} }
/// Ergの文法として、属性への代入は存在しない(必ずオブジェクトはすべての属性を初期化しなくてはならないため)
/// この関数はPythonへ落とし込むときに使う
fn store_acc(&mut self, acc: Accessor) { fn store_acc(&mut self, acc: Accessor) {
log!(info "entered {} ({acc})", fn_name!()); log!(info "entered {} ({acc})", fn_name!());
match acc { match acc {
@ -719,6 +717,11 @@ impl CodeGenerator {
.non_defaults .non_defaults
.iter() .iter()
.map(|p| p.inspect().map(|s| &s[..]).unwrap_or("_")) .map(|p| p.inspect().map(|s| &s[..]).unwrap_or("_"))
.chain(if let Some(var_args) = &params.var_args {
vec![var_args.inspect().map(|s| &s[..]).unwrap_or("_")]
} else {
vec![]
})
.chain( .chain(
params params
.defaults .defaults
@ -783,7 +786,7 @@ impl CodeGenerator {
self.emit_store_instr(sig.ident, Name); self.emit_store_instr(sig.ident, Name);
} }
fn emit_subr_def(&mut self, sig: SubrSignature, body: DefBody) { fn emit_subr_def(&mut self, class_name: Option<&str>, sig: SubrSignature, body: DefBody) {
log!(info "entered {} ({sig} = {})", fn_name!(), body.block); log!(info "entered {} ({sig} = {})", fn_name!(), body.block);
let name = sig.ident.inspect().clone(); let name = sig.ident.inspect().clone();
let mut opcode_flag = 0u8; let mut opcode_flag = 0u8;
@ -800,7 +803,11 @@ impl CodeGenerator {
self.write_arg(cellvars_len); self.write_arg(cellvars_len);
opcode_flag += 8; opcode_flag += 8;
} }
self.emit_load_const(name.clone()); if let Some(class) = class_name {
self.emit_load_const(Str::from(format!("{class}.{name}")));
} else {
self.emit_load_const(name);
}
self.write_instr(MAKE_FUNCTION); self.write_instr(MAKE_FUNCTION);
self.write_arg(opcode_flag); self.write_arg(opcode_flag);
// stack_dec: <code obj> + <name> -> <function> // stack_dec: <code obj> + <name> -> <function>
@ -989,12 +996,15 @@ impl CodeGenerator {
Expr::Accessor(Accessor::Local(local)) => { Expr::Accessor(Accessor::Local(local)) => {
self.emit_call_local(local, call.args).unwrap() 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!()); log!(info "entered {}", fn_name!());
match &local.inspect()[..] { match &local.inspect()[..] {
"assert" => self.emit_assert_instr(args), "assert" => self.emit_assert_instr(args),
@ -1008,33 +1018,13 @@ impl CodeGenerator {
self.emit_load_name_instr(ident).unwrap_or_else(|e| { self.emit_load_name_instr(ident).unwrap_or_else(|e| {
self.errs.push(e); self.errs.push(e);
}); });
let argc = args.len(); self.emit_args(args, Name);
let mut kws = Vec::with_capacity(args.kw_len());
while let Some(arg) = args.try_remove_pos(0) {
self.codegen_expr(arg.expr);
}
while let Some(arg) = args.try_remove_kw(0) {
kws.push(ValueObj::Str(arg.keyword.content.clone()));
self.codegen_expr(arg.expr);
}
let kwsc = if !kws.is_empty() {
let kws_tuple = ValueObj::from(kws);
self.emit_load_const(kws_tuple);
self.write_instr(CALL_FUNCTION_KW);
1
} else {
self.write_instr(CALL_FUNCTION);
0
};
self.write_arg(argc as u8);
// (1 (subroutine) + argc + kwsc) input objects -> 1 return object
self.stack_dec_n((1 + argc + kwsc) - 1);
Ok(()) Ok(())
} }
} }
} }
fn emit_call_method(&mut self, obj: Expr, method_name: Token, mut args: Args) { fn emit_call_method(&mut self, obj: Expr, method_name: Token, args: Args) {
log!(info "entered {}", fn_name!()); log!(info "entered {}", fn_name!());
if &method_name.inspect()[..] == "update!" { if &method_name.inspect()[..] == "update!" {
return self.emit_call_update(obj, args); return self.emit_call_update(obj, args);
@ -1050,11 +1040,29 @@ impl CodeGenerator {
.unwrap_or_else(|err| { .unwrap_or_else(|err| {
self.errs.push(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 argc = args.len();
let pos_len = args.pos_args.len();
let mut kws = Vec::with_capacity(args.kw_len()); let mut kws = Vec::with_capacity(args.kw_len());
while let Some(arg) = args.try_remove_pos(0) { while let Some(arg) = args.try_remove_pos(0) {
self.codegen_expr(arg.expr); self.codegen_expr(arg.expr);
} }
if let Some(var_args) = &args.var_args {
if pos_len > 0 {
self.write_instr(Opcode::BUILD_LIST);
self.write_arg(pos_len as u8);
}
self.codegen_expr(var_args.expr.clone());
if pos_len > 0 {
self.write_instr(Opcode::LIST_EXTEND);
self.write_arg(1);
self.write_instr(Opcode::LIST_TO_TUPLE);
self.write_arg(0);
}
}
while let Some(arg) = args.try_remove_kw(0) { while let Some(arg) = args.try_remove_kw(0) {
kws.push(ValueObj::Str(arg.keyword.content.clone())); kws.push(ValueObj::Str(arg.keyword.content.clone()));
self.codegen_expr(arg.expr); self.codegen_expr(arg.expr);
@ -1063,13 +1071,27 @@ impl CodeGenerator {
let kws_tuple = ValueObj::from(kws); let kws_tuple = ValueObj::from(kws);
self.emit_load_const(kws_tuple); self.emit_load_const(kws_tuple);
self.write_instr(CALL_FUNCTION_KW); self.write_instr(CALL_FUNCTION_KW);
self.write_arg(argc as u8);
1 1
} else { } else {
self.write_instr(CALL_METHOD); if args.var_args.is_some() {
self.write_instr(CALL_FUNCTION_EX);
if kws.is_empty() {
self.write_arg(0);
} else {
self.write_arg(1);
}
} else {
if kind.is_method() {
self.write_instr(CALL_METHOD);
} else {
self.write_instr(CALL_FUNCTION);
}
self.write_arg(argc as u8);
}
0 0
}; };
self.write_arg(argc as u8); // (1 (subroutine) + argc + kwsc) input objects -> 1 return object
// (1 (method) + argc + kwsc) input objects -> 1 return object
self.stack_dec_n((1 + argc + kwsc) - 1); self.stack_dec_n((1 + argc + kwsc) - 1);
} }
@ -1149,7 +1171,7 @@ impl CodeGenerator {
} }
Expr::Accessor(acc) => self.codegen_acc(acc), Expr::Accessor(acc) => self.codegen_acc(acc),
Expr::Def(def) => match def.sig { Expr::Def(def) => match def.sig {
Signature::Subr(sig) => self.emit_subr_def(sig, def.body), Signature::Subr(sig) => self.emit_subr_def(None, sig, def.body),
Signature::Var(sig) => self.emit_var_def(sig, def.body), Signature::Var(sig) => self.emit_var_def(sig, def.body),
}, },
Expr::ClassDef(class) => self.emit_class_def(class), Expr::ClassDef(class) => self.emit_class_def(class),
@ -1420,14 +1442,17 @@ impl CodeGenerator {
let mod_name = self.toplevel_block_codeobj().name.clone(); let mod_name = self.toplevel_block_codeobj().name.clone();
self.emit_load_const(mod_name); self.emit_load_const(mod_name);
self.emit_store_instr(Identifier::public("__module__"), 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_store_instr(Identifier::public("__qualname__"), Name);
self.emit_init_method(&class.sig, class.__new__.clone());
if class.need_to_gen_new { 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() { 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 // TODO: discard
if self.cur_block().stack_len == 1 { if self.cur_block().stack_len == 1 {
self.emit_pop_top(); self.emit_pop_top();
@ -1435,7 +1460,10 @@ impl CodeGenerator {
} }
for mut def in class.public_methods.into_iter() { for mut def in class.public_methods.into_iter() {
def.sig.ident_mut().dot = Some(Token::dummy()); 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 // TODO: discard
if self.cur_block().stack_len == 1 { if self.cur_block().stack_len == 1 {
self.emit_pop_top(); self.emit_pop_top();
@ -1474,9 +1502,10 @@ impl CodeGenerator {
unit.codeobj 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!()); log!(info "entered {}", fn_name!());
let line = sig.ln_begin().unwrap(); 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 ident = Identifier::public_with_line(Token::dummy(), Str::ever("__init__"), line);
let param_name = fresh_varname(); let param_name = fresh_varname();
let param = VarName::from_str_and_line(Str::from(param_name.clone()), line); 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 = VarName::from_str_and_line(Str::ever("self"), line);
let self_param = ParamSignature::new(ParamPattern::VarName(self_param), None, None); let self_param = ParamSignature::new(ParamPattern::VarName(self_param), None, None);
let params = Params::new(vec![self_param, param], None, vec![], 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![]; let mut attrs = vec![];
match __new__.non_default_params().unwrap()[0].typ() { match __new__.non_default_params().unwrap()[0].typ() {
// {x = Int; y = Int} // {x = Int; y = Int}
@ -1519,8 +1548,49 @@ impl CodeGenerator {
} }
let block = Block::new(attrs); let block = Block::new(attrs);
let body = DefBody::new(Token::dummy(), block, DefId(0)); let body = DefBody::new(Token::dummy(), block, DefId(0));
let init_def = Def::new(sig, body.clone()); self.emit_subr_def(Some(class_name), subr_sig, body);
self.codegen_expr(Expr::Def(init_def)); }
/// ```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(&param_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 { fn codegen_block(&mut self, block: Block, opt_name: Option<Str>, params: Vec<Str>) -> CodeObj {

View file

@ -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( fn get_context(
&self, &self,
obj: &hir::Expr, obj: &hir::Expr,

View file

@ -490,6 +490,20 @@ impl Context {
Self::poly_class(name, vec![], super_classes, super_traits, level) Self::poly_class(name, vec![], super_classes, super_traits, level)
} }
#[inline]
pub fn methods<S: Into<Str>>(name: S, level: usize) -> Self {
Self::with_capacity(
name.into(),
ContextKind::MethodDefs,
vec![],
None,
vec![],
vec![],
2,
level,
)
}
#[inline] #[inline]
pub fn poly_patch<S: Into<Str>>( pub fn poly_patch<S: Into<Str>>(
name: S, name: S,

View file

@ -508,6 +508,7 @@ impl Context {
Ok(()) Ok(())
} }
/// e.g. .new
fn register_auto_impl( fn register_auto_impl(
&mut self, &mut self,
name: &'static str, 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) { fn _register_gen_decl(&mut self, name: VarName, t: Type, vis: Visibility) {
if self.decls.get(&name).is_some() { if self.decls.get(&name).is_some() {
panic!("already registered: {name}"); panic!("already registered: {name}");
@ -577,11 +595,13 @@ impl Context {
if gen.t.is_monomorphic() { if gen.t.is_monomorphic() {
let super_traits = gen.impls.iter().map(|to| to.typ().clone()).collect(); 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 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 require = gen.require_or_sup.typ().clone();
let new_t = func1(require, gen.t.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); self.register_gen_mono_type(gen, ctx, Const);
} else { } else {
todo!() todo!()
@ -593,6 +613,7 @@ impl Context {
let super_traits = gen.impls.iter().map(|to| to.typ().clone()).collect(); let super_traits = gen.impls.iter().map(|to| to.typ().clone()).collect();
let mut ctx = let mut ctx =
Self::mono_class(gen.t.name(), super_classes, super_traits, self.level); 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()) { if let Some(sup) = self.rec_get_const_obj(&gen.require_or_sup.typ().name()) {
let sup = enum_unwrap!(sup, ValueObj::Type); let sup = enum_unwrap!(sup, ValueObj::Type);
let param_t = match sup { let param_t = match sup {
@ -607,9 +628,15 @@ impl Context {
param_t.clone() param_t.clone()
}; };
let new_t = func1(param_t, gen.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); self.register_gen_mono_type(gen, ctx, Const);
} else { } else {
todo!("super class not found") todo!("super class not found")

View file

@ -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( pub fn violate_decl_error(
errno: usize, errno: usize,
loc: Location, loc: Location,

View file

@ -119,6 +119,7 @@ impl KwArg {
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct Args { pub struct Args {
pub pos_args: Vec<PosArg>, pub pos_args: Vec<PosArg>,
pub var_args: Option<Box<PosArg>>,
pub kw_args: Vec<KwArg>, pub kw_args: Vec<KwArg>,
paren: Option<(Token, Token)>, paren: Option<(Token, Token)>,
} }
@ -128,6 +129,10 @@ impl NestedDisplay for Args {
if !self.pos_args.is_empty() { if !self.pos_args.is_empty() {
fmt_lines(self.pos_args.iter(), f, level)?; fmt_lines(self.pos_args.iter(), f, level)?;
} }
if let Some(var_args) = &self.var_args {
writeln!(f, "...")?;
var_args.fmt_nest(f, level)?;
}
if !self.kw_args.is_empty() { if !self.kw_args.is_empty() {
fmt_lines(self.kw_args.iter(), f, level)?; fmt_lines(self.kw_args.iter(), f, level)?;
} }
@ -139,6 +144,7 @@ impl From<Vec<Expr>> for Args {
fn from(exprs: Vec<Expr>) -> Self { fn from(exprs: Vec<Expr>) -> Self {
Self { Self {
pos_args: exprs.into_iter().map(PosArg::new).collect(), pos_args: exprs.into_iter().map(PosArg::new).collect(),
var_args: None,
kw_args: Vec::new(), kw_args: Vec::new(),
paren: None, paren: None,
} }
@ -167,30 +173,33 @@ impl Locational for Args {
// impl_stream!(Args, KwArg, kw_args); // impl_stream!(Args, KwArg, kw_args);
impl Args { impl Args {
pub const fn new( pub fn new(
pos_args: Vec<PosArg>, pos_args: Vec<PosArg>,
var_args: Option<PosArg>,
kw_args: Vec<KwArg>, kw_args: Vec<KwArg>,
paren: Option<(Token, Token)>, paren: Option<(Token, Token)>,
) -> Self { ) -> Self {
Self { Self {
pos_args, pos_args,
var_args: var_args.map(Box::new),
kw_args, kw_args,
paren, paren,
} }
} }
pub const fn empty() -> Self { pub fn empty() -> Self {
Self::new(vec![], vec![], None) Self::new(vec![], None, vec![], None)
} }
#[inline] #[inline]
pub fn len(&self) -> usize { pub fn len(&self) -> usize {
self.pos_args.len() + self.kw_args.len() let var_argc = if self.var_args.is_none() { 0 } else { 1 };
self.pos_args.len() + var_argc + self.kw_args.len()
} }
#[inline] #[inline]
pub fn is_empty(&self) -> bool { pub fn is_empty(&self) -> bool {
self.pos_args.is_empty() && self.kw_args.is_empty() self.pos_args.is_empty() && self.var_args.is_none() && self.kw_args.is_empty()
} }
#[inline] #[inline]
@ -1338,7 +1347,7 @@ pub struct ClassDef {
pub kind: TypeKind, pub kind: TypeKind,
pub sig: Signature, pub sig: Signature,
pub require_or_sup: Box<Expr>, 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 need_to_gen_new: bool,
pub __new__: Type, pub __new__: Type,
pub private_methods: RecordAttrs, pub private_methods: RecordAttrs,

View file

@ -50,12 +50,12 @@ impl Linker {
Expr::Methods(methods) => match &methods.class { Expr::Methods(methods) => match &methods.class {
TypeSpec::PreDeclTy(PreDeclTypeSpec::Simple(simple)) => { TypeSpec::PreDeclTy(PreDeclTypeSpec::Simple(simple)) => {
if let Some(pos) = self.def_root_pos_map.get(simple.name.inspect()) { if let Some(pos) = self.def_root_pos_map.get(simple.name.inspect()) {
let mut type_def = match new.remove(*pos) { let mut class_def = match new.remove(*pos) {
Expr::ClassDef(type_def) => type_def, Expr::ClassDef(class_def) => class_def,
_ => unreachable!(), _ => unreachable!(),
}; };
type_def.methods_list.push(methods); class_def.methods_list.push(methods);
new.insert(*pos, Expr::ClassDef(type_def)); new.insert(*pos, Expr::ClassDef(class_def));
} else { } else {
log!("{}", simple.name.inspect()); log!("{}", simple.name.inspect());
log!("{}", self.def_root_pos_map); log!("{}", self.def_root_pos_map);

View file

@ -330,6 +330,7 @@ impl ASTLowerer {
let (pos_args, kw_args, paren) = call.args.deconstruct(); let (pos_args, kw_args, paren) = call.args.deconstruct();
let mut hir_args = hir::Args::new( let mut hir_args = hir::Args::new(
Vec::with_capacity(pos_args.len()), Vec::with_capacity(pos_args.len()),
None,
Vec::with_capacity(kw_args.len()), Vec::with_capacity(kw_args.len()),
paren, paren,
); );
@ -368,7 +369,7 @@ impl ASTLowerer {
&[], &[],
&self.ctx.name, &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)) Ok(hir::Call::new(class, Some(method_name), args, sig_t))
} }
@ -570,10 +571,33 @@ impl ASTLowerer {
} }
} }
match self.ctx.pop() { match self.ctx.pop() {
Ok(ctx) => { Ok(methods) => {
self.check_override(&class, &ctx); self.check_override(&class, &methods);
if let Some((_, class_root)) = self.ctx.rec_get_mut_nominal_type_ctx(&class) { 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 { } else {
todo!() todo!()
} }
@ -589,8 +613,11 @@ impl ASTLowerer {
.unwrap(); .unwrap();
let type_obj = enum_unwrap!(self.ctx.rec_get_const_obj(hir_def.sig.ident().inspect()).unwrap(), ValueObj::Type:(TypeObj::Generated:(_))); 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() // 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") { let (__new__, need_to_gen_new) = if let (Some(dunder_new_vi), Some(new_vi)) = (
(vi.t.clone(), vi.kind == VarKind::Auto) ctx.get_current_scope_var("__new__"),
ctx.get_current_scope_var("new"),
) {
(dunder_new_vi.t.clone(), new_vi.kind == VarKind::Auto)
} else { } else {
todo!() todo!()
}; };

View file

@ -68,6 +68,7 @@ pub enum VarKind {
default: DefaultInfo, default: DefaultInfo,
}, },
Auto, Auto,
FixedAuto,
DoesNotExist, DoesNotExist,
Builtin, Builtin,
} }

View file

@ -2236,9 +2236,6 @@ pub enum ParamPattern {
// DataPack(ParamDataPackPattern), // DataPack(ParamDataPackPattern),
Ref(VarName), Ref(VarName),
RefMut(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 { impl NestedDisplay for ParamPattern {
@ -2252,20 +2249,17 @@ impl NestedDisplay for ParamPattern {
Self::Record(record) => write!(f, "{}", record), Self::Record(record) => write!(f, "{}", record),
Self::Ref(var_name) => write!(f, "ref {}", var_name), Self::Ref(var_name) => write!(f, "ref {}", var_name),
Self::RefMut(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_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 { impl ParamPattern {
pub const fn inspect(&self) -> Option<&Str> { pub const fn inspect(&self) -> Option<&Str> {
match self { match self {
Self::VarName(n) | Self::VarArgs(n) | Self::Ref(n) | Self::RefMut(n) => { Self::VarName(n) | Self::Ref(n) | Self::RefMut(n) => Some(n.inspect()),
Some(n.inspect())
}
_ => None, _ => None,
} }
} }
@ -2277,9 +2271,7 @@ impl ParamPattern {
pub fn is_procedural(&self) -> bool { pub fn is_procedural(&self) -> bool {
match self { match self {
Self::Discard(_) => true, Self::Discard(_) => true,
Self::VarName(n) | Self::VarArgs(n) | Self::Ref(n) | Self::RefMut(n) => { Self::VarName(n) | Self::Ref(n) | Self::RefMut(n) => n.is_procedural(),
n.is_procedural()
}
_ => false, _ => false,
} }
} }
@ -2287,7 +2279,7 @@ impl ParamPattern {
pub fn is_const(&self) -> bool { pub fn is_const(&self) -> bool {
match self { match self {
Self::Discard(_) => true, Self::Discard(_) => true,
Self::VarName(n) | Self::VarArgs(n) | Self::Ref(n) | Self::RefMut(n) => n.is_const(), Self::VarName(n) | Self::Ref(n) | Self::RefMut(n) => n.is_const(),
_ => false, _ => false,
} }
} }
@ -2381,7 +2373,11 @@ impl Locational for Params {
} else if !self.non_defaults.is_empty() { } else if !self.non_defaults.is_empty() {
Location::concat(&self.non_defaults[0], self.non_defaults.last().unwrap()) Location::concat(&self.non_defaults[0], self.non_defaults.last().unwrap())
} else if let Some(var_args) = &self.var_args { } else if let Some(var_args) = &self.var_args {
Location::concat(var_args.as_ref(), self.defaults.last().unwrap()) if !self.defaults.is_empty() {
Location::concat(var_args.as_ref(), self.defaults.last().unwrap())
} else {
var_args.loc()
}
} else if !self.defaults.is_empty() { } else if !self.defaults.is_empty() {
Location::concat(&self.defaults[0], self.defaults.last().unwrap()) Location::concat(&self.defaults[0], self.defaults.last().unwrap())
} else { } else {

View file

@ -7,9 +7,12 @@ Point3D = Inherit Point2D, Additional := {z = Int}
Point3D. Point3D.
# Overloading is prohibited by default. Remove this decorator and check for errors. # Overloading is prohibited by default. Remove this decorator and check for errors.
@Override @Override
new x, y, z = Point3D::__new__ {x; y; z} new x, y, z =
Point3D::__new__ {x; y; z}
@Override @Override
norm self = self::x**2 + self::y**2 + self::z**2 norm self = self::x**2 + self::y**2 + self::z**2
p = Point3D.new {x = 1; y = 2; z = 3} p = Point2D.new {x = 1; y = 2}
print! p.norm() print! p, p.norm()
q = Point3D.new 1, 2, 3
print! q, q.norm()