mirror of
https://github.com/erg-lang/erg.git
synced 2025-09-29 12:24:45 +00:00
Fix codegen bug
This commit is contained in:
parent
1d38b895e8
commit
edab3a8ad2
1 changed files with 78 additions and 62 deletions
|
@ -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, Local, Signature,
|
Accessor, Args, Array, Block, Call, ClassDef, Def, DefBody, Expr, Literal, Local, 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"),
|
||||||
("Type", _, "new" | "__new__") => Str::ever("__call__"),
|
(_, _, "new" | "__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"),
|
||||||
|
@ -319,7 +319,7 @@ impl_stream_for_wrapper!(CodeGenStack, CodeGenUnit);
|
||||||
pub struct CodeGenerator {
|
pub struct CodeGenerator {
|
||||||
cfg: ErgConfig,
|
cfg: ErgConfig,
|
||||||
str_cache: CacheSet<str>,
|
str_cache: CacheSet<str>,
|
||||||
namedtuple_loaded: bool,
|
prelude_loaded: bool,
|
||||||
unit_size: usize,
|
unit_size: usize,
|
||||||
units: CodeGenStack,
|
units: CodeGenStack,
|
||||||
pub(crate) errs: CompileErrors,
|
pub(crate) errs: CompileErrors,
|
||||||
|
@ -330,7 +330,7 @@ impl CodeGenerator {
|
||||||
Self {
|
Self {
|
||||||
cfg,
|
cfg,
|
||||||
str_cache: CacheSet::new(),
|
str_cache: CacheSet::new(),
|
||||||
namedtuple_loaded: false,
|
prelude_loaded: false,
|
||||||
unit_size: 0,
|
unit_size: 0,
|
||||||
units: CodeGenStack::empty(),
|
units: CodeGenStack::empty(),
|
||||||
errs: CompileErrors::empty(),
|
errs: CompileErrors::empty(),
|
||||||
|
@ -596,7 +596,7 @@ impl CodeGenerator {
|
||||||
uniq_obj_name: Option<&str>,
|
uniq_obj_name: Option<&str>,
|
||||||
name: Str,
|
name: Str,
|
||||||
) -> CompileResult<()> {
|
) -> CompileResult<()> {
|
||||||
log!(info "entered {}", fn_name!());
|
log!(info "entered {} ({class}.{name})", fn_name!());
|
||||||
let name = self
|
let name = self
|
||||||
.local_search(&name, Attr)
|
.local_search(&name, Attr)
|
||||||
.unwrap_or_else(|| self.register_attr(class, uniq_obj_name, name));
|
.unwrap_or_else(|| self.register_attr(class, uniq_obj_name, name));
|
||||||
|
@ -617,7 +617,7 @@ impl CodeGenerator {
|
||||||
uniq_obj_name: Option<&str>,
|
uniq_obj_name: Option<&str>,
|
||||||
name: Str,
|
name: Str,
|
||||||
) -> CompileResult<()> {
|
) -> CompileResult<()> {
|
||||||
log!(info "entered {}", fn_name!());
|
log!(info "entered {} ({class}.{name})", fn_name!());
|
||||||
let name = self
|
let name = self
|
||||||
.local_search(&name, Method)
|
.local_search(&name, Method)
|
||||||
.unwrap_or_else(|| self.register_method(class, uniq_obj_name, name));
|
.unwrap_or_else(|| self.register_method(class, uniq_obj_name, name));
|
||||||
|
@ -633,14 +633,22 @@ impl CodeGenerator {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn emit_store_instr(&mut self, ident: Identifier, acc_kind: AccessKind) {
|
fn emit_store_instr(&mut self, ident: Identifier, acc_kind: AccessKind) {
|
||||||
log!(info "entered {}", fn_name!());
|
log!(info "entered {} ({ident})", fn_name!());
|
||||||
let name = self
|
let name = self
|
||||||
.local_search(ident.inspect(), acc_kind)
|
.local_search(ident.inspect(), acc_kind)
|
||||||
.unwrap_or_else(|| self.register_name(ident));
|
.unwrap_or_else(|| {
|
||||||
|
if acc_kind.is_local() {
|
||||||
|
self.register_name(ident)
|
||||||
|
} else {
|
||||||
|
self.register_attr("", None, ident.inspect().clone())
|
||||||
|
}
|
||||||
|
});
|
||||||
let instr = match name.kind {
|
let instr = match name.kind {
|
||||||
StoreLoadKind::Fast => Opcode::STORE_FAST,
|
StoreLoadKind::Fast => Opcode::STORE_FAST,
|
||||||
StoreLoadKind::FastConst => Opcode::ERG_STORE_FAST_IMMUT,
|
StoreLoadKind::FastConst => Opcode::ERG_STORE_FAST_IMMUT,
|
||||||
StoreLoadKind::Global | StoreLoadKind::GlobalConst => Opcode::STORE_GLOBAL,
|
// NOTE: First-time variables are treated as GLOBAL, but they are always first-time variables when assigned, so they are just NAME
|
||||||
|
// NOTE: 初見の変数はGLOBAL扱いになるが、代入時は必ず初見であるので単なるNAME
|
||||||
|
StoreLoadKind::Global | StoreLoadKind::GlobalConst => Opcode::STORE_NAME,
|
||||||
StoreLoadKind::Deref | StoreLoadKind::DerefConst => Opcode::STORE_DEREF,
|
StoreLoadKind::Deref | StoreLoadKind::DerefConst => Opcode::STORE_DEREF,
|
||||||
StoreLoadKind::Local | StoreLoadKind::LocalConst => {
|
StoreLoadKind::Local | StoreLoadKind::LocalConst => {
|
||||||
match acc_kind {
|
match acc_kind {
|
||||||
|
@ -654,10 +662,13 @@ impl CodeGenerator {
|
||||||
self.write_instr(instr);
|
self.write_instr(instr);
|
||||||
self.write_arg(name.idx as u8);
|
self.write_arg(name.idx as u8);
|
||||||
self.stack_dec();
|
self.stack_dec();
|
||||||
|
if instr == Opcode::STORE_ATTR {
|
||||||
|
self.stack_dec();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn store_acc(&mut self, acc: Accessor) {
|
fn store_acc(&mut self, acc: Accessor) {
|
||||||
log!(info "entered {}", fn_name!());
|
log!(info "entered {} ({acc})", fn_name!());
|
||||||
match acc {
|
match acc {
|
||||||
Accessor::Local(local) => {
|
Accessor::Local(local) => {
|
||||||
self.emit_store_instr(Identifier::new(None, VarName::new(local.name)), Name);
|
self.emit_store_instr(Identifier::new(None, VarName::new(local.name)), Name);
|
||||||
|
@ -719,7 +730,7 @@ impl CodeGenerator {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn emit_class_def(&mut self, class_def: ClassDef) {
|
fn emit_class_def(&mut self, class_def: ClassDef) {
|
||||||
log!(info "entered {}", fn_name!());
|
log!(info "entered {} ({class_def})", fn_name!());
|
||||||
let ident = class_def.sig.ident().clone();
|
let ident = class_def.sig.ident().clone();
|
||||||
let kind = class_def.kind;
|
let kind = class_def.kind;
|
||||||
let require_or_sup = class_def.require_or_sup.clone();
|
let require_or_sup = class_def.require_or_sup.clone();
|
||||||
|
@ -732,19 +743,20 @@ impl CodeGenerator {
|
||||||
self.write_instr(Opcode::MAKE_FUNCTION);
|
self.write_instr(Opcode::MAKE_FUNCTION);
|
||||||
self.write_arg(0);
|
self.write_arg(0);
|
||||||
self.emit_load_const(ident.inspect().clone());
|
self.emit_load_const(ident.inspect().clone());
|
||||||
let subclasses_len = self.emit_require_type(kind, *require_or_sup);
|
|
||||||
// LOAD subclasses
|
// LOAD subclasses
|
||||||
|
let subclasses_len = self.emit_require_type(kind, *require_or_sup);
|
||||||
self.write_instr(Opcode::CALL_FUNCTION);
|
self.write_instr(Opcode::CALL_FUNCTION);
|
||||||
self.write_arg(2 + subclasses_len as u8);
|
self.write_arg(2 + subclasses_len as u8);
|
||||||
self.stack_dec_n((1 + 2 + subclasses_len) - 1);
|
self.stack_dec_n((1 + 2 + subclasses_len) - 1);
|
||||||
self.emit_store_instr(ident, Name);
|
self.emit_store_instr(ident, Name);
|
||||||
|
self.stack_dec();
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTE: use `TypeVar`, `Generic` in `typing` module
|
// NOTE: use `TypeVar`, `Generic` in `typing` module
|
||||||
// fn emit_poly_type_def(&mut self, sig: SubrSignature, body: DefBody) {}
|
// fn emit_poly_type_def(&mut self, sig: SubrSignature, body: DefBody) {}
|
||||||
|
|
||||||
fn emit_require_type(&mut self, kind: TypeKind, require_or_sup: Expr) -> usize {
|
fn emit_require_type(&mut self, kind: TypeKind, require_or_sup: Expr) -> usize {
|
||||||
log!(info "entered {}", fn_name!());
|
log!(info "entered {} ({kind:?}, {require_or_sup})", fn_name!());
|
||||||
match kind {
|
match kind {
|
||||||
TypeKind::Class => 0,
|
TypeKind::Class => 0,
|
||||||
TypeKind::Subclass => {
|
TypeKind::Subclass => {
|
||||||
|
@ -756,13 +768,13 @@ impl CodeGenerator {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn emit_attr_def(&mut self, attr_def: AttrDef) {
|
fn emit_attr_def(&mut self, attr_def: AttrDef) {
|
||||||
log!(info "entered {}", fn_name!());
|
log!(info "entered {} ({attr_def})", fn_name!());
|
||||||
self.codegen_frameless_block(attr_def.block, vec![]);
|
self.codegen_frameless_block(attr_def.block, vec![]);
|
||||||
self.store_acc(attr_def.attr);
|
self.store_acc(attr_def.attr);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn emit_var_def(&mut self, sig: VarSignature, mut body: DefBody) {
|
fn emit_var_def(&mut self, sig: VarSignature, mut body: DefBody) {
|
||||||
log!(info "entered {}", fn_name!());
|
log!(info "entered {} ({sig} = {})", fn_name!(), body.block);
|
||||||
if body.block.len() == 1 {
|
if body.block.len() == 1 {
|
||||||
self.codegen_expr(body.block.remove(0));
|
self.codegen_expr(body.block.remove(0));
|
||||||
} else {
|
} else {
|
||||||
|
@ -772,7 +784,7 @@ impl CodeGenerator {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn emit_subr_def(&mut self, sig: SubrSignature, body: DefBody) {
|
fn emit_subr_def(&mut self, sig: SubrSignature, body: DefBody) {
|
||||||
log!(info "entered {}", fn_name!());
|
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;
|
||||||
let params = self.gen_param_names(&sig.params);
|
let params = self.gen_param_names(&sig.params);
|
||||||
|
@ -969,7 +981,7 @@ impl CodeGenerator {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn emit_call(&mut self, call: Call) {
|
fn emit_call(&mut self, call: Call) {
|
||||||
log!(info "entered {}", fn_name!());
|
log!(info "entered {} ({call})", fn_name!());
|
||||||
if let Some(method_name) = call.method_name {
|
if let Some(method_name) = call.method_name {
|
||||||
self.emit_call_method(*call.obj, method_name, call.args);
|
self.emit_call_method(*call.obj, method_name, call.args);
|
||||||
} else {
|
} else {
|
||||||
|
@ -1100,7 +1112,7 @@ impl CodeGenerator {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn codegen_expr(&mut self, expr: Expr) {
|
fn codegen_expr(&mut self, expr: Expr) {
|
||||||
log!(info "entered {}", fn_name!());
|
log!(info "entered {} ({expr})", fn_name!());
|
||||||
if expr.ln_begin().unwrap_or_else(|| panic!("{expr}")) > self.cur_block().prev_lineno {
|
if expr.ln_begin().unwrap_or_else(|| panic!("{expr}")) > self.cur_block().prev_lineno {
|
||||||
let sd = self.cur_block().lasti - self.cur_block().prev_lasti;
|
let sd = self.cur_block().lasti - self.cur_block().prev_lasti;
|
||||||
let ld = expr.ln_begin().unwrap() - self.cur_block().prev_lineno;
|
let ld = expr.ln_begin().unwrap() - self.cur_block().prev_lineno;
|
||||||
|
@ -1280,20 +1292,6 @@ impl CodeGenerator {
|
||||||
},
|
},
|
||||||
Expr::Record(rec) => {
|
Expr::Record(rec) => {
|
||||||
let attrs_len = rec.attrs.len();
|
let attrs_len = rec.attrs.len();
|
||||||
// importing namedtuple
|
|
||||||
if !self.namedtuple_loaded {
|
|
||||||
self.emit_load_const(0);
|
|
||||||
self.emit_load_const(ValueObj::Tuple(std::rc::Rc::from([ValueObj::Str(
|
|
||||||
Str::ever("namedtuple"),
|
|
||||||
)])));
|
|
||||||
let ident = Identifier::public("collections");
|
|
||||||
self.emit_import_name_instr(ident).unwrap();
|
|
||||||
let ident = Identifier::public("namedtuple");
|
|
||||||
self.emit_import_from_instr(ident).unwrap();
|
|
||||||
let ident = Identifier::private(Str::ever("#NamedTuple"));
|
|
||||||
self.emit_store_instr(ident, Name);
|
|
||||||
self.namedtuple_loaded = true;
|
|
||||||
}
|
|
||||||
// making record type
|
// making record type
|
||||||
let ident = Identifier::private(Str::ever("#NamedTuple"));
|
let ident = Identifier::private(Str::ever("#NamedTuple"));
|
||||||
self.emit_load_name_instr(ident).unwrap();
|
self.emit_load_name_instr(ident).unwrap();
|
||||||
|
@ -1339,7 +1337,7 @@ impl CodeGenerator {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn codegen_acc(&mut self, acc: Accessor) {
|
fn codegen_acc(&mut self, acc: Accessor) {
|
||||||
log!(info "entered {}", fn_name!());
|
log!(info "entered {} ({acc})", fn_name!());
|
||||||
match acc {
|
match acc {
|
||||||
Accessor::Local(local) => {
|
Accessor::Local(local) => {
|
||||||
self.emit_load_name_instr(Identifier::new(None, VarName::new(local.name)))
|
self.emit_load_name_instr(Identifier::new(None, VarName::new(local.name)))
|
||||||
|
@ -1421,9 +1419,9 @@ 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__"), Attr);
|
self.emit_store_instr(Identifier::public("__module__"), Name);
|
||||||
self.emit_load_const(name);
|
self.emit_load_const(name);
|
||||||
self.emit_store_instr(Identifier::public("__qualname__"), Attr);
|
self.emit_store_instr(Identifier::public("__qualname__"), Name);
|
||||||
if class.need_to_gen_new {
|
if class.need_to_gen_new {
|
||||||
self.emit_auto_new(&class.sig, class.__new__);
|
self.emit_auto_new(&class.sig, class.__new__);
|
||||||
}
|
}
|
||||||
|
@ -1479,19 +1477,13 @@ impl CodeGenerator {
|
||||||
fn emit_auto_new(&mut self, sig: &Signature, __new__: Type) {
|
fn emit_auto_new(&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 ident = Identifier::private_with_line(Str::ever("__new__"), 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);
|
||||||
let params = Params::new(
|
let param = ParamSignature::new(ParamPattern::VarName(param), None, None);
|
||||||
vec![ParamSignature::new(
|
let self_param = VarName::from_str_and_line(Str::ever("self"), line);
|
||||||
ParamPattern::VarName(param),
|
let self_param = ParamSignature::new(ParamPattern::VarName(self_param), None, None);
|
||||||
None,
|
let params = Params::new(vec![self_param, param], None, vec![], None);
|
||||||
None,
|
|
||||||
)],
|
|
||||||
None,
|
|
||||||
vec![],
|
|
||||||
None,
|
|
||||||
);
|
|
||||||
let sig = Signature::Subr(SubrSignature::new(ident, params.clone(), __new__.clone()));
|
let sig = Signature::Subr(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() {
|
||||||
|
@ -1503,34 +1495,32 @@ impl CodeGenerator {
|
||||||
Token::symbol_with_line(¶m_name[..], line),
|
Token::symbol_with_line(¶m_name[..], line),
|
||||||
Type::Failure,
|
Type::Failure,
|
||||||
));
|
));
|
||||||
let attr = Accessor::Attr(Attribute::new(
|
|
||||||
obj,
|
|
||||||
Token::symbol(&field.symbol[..]),
|
|
||||||
Type::Failure,
|
|
||||||
));
|
|
||||||
let obj = Expr::Accessor(Accessor::local(
|
|
||||||
Token::symbol_with_line("self", line),
|
|
||||||
Type::Failure,
|
|
||||||
));
|
|
||||||
let expr = Expr::Accessor(Accessor::Attr(Attribute::new(
|
let expr = Expr::Accessor(Accessor::Attr(Attribute::new(
|
||||||
obj,
|
obj,
|
||||||
Token::symbol(&field.symbol[..]),
|
Token::symbol(&field.symbol[..]),
|
||||||
Type::Failure,
|
Type::Failure,
|
||||||
)));
|
)));
|
||||||
|
let obj = Expr::Accessor(Accessor::local(
|
||||||
|
Token::symbol_with_line("self", line),
|
||||||
|
Type::Failure,
|
||||||
|
));
|
||||||
|
let attr = Accessor::Attr(Attribute::new(
|
||||||
|
obj,
|
||||||
|
Token::symbol(&field.symbol[..]),
|
||||||
|
Type::Failure,
|
||||||
|
));
|
||||||
let attr_def = AttrDef::new(attr, Block::new(vec![expr]));
|
let attr_def = AttrDef::new(attr, Block::new(vec![expr]));
|
||||||
attrs.push(Expr::AttrDef(attr_def));
|
attrs.push(Expr::AttrDef(attr_def));
|
||||||
}
|
}
|
||||||
|
let none = Token::new(TokenKind::NoneLit, "None", line, 0);
|
||||||
|
attrs.push(Expr::Lit(Literal::from(none)));
|
||||||
}
|
}
|
||||||
other => todo!("{other}"),
|
other => todo!("{other}"),
|
||||||
}
|
}
|
||||||
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 private_new_def = Def::new(sig, body.clone());
|
let init_def = Def::new(sig, body.clone());
|
||||||
self.codegen_expr(Expr::Def(private_new_def));
|
self.codegen_expr(Expr::Def(init_def));
|
||||||
let ident = Identifier::public_with_line(Token::dummy(), Str::ever("new"), line);
|
|
||||||
let sig = Signature::Subr(SubrSignature::new(ident, params, __new__));
|
|
||||||
let new_def = Def::new(sig, body);
|
|
||||||
self.codegen_expr(Expr::Def(new_def));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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 {
|
||||||
|
@ -1582,7 +1572,10 @@ impl CodeGenerator {
|
||||||
// end of flagging
|
// end of flagging
|
||||||
let unit = self.units.pop().unwrap();
|
let unit = self.units.pop().unwrap();
|
||||||
if !self.units.is_empty() {
|
if !self.units.is_empty() {
|
||||||
let ld = unit.prev_lineno - self.cur_block().prev_lineno;
|
let ld = unit
|
||||||
|
.prev_lineno
|
||||||
|
.checked_sub(self.cur_block().prev_lineno)
|
||||||
|
.unwrap_or(0);
|
||||||
if ld != 0 {
|
if ld != 0 {
|
||||||
if let Some(l) = self.mut_cur_block_codeobj().lnotab.last_mut() {
|
if let Some(l) = self.mut_cur_block_codeobj().lnotab.last_mut() {
|
||||||
*l += ld as u8;
|
*l += ld as u8;
|
||||||
|
@ -1593,6 +1586,25 @@ impl CodeGenerator {
|
||||||
unit.codeobj
|
unit.codeobj
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn load_prelude(&mut self) {
|
||||||
|
self.init_record();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn init_record(&mut self) {
|
||||||
|
// importing namedtuple
|
||||||
|
self.emit_load_const(0);
|
||||||
|
self.emit_load_const(ValueObj::Tuple(std::rc::Rc::from([ValueObj::Str(
|
||||||
|
Str::ever("namedtuple"),
|
||||||
|
)])));
|
||||||
|
let ident = Identifier::public("collections");
|
||||||
|
self.emit_import_name_instr(ident).unwrap();
|
||||||
|
let ident = Identifier::public("namedtuple");
|
||||||
|
self.emit_import_from_instr(ident).unwrap();
|
||||||
|
let ident = Identifier::private(Str::ever("#NamedTuple"));
|
||||||
|
self.emit_store_instr(ident, Name);
|
||||||
|
// self.namedtuple_loaded = true;
|
||||||
|
}
|
||||||
|
|
||||||
pub fn codegen(&mut self, hir: HIR) -> CodeObj {
|
pub fn codegen(&mut self, hir: HIR) -> CodeObj {
|
||||||
log!(info "the code-generating process has started.{RESET}");
|
log!(info "the code-generating process has started.{RESET}");
|
||||||
self.unit_size += 1;
|
self.unit_size += 1;
|
||||||
|
@ -1603,6 +1615,10 @@ impl CodeGenerator {
|
||||||
"<module>",
|
"<module>",
|
||||||
1,
|
1,
|
||||||
));
|
));
|
||||||
|
if !self.prelude_loaded {
|
||||||
|
self.load_prelude();
|
||||||
|
self.prelude_loaded = true;
|
||||||
|
}
|
||||||
let mut print_point = 0;
|
let mut print_point = 0;
|
||||||
if self.input().is_repl() {
|
if self.input().is_repl() {
|
||||||
print_point = self.cur_block().lasti;
|
print_point = self.cur_block().lasti;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue