diff --git a/compiler/erg_compiler/codegen.rs b/compiler/erg_compiler/codegen.rs index e804c28b..a7666160 100644 --- a/compiler/erg_compiler/codegen.rs +++ b/compiler/erg_compiler/codegen.rs @@ -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)>, ) { 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::>()))); - self.emit_import_name_instr(module).unwrap(); + .map(|ident| ValueObj::Str(ident.0.inspect().clone())) + .collect::>(); + 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, + ) { + 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: () + + -> + 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("".into()), params); + let code = self.emit_block(lambda.body, Some("".into()), params); self.emit_load_const(code); self.emit_load_const(""); 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) { + fn emit_frameless_block(&mut self, block: Block, params: Vec) { 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, params: Vec) -> CodeObj { + fn emit_block(&mut self, block: Block, opt_name: Option, params: Vec) -> 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 { "".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(); diff --git a/compiler/erg_compiler/compile.rs b/compiler/erg_compiler/compile.rs index b92a04e5..6b33cb95 100644 --- a/compiler/erg_compiler/compile.rs +++ b/compiler/erg_compiler/compile.rs @@ -183,7 +183,7 @@ impl Compiler { .ownership_checker .check(hir) .map_err(|errs| self.convert(errs))?; - let codeobj = self.code_generator.codegen(hir); + let codeobj = self.code_generator.emit(hir); log!(info "code object:\n{}", codeobj.code_info()); log!( info "the compiling process has completed, found errors: {}", diff --git a/compiler/erg_compiler/hir.rs b/compiler/erg_compiler/hir.rs index fbcfcc23..244eb059 100644 --- a/compiler/erg_compiler/hir.rs +++ b/compiler/erg_compiler/hir.rs @@ -1185,7 +1185,7 @@ impl Signature { } } - pub fn ident(&self) -> &Identifier { + pub const fn ident(&self) -> &Identifier { match self { Self::Var(v) => &v.ident, Self::Subr(s) => &s.ident, @@ -1198,6 +1198,13 @@ impl Signature { Self::Subr(s) => &mut s.ident, } } + + pub fn into_ident(self) -> Identifier { + match self { + Self::Var(v) => v.ident, + Self::Subr(s) => s.ident, + } + } } /// represents a declaration of a variable diff --git a/examples/trait.er b/examples/trait.er index 570d27ed..bfb30c22 100644 --- a/examples/trait.er +++ b/examples/trait.er @@ -11,6 +11,7 @@ Point3D|Point2D <: Norm|. norm|T <: Norm| x: T = x.norm() p = Point2D.new {x = 3; y = 4} +print! norm(p) assert norm(p) == 25 assert norm(Point3D.new {x = 3; y = 4; z = 5}) == 50 # assert norm(1) # this should be an error