Merge branch 'main' into patch

This commit is contained in:
Shunsuke Shibayama 2022-12-05 17:25:45 +09:00
commit 52c76431ee
55 changed files with 876 additions and 249 deletions

View file

@ -138,6 +138,7 @@ pub struct PyCodeGenerator {
pub(crate) py_version: PythonVersion,
str_cache: CacheSet<str>,
prelude_loaded: bool,
mutate_op_loaded: bool,
in_op_loaded: bool,
record_type_loaded: bool,
module_type_loaded: bool,
@ -154,6 +155,7 @@ impl PyCodeGenerator {
cfg,
str_cache: CacheSet::new(),
prelude_loaded: false,
mutate_op_loaded: false,
in_op_loaded: false,
record_type_loaded: false,
module_type_loaded: false,
@ -431,7 +433,8 @@ impl PyCodeGenerator {
}
fn emit_load_const<C: Into<ValueObj>>(&mut self, cons: C) {
let value = cons.into();
let value: ValueObj = cons.into();
let is_int = value.is_int();
let is_nat = value.is_nat();
let is_bool = value.is_bool();
if !self.cfg.no_std {
@ -441,6 +444,9 @@ impl PyCodeGenerator {
} else if is_nat {
self.emit_push_null();
self.emit_load_name_instr(Identifier::public("Nat"));
} else if is_int {
self.emit_push_null();
self.emit_load_name_instr(Identifier::public("Int"));
}
}
let idx = self
@ -455,7 +461,8 @@ impl PyCodeGenerator {
self.write_instr(LOAD_CONST);
self.write_arg(idx);
self.stack_inc();
if !self.cfg.no_std && is_nat {
if !self.cfg.no_std && is_int {
// is_int => is_nat and is_bool
self.emit_call_instr(1, Name);
self.stack_dec();
}
@ -1290,12 +1297,18 @@ impl PyCodeGenerator {
fn emit_unaryop(&mut self, unary: UnaryOp) {
log!(info "entered {} ({unary})", fn_name!());
let tycode = TypeCode::from(unary.lhs_t());
self.emit_expr(*unary.expr);
let instr = match &unary.op.kind {
// TODO:
TokenKind::PrePlus => UNARY_POSITIVE,
TokenKind::PreMinus => UNARY_NEGATIVE,
TokenKind::Mutate => NOP, // ERG_MUTATE,
TokenKind::Mutate => {
if !self.mutate_op_loaded {
self.load_mutate_op();
}
self.emit_push_null();
self.emit_load_name_instr(Identifier::private("#mutate_operator"));
NOP // ERG_MUTATE,
}
_ => {
CompileError::feature_error(
self.cfg.input.clone(),
@ -1307,8 +1320,14 @@ impl PyCodeGenerator {
NOT_IMPLEMENTED
}
};
self.write_instr(instr);
self.write_arg(tycode as usize);
self.emit_expr(*unary.expr);
if instr != NOP {
self.write_instr(instr);
self.write_arg(tycode as usize);
} else {
self.emit_precall_and_call(1);
self.stack_dec();
}
}
fn emit_binop(&mut self, bin: BinOp) {
@ -1767,7 +1786,7 @@ impl PyCodeGenerator {
}
fn emit_match_guard(&mut self, t_spec: TypeSpec, pop_jump_points: &mut Vec<usize>) {
#[allow(clippy::single_match)]
log!(info "entered {} ({t_spec})", fn_name!());
match t_spec {
TypeSpec::Enum(enum_t) => {
let elems = ValueObj::vec_from_const_args(enum_t);
@ -1817,14 +1836,42 @@ impl PyCodeGenerator {
self.write_arg(0);
self.stack_dec();
}
// _: (Int, Str)
TypeSpec::Tuple(tup) => {
let len = tup.len();
for (i, t_spec) in tup.into_iter().enumerate() {
if i != 0 && i != len - 1 {
self.dup_top();
}
self.emit_load_const(i);
self.write_instr(Opcode311::BINARY_SUBSCR);
self.write_arg(0);
self.stack_dec();
self.emit_match_guard(t_spec, pop_jump_points);
}
}
// TODO: consider ordering (e.g. both [1, 2] and [2, 1] is type of [{1, 2}; 2])
TypeSpec::Array(arr) => {
let ValueObj::Nat(len) = ValueObj::from_const_expr(arr.len) else { todo!() };
for i in 0..=(len - 1) {
if i != 0 && i != len - 1 {
self.dup_top();
}
self.emit_load_const(i);
self.write_instr(Opcode311::BINARY_SUBSCR);
self.write_arg(0);
self.stack_dec();
self.emit_match_guard(*arr.ty.clone(), pop_jump_points);
}
}
/*TypeSpec::Interval { op, lhs, rhs } => {
let binop = BinOp::new(op, lhs.downcast(), rhs.downcast(), VarInfo::default());
self.emit_binop(binop);
}*/
// TODO:
other => {
log!(err "{other}")
}
TypeSpec::Infer(_) => unreachable!(),
// TODO:
other => log!(err "{other}"),
}
}
@ -2015,7 +2062,7 @@ impl PyCodeGenerator {
} else if let Some(func_name) = debind(&method_name) {
return self.emit_call_fake_method(obj, func_name, method_name, args);
}
let is_py_api = obj.is_py_api();
let is_py_api = method_name.is_py_api();
self.emit_expr(obj);
self.emit_load_method_instr(method_name);
self.emit_args_311(args, Method, is_py_api);
@ -2699,10 +2746,15 @@ impl PyCodeGenerator {
}
fn load_prelude(&mut self) {
// NOTE: Integers need to be used in IMPORT_NAME
// but `Int` are called before importing it, so they need to be no_std mode
let no_std = self.cfg.no_std;
self.cfg.no_std = true;
self.load_record_type();
self.load_prelude_py();
self.prelude_loaded = true;
self.record_type_loaded = true;
self.cfg.no_std = no_std;
}
fn load_in_op(&mut self) {
@ -2721,6 +2773,22 @@ impl PyCodeGenerator {
self.in_op_loaded = true;
}
fn load_mutate_op(&mut self) {
let mod_name = if self.py_version.minor >= Some(10) {
Identifier::public("_erg_std_prelude")
} else {
Identifier::public("_erg_std_prelude_old")
};
self.emit_global_import_items(
mod_name,
vec![(
Identifier::public("mutate_operator"),
Some(Identifier::private("#mutate_operator")),
)],
);
self.mutate_op_loaded = true;
}
fn load_control(&mut self) {
let mod_name = Identifier::public("_erg_control");
self.emit_import_all_instr(mod_name);