Impl trait code generating

This commit is contained in:
Shunsuke Shibayama 2022-09-19 00:34:39 +09:00
parent bd17bf3299
commit 67e4607c70
4 changed files with 232 additions and 54 deletions

View file

@ -3,7 +3,6 @@
//! ASTからPythonバイトコード(コードオブジェクト)を生成する
use std::fmt;
use std::process;
use std::rc::Rc;
use erg_common::astr::AtomicStr;
use erg_common::cache::CacheSet;
@ -583,7 +582,7 @@ impl CodeGenerator {
Ok(())
}
fn emit_import_name_instr(&mut self, ident: Identifier) -> CompileResult<()> {
fn emit_import_name_instr(&mut self, ident: Identifier, items_len: usize) -> CompileResult<()> {
log!(info "entered {}", fn_name!());
let escaped = escape_name(ident);
let name = self
@ -592,6 +591,7 @@ impl CodeGenerator {
self.write_instr(IMPORT_NAME);
self.write_arg(name.idx as u8);
self.stack_dec(); // (level + from_list) -> module object
self.stack_inc_n(items_len - 1);
Ok(())
}
@ -614,11 +614,13 @@ impl CodeGenerator {
items: Vec<(Identifier, Option<Identifier>)>,
) {
self.emit_load_const(0);
let items_names = items
let item_names = items
.iter()
.map(|ident| ValueObj::Str(ident.0.inspect().clone()));
self.emit_load_const(ValueObj::Tuple(Rc::from(items_names.collect::<Vec<_>>())));
self.emit_import_name_instr(module).unwrap();
.map(|ident| ValueObj::Str(ident.0.inspect().clone()))
.collect::<Vec<_>>();
let items_len = item_names.len();
self.emit_load_const(item_names);
self.emit_import_name_instr(module, items_len).unwrap();
for (item, renamed) in items.into_iter() {
if let Some(renamed) = renamed {
self.emit_import_from_instr(item).unwrap();
@ -717,7 +719,7 @@ impl CodeGenerator {
self.emit_store_instr(ident, Name);
}
Accessor::Attr(attr) => {
self.codegen_expr(*attr.obj);
self.emit_expr(*attr.obj);
self.emit_store_instr(attr.ident, Attr);
}
acc => todo!("store: {acc}"),
@ -790,7 +792,7 @@ impl CodeGenerator {
// class C:
// a = x
if Some(&self.cur_block_codeobj().name[..]) != a.obj.__name__() {
self.codegen_expr(*a.obj);
self.emit_expr(*a.obj);
self.emit_load_attr_instr(
&class,
uniq_obj_name.as_ref().map(|s| &s[..]),
@ -806,15 +808,15 @@ impl CodeGenerator {
}
}
Accessor::TupleAttr(t_attr) => {
self.codegen_expr(*t_attr.obj);
self.emit_expr(*t_attr.obj);
self.emit_load_const(t_attr.index.value);
self.write_instr(BINARY_SUBSCR);
self.write_arg(0);
self.stack_dec();
}
Accessor::Subscr(subscr) => {
self.codegen_expr(*subscr.obj);
self.codegen_expr(*subscr.index);
self.emit_expr(*subscr.obj);
self.emit_expr(*subscr.index);
self.write_instr(BINARY_SUBSCR);
self.write_arg(0);
self.stack_dec();
@ -834,7 +836,155 @@ impl CodeGenerator {
}
fn emit_trait_def(&mut self, def: Def) {
todo!()
self.write_instr(Opcode::LOAD_BUILD_CLASS);
self.write_arg(0);
self.stack_inc();
let code = self.emit_trait_block(def.def_kind(), &def.sig, def.body.block);
self.emit_load_const(code);
self.emit_load_const(def.sig.ident().inspect().clone());
self.write_instr(Opcode::MAKE_FUNCTION);
self.write_arg(0);
self.emit_load_const(def.sig.ident().inspect().clone());
self.emit_load_name_instr(Identifier::private(Str::ever("#ABCMeta")))
.unwrap();
self.emit_load_const(vec![ValueObj::from("metaclass")]);
let subclasses_len = 1;
self.write_instr(Opcode::CALL_FUNCTION_KW);
self.write_arg(2 + subclasses_len as u8);
self.stack_dec_n((1 + 2 + subclasses_len) - 1);
self.emit_store_instr(def.sig.into_ident(), Name);
self.stack_dec();
}
// trait variables will be removed
// T = Trait {
// x = Int
// f = (self: Self) -> Int
// }
// ↓
// class T(metaclass=ABCMeta):
// def f(): pass
fn emit_trait_block(&mut self, kind: DefKind, sig: &Signature, mut block: Block) -> CodeObj {
let name = sig.ident().inspect().clone();
let mut trait_call = enum_unwrap!(block.remove(0), Expr::Call);
let req = if kind == DefKind::Trait {
enum_unwrap!(
trait_call.args.remove_left_or_key("Requirement").unwrap(),
Expr::Record
)
} else {
todo!()
};
self.unit_size += 1;
let firstlineno = block
.get(0)
.and_then(|def| def.ln_begin())
.unwrap_or_else(|| sig.ln_begin().unwrap());
self.units.push(CodeGenUnit::new(
self.unit_size,
vec![],
Str::rc(self.cfg.input.enclosed_name()),
&name,
firstlineno,
));
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_store_instr(Identifier::public("__qualname__"), Name);
for def in req.attrs.into_iter() {
self.emit_empty_func(
Some(sig.ident().inspect()),
def.sig.into_ident(),
Some(Identifier::private(Str::ever("#abstractmethod"))),
);
}
self.emit_load_const(ValueObj::None);
self.write_instr(RETURN_VALUE);
self.write_arg(0u8);
if self.cur_block().stack_len > 1 {
let block_id = self.cur_block().id;
let stack_len = self.cur_block().stack_len;
self.errs.push(CompileError::stack_bug(
self.input().clone(),
Location::Unknown,
stack_len,
block_id,
fn_name_full!(),
));
self.crash("error in emit_trait_block: invalid stack size");
}
// flagging
if !self.cur_block_codeobj().varnames.is_empty() {
self.mut_cur_block_codeobj().flags += CodeObjFlags::NewLocals as u32;
}
// end of flagging
let unit = self.units.pop().unwrap();
if !self.units.is_empty() {
let ld = unit.prev_lineno - self.cur_block().prev_lineno;
if ld != 0 {
if let Some(l) = self.mut_cur_block_codeobj().lnotab.last_mut() {
*l += ld as u8;
}
self.mut_cur_block().prev_lineno += ld;
}
}
unit.codeobj
}
fn emit_empty_func(
&mut self,
class_name: Option<&str>,
ident: Identifier,
deco: Option<Identifier>,
) {
log!(info "entered {} ({ident})", fn_name!());
let deco_is_some = deco.is_some();
if let Some(deco) = deco {
self.emit_load_name_instr(deco).unwrap();
}
let code = {
self.unit_size += 1;
self.units.push(CodeGenUnit::new(
self.unit_size,
vec![],
Str::rc(self.cfg.input.enclosed_name()),
ident.inspect(),
ident.ln_begin().unwrap(),
));
self.emit_load_const(ValueObj::None);
self.write_instr(RETURN_VALUE);
self.write_arg(0u8);
let unit = self.units.pop().unwrap();
if !self.units.is_empty() {
let ld = unit
.prev_lineno
.saturating_sub(self.cur_block().prev_lineno);
if ld != 0 {
if let Some(l) = self.mut_cur_block_codeobj().lnotab.last_mut() {
*l += ld as u8;
}
self.mut_cur_block().prev_lineno += ld;
}
}
unit.codeobj
};
self.emit_load_const(code);
if let Some(class) = class_name {
self.emit_load_const(Str::from(format!("{class}.{}", ident.name.inspect())));
} else {
self.emit_load_const(ident.name.inspect().clone());
}
self.write_instr(MAKE_FUNCTION);
self.write_arg(0);
if deco_is_some {
self.write_instr(CALL_FUNCTION);
self.write_arg(1);
self.stack_dec();
}
// stack_dec: (<abstractmethod>) + <code obj> + <name> -> <function>
self.stack_dec();
self.emit_store_instr(ident, Name);
}
fn emit_class_def(&mut self, class_def: ClassDef) {
@ -845,7 +995,7 @@ impl CodeGenerator {
self.write_instr(Opcode::LOAD_BUILD_CLASS);
self.write_arg(0);
self.stack_inc();
let code = self.codegen_typedef_block(class_def);
let code = self.emit_typedef_block(class_def);
self.emit_load_const(code);
self.emit_load_const(ident.inspect().clone());
self.write_instr(Opcode::MAKE_FUNCTION);
@ -868,7 +1018,7 @@ impl CodeGenerator {
match kind {
TypeKind::Class => 0,
TypeKind::Subclass => {
self.codegen_expr(require_or_sup);
self.emit_expr(require_or_sup);
1 // TODO: not always 1
}
_ => todo!(),
@ -877,16 +1027,16 @@ impl CodeGenerator {
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.emit_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));
self.emit_expr(body.block.remove(0));
} else {
self.codegen_frameless_block(body.block, vec![]);
self.emit_frameless_block(body.block, vec![]);
}
self.emit_store_instr(sig.ident, Name);
}
@ -896,7 +1046,7 @@ impl CodeGenerator {
let name = sig.ident.inspect().clone();
let mut opcode_flag = 0u8;
let params = self.gen_param_names(&sig.params);
let code = self.codegen_block(body.block, Some(name.clone()), params);
let code = self.emit_block(body.block, Some(name.clone()), params);
self.emit_load_const(code);
if !self.cur_block_codeobj().cellvars.is_empty() {
let cellvars_len = self.cur_block_codeobj().cellvars.len() as u8;
@ -923,7 +1073,7 @@ impl CodeGenerator {
fn emit_lambda(&mut self, lambda: Lambda) {
log!(info "entered {} ({lambda})", fn_name!());
let params = self.gen_param_names(&lambda.params);
let code = self.codegen_block(lambda.body, Some("<lambda>".into()), params);
let code = self.emit_block(lambda.body, Some("<lambda>".into()), params);
self.emit_load_const(code);
self.emit_load_const("<lambda>");
self.write_instr(MAKE_FUNCTION);
@ -935,7 +1085,7 @@ impl CodeGenerator {
fn emit_unaryop(&mut self, unary: UnaryOp) {
log!(info "entered {} ({unary})", fn_name!());
let tycode = TypeCode::from(unary.lhs_t());
self.codegen_expr(*unary.expr);
self.emit_expr(*unary.expr);
let instr = match &unary.op.kind {
// TODO:
TokenKind::PrePlus => UNARY_POSITIVE,
@ -969,8 +1119,8 @@ impl CodeGenerator {
_ => {}
}
let type_pair = TypePair::new(bin.lhs_t(), bin.rhs_t());
self.codegen_expr(*bin.lhs);
self.codegen_expr(*bin.rhs);
self.emit_expr(*bin.lhs);
self.emit_expr(*bin.rhs);
let instr = match &bin.op.kind {
TokenKind::Plus => BINARY_ADD,
TokenKind::Minus => BINARY_SUBTRACT,
@ -1023,7 +1173,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_expr(arg);
self.emit_pop_top();
}
Ok(())
@ -1032,7 +1182,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);
self.emit_expr(cond);
let idx_pop_jump_if_false = self.cur_block().lasti;
self.write_instr(POP_JUMP_IF_FALSE);
// cannot detect where to jump to at this moment, so put as 0
@ -1041,10 +1191,10 @@ impl CodeGenerator {
// then block
Expr::Lambda(lambda) => {
let params = self.gen_param_names(&lambda.params);
self.codegen_frameless_block(lambda.body, params);
self.emit_frameless_block(lambda.body, params);
}
other => {
self.codegen_expr(other);
self.emit_expr(other);
}
}
if args.get(0).is_some() {
@ -1056,10 +1206,10 @@ impl CodeGenerator {
match args.remove(0) {
Expr::Lambda(lambda) => {
let params = self.gen_param_names(&lambda.params);
self.codegen_frameless_block(lambda.body, params);
self.emit_frameless_block(lambda.body, params);
}
other => {
self.codegen_expr(other);
self.emit_expr(other);
}
}
let idx_jump_forward = idx_else_begin - 2;
@ -1081,7 +1231,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.emit_expr(iterable);
self.write_instr(GET_ITER);
self.write_arg(0);
let idx_for_iter = self.cur_block().lasti;
@ -1092,7 +1242,7 @@ impl CodeGenerator {
self.write_arg(0);
let lambda = enum_unwrap!(args.remove(0), Expr::Lambda);
let params = self.gen_param_names(&lambda.params);
self.codegen_frameless_block(lambda.body, params); // ここでPOPされる
self.emit_frameless_block(lambda.body, params); // ここでPOPされる
self.write_instr(JUMP_ABSOLUTE);
self.write_arg((idx_for_iter / 2) as u8);
let idx_end = self.cur_block().lasti;
@ -1104,7 +1254,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);
self.emit_expr(expr);
let len = args.len();
let mut absolute_jump_points = vec![];
while let Some(expr) = args.try_remove(0) {
@ -1122,7 +1272,7 @@ impl CodeGenerator {
}
let pat = lambda.params.non_defaults.remove(0).pat;
let pop_jump_points = self.emit_match_pattern(pat)?;
self.codegen_frameless_block(lambda.body, Vec::new());
self.emit_frameless_block(lambda.body, Vec::new());
for pop_jump_point in pop_jump_points.into_iter() {
let idx = self.cur_block().lasti + 2;
self.edit_code(pop_jump_point + 1, idx / 2); // jump to POP_TOP
@ -1202,7 +1352,7 @@ impl CodeGenerator {
self.emit_call_local(ident, call.args).unwrap()
}
other => {
self.codegen_expr(other);
self.emit_expr(other);
self.emit_args(call.args, Name);
}
}
@ -1237,7 +1387,7 @@ impl CodeGenerator {
} else if is_fake_method(&class, method_name.inspect()) {
return self.emit_call_fake_method(obj, method_name, args);
}
self.codegen_expr(obj);
self.emit_expr(obj);
self.emit_load_method_instr(&class, uniq_obj_name.as_ref().map(|s| &s[..]), method_name)
.unwrap_or_else(|err| {
self.errs.push(err);
@ -1250,14 +1400,14 @@ impl CodeGenerator {
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);
self.emit_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());
self.emit_expr(var_args.expr.clone());
if pos_len > 0 {
self.write_instr(Opcode::LIST_EXTEND);
self.write_arg(1);
@ -1267,7 +1417,7 @@ impl CodeGenerator {
}
while let Some(arg) = args.try_remove_kw(0) {
kws.push(ValueObj::Str(arg.keyword.content.clone()));
self.codegen_expr(arg.expr);
self.emit_expr(arg.expr);
}
let kwsc = if !kws.is_empty() {
let kws_tuple = ValueObj::from(kws);
@ -1304,7 +1454,7 @@ impl CodeGenerator {
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.emit_expr(func);
self.emit_acc(acc.clone());
self.write_instr(CALL_FUNCTION);
self.write_arg(1);
@ -1325,7 +1475,7 @@ impl CodeGenerator {
// 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));
self.emit_expr(args.remove(0));
let pop_jump_point = self.cur_block().lasti;
self.write_instr(Opcode::POP_JUMP_IF_TRUE);
self.write_arg(0);
@ -1333,7 +1483,7 @@ impl CodeGenerator {
self.write_instr(Opcode::LOAD_ASSERTION_ERROR);
self.write_arg(0);
if let Some(expr) = args.try_remove(0) {
self.codegen_expr(expr);
self.emit_expr(expr);
self.write_instr(Opcode::CALL_FUNCTION);
self.write_arg(1);
}
@ -1373,7 +1523,7 @@ impl CodeGenerator {
let ident = Identifier::private(Str::ever("#rec"));
self.emit_load_name_instr(ident).unwrap();
for field in rec.attrs.into_iter() {
self.codegen_frameless_block(field.body.block, vec![]);
self.emit_frameless_block(field.body.block, vec![]);
}
self.write_instr(CALL_FUNCTION);
self.write_arg(attrs_len as u8);
@ -1381,7 +1531,7 @@ impl CodeGenerator {
self.stack_dec_n((1 + attrs_len + 0) - 1);
}
fn codegen_expr(&mut self, expr: Expr) {
fn emit_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;
@ -1428,7 +1578,7 @@ impl CodeGenerator {
Array::Normal(mut arr) => {
let len = arr.elems.len();
while let Some(arg) = arr.elems.try_remove_pos(0) {
self.codegen_expr(arg.expr);
self.emit_expr(arg.expr);
}
self.write_instr(BUILD_LIST);
self.write_arg(len as u8);
@ -1446,7 +1596,7 @@ impl CodeGenerator {
Tuple::Normal(mut tup) => {
let len = tup.elems.len();
while let Some(arg) = tup.elems.try_remove_pos(0) {
self.codegen_expr(arg.expr);
self.emit_expr(arg.expr);
}
self.write_instr(BUILD_TUPLE);
self.write_arg(len as u8);
@ -1471,13 +1621,13 @@ impl CodeGenerator {
}
/// forブロックなどで使う
fn codegen_frameless_block(&mut self, block: Block, params: Vec<Str>) {
fn emit_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);
}
for expr in block.into_iter() {
self.codegen_expr(expr);
self.emit_expr(expr);
// TODO: discard
// 最終的に帳尻を合わせる(コード生成の順番的にスタックの整合性が一時的に崩れる場合がある)
if self.cur_block().stack_len == 1 {
@ -1487,7 +1637,7 @@ impl CodeGenerator {
self.cancel_pop_top();
}
fn codegen_typedef_block(&mut self, class: ClassDef) -> CodeObj {
fn emit_typedef_block(&mut self, class: ClassDef) -> CodeObj {
log!(info "entered {}", fn_name!());
let name = class.sig.ident().inspect().clone();
self.unit_size += 1;
@ -1659,7 +1809,7 @@ impl CodeGenerator {
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 emit_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 {
@ -1667,7 +1817,10 @@ impl CodeGenerator {
} else {
"<block>".into()
};
let firstlineno = block.first().unwrap().ln_begin().unwrap();
let firstlineno = block
.first()
.and_then(|first| first.ln_begin())
.unwrap_or(0);
self.units.push(CodeGenUnit::new(
self.unit_size,
params,
@ -1676,7 +1829,7 @@ impl CodeGenerator {
firstlineno,
));
for expr in block.into_iter() {
self.codegen_expr(expr);
self.emit_expr(expr);
// NOTE: 各行のトップレベルでは0個または1個のオブジェクトが残っている
// Pythonの場合使わなかったオブジェクトはそのまま捨てられるが、Ergではdiscardを使う必要がある
// TODO: discard
@ -1723,6 +1876,7 @@ impl CodeGenerator {
fn load_prelude(&mut self) {
self.init_record();
self.load_abc();
}
fn init_record(&mut self) {
@ -1737,7 +1891,23 @@ impl CodeGenerator {
// self.namedtuple_loaded = true;
}
pub fn codegen(&mut self, hir: HIR) -> CodeObj {
fn load_abc(&mut self) {
self.emit_import_items(
Identifier::public("abc"),
vec![
(
Identifier::public("ABCMeta"),
Some(Identifier::private(Str::ever("#ABCMeta"))),
),
(
Identifier::public("abstractmethod"),
Some(Identifier::private(Str::ever("#abstractmethod"))),
),
],
);
}
pub fn emit(&mut self, hir: HIR) -> CodeObj {
log!(info "the code-generating process has started.{RESET}");
self.unit_size += 1;
self.units.push(CodeGenUnit::new(
@ -1761,7 +1931,7 @@ impl CodeGenerator {
self.stack_dec();
}
for expr in hir.module.into_iter() {
self.codegen_expr(expr);
self.emit_expr(expr);
// TODO: discard
if self.cur_block().stack_len == 1 {
self.emit_pop_top();