Fix codegen bug

This commit is contained in:
Shunsuke Shibayama 2022-10-20 23:22:46 +09:00
parent c2e7f78b73
commit e26a89c0b3
7 changed files with 73 additions and 28 deletions

View file

@ -6,7 +6,7 @@ use std::process::Command;
use crate::serialize::get_magic_num_from_bytes; use crate::serialize::get_magic_num_from_bytes;
#[cfg(unix)] #[cfg(unix)]
pub const BUILTIN_PYTHON_MODS: [&str; 17] = [ pub const BUILTIN_PYTHON_MODS: [&str; 18] = [
"glob", "glob",
"http", "http",
"importlib", "importlib",
@ -17,6 +17,7 @@ pub const BUILTIN_PYTHON_MODS: [&str; 17] = [
"posix", "posix",
"random", "random",
"re", "re",
"shutil",
"socket", "socket",
"subprocess", "subprocess",
"sys", "sys",
@ -26,7 +27,7 @@ pub const BUILTIN_PYTHON_MODS: [&str; 17] = [
"zipfile", "zipfile",
]; ];
#[cfg(not(unix))] #[cfg(not(unix))]
pub const BUILTIN_PYTHON_MODS: [&str; 16] = [ pub const BUILTIN_PYTHON_MODS: [&str; 17] = [
"glob", "glob",
"http", "http",
"importlib", "importlib",
@ -36,6 +37,7 @@ pub const BUILTIN_PYTHON_MODS: [&str; 16] = [
"os", "os",
"random", "random",
"re", "re",
"shutil",
"socket", "socket",
"subprocess", "subprocess",
"sys", "sys",

View file

@ -947,9 +947,17 @@ impl CodeGenerator {
match &bin.op.kind { match &bin.op.kind {
// l..<r == range(l, r) // l..<r == range(l, r)
TokenKind::RightOpen => { TokenKind::RightOpen => {
self.emit_load_name_instr(Identifier::public("range")); self.emit_load_name_instr(Identifier::public("RightOpenRange"));
}
TokenKind::LeftOpen => {
self.emit_load_name_instr(Identifier::public("LeftOpenRange"));
}
TokenKind::Closed => {
self.emit_load_name_instr(Identifier::public("ClosedRange"));
}
TokenKind::Open => {
self.emit_load_name_instr(Identifier::public("OpenRange"));
} }
TokenKind::LeftOpen | TokenKind::Closed | TokenKind::Open => todo!(),
TokenKind::InOp => { TokenKind::InOp => {
// if no-std, always `x in y == True` // if no-std, always `x in y == True`
if self.cfg.no_std { if self.cfg.no_std {
@ -1056,6 +1064,7 @@ impl CodeGenerator {
fn emit_if_instr(&mut self, mut args: Args) { fn emit_if_instr(&mut self, mut args: Args) {
log!(info "entered {}", fn_name!()); log!(info "entered {}", fn_name!());
let init_stack_len = self.cur_block().stack_len;
let cond = args.remove(0); let cond = args.remove(0);
self.emit_expr(cond); self.emit_expr(cond);
let idx_pop_jump_if_false = self.cur_block().lasti; let idx_pop_jump_if_false = self.cur_block().lasti;
@ -1065,8 +1074,8 @@ impl CodeGenerator {
match args.remove(0) { match args.remove(0) {
// then block // then block
Expr::Lambda(lambda) => { Expr::Lambda(lambda) => {
let params = self.gen_param_names(&lambda.params); // let params = self.gen_param_names(&lambda.params);
self.emit_frameless_block(lambda.body, params); self.emit_frameless_block(lambda.body, vec![]);
} }
other => { other => {
self.emit_expr(other); self.emit_expr(other);
@ -1080,8 +1089,8 @@ impl CodeGenerator {
self.edit_code(idx_pop_jump_if_false + 1, idx_else_begin / 2); self.edit_code(idx_pop_jump_if_false + 1, idx_else_begin / 2);
match args.remove(0) { match args.remove(0) {
Expr::Lambda(lambda) => { Expr::Lambda(lambda) => {
let params = self.gen_param_names(&lambda.params); // let params = self.gen_param_names(&lambda.params);
self.emit_frameless_block(lambda.body, params); self.emit_frameless_block(lambda.body, vec![]);
} }
other => { other => {
self.emit_expr(other); self.emit_expr(other);
@ -1090,15 +1099,18 @@ impl CodeGenerator {
let idx_jump_forward = idx_else_begin - 2; let idx_jump_forward = idx_else_begin - 2;
let idx_end = self.cur_block().lasti; let idx_end = self.cur_block().lasti;
self.edit_code(idx_jump_forward + 1, (idx_end - idx_jump_forward - 2) / 2); self.edit_code(idx_jump_forward + 1, (idx_end - idx_jump_forward - 2) / 2);
// FIXME: this is a hack to make sure the stack is balanced
while self.cur_block().stack_len != init_stack_len + 1 {
self.stack_dec(); self.stack_dec();
// self.stack_dec(); }
} else { } else {
// no else block // no else block
let idx_end = self.cur_block().lasti; let idx_end = self.cur_block().lasti;
self.edit_code(idx_pop_jump_if_false + 1, idx_end / 2); self.edit_code(idx_pop_jump_if_false + 1, idx_end / 2);
self.emit_load_const(ValueObj::None); self.emit_load_const(ValueObj::None);
while self.cur_block().stack_len != init_stack_len + 1 {
self.stack_dec(); self.stack_dec();
self.stack_dec(); }
} }
} }
@ -1110,18 +1122,24 @@ impl CodeGenerator {
self.write_arg(0); self.write_arg(0);
let idx_for_iter = self.cur_block().lasti; let idx_for_iter = self.cur_block().lasti;
self.write_instr(FOR_ITER); self.write_instr(FOR_ITER);
self.stack_inc();
// FOR_ITER pushes a value onto the stack, but we can't know how many // FOR_ITER pushes a value onto the stack, but we can't know how many
// but after executing this instruction, stack_len should be 1 // but after executing this instruction, stack_len should be 1
// cannot detect where to jump to at this moment, so put as 0 // cannot detect where to jump to at this moment, so put as 0
self.write_arg(0); self.write_arg(0);
let lambda = enum_unwrap!(args.remove(0), Expr::Lambda); let lambda = enum_unwrap!(args.remove(0), Expr::Lambda);
let init_stack_len = self.cur_block().stack_len;
let params = self.gen_param_names(&lambda.params); let params = self.gen_param_names(&lambda.params);
self.emit_frameless_block(lambda.body, params); // ここでPOPされる self.emit_frameless_block(lambda.body, params);
if self.cur_block().stack_len >= init_stack_len {
self.emit_pop_top();
}
self.write_instr(JUMP_ABSOLUTE); self.write_instr(JUMP_ABSOLUTE);
self.write_arg((idx_for_iter / 2) as u8); self.write_arg((idx_for_iter / 2) as u8);
let idx_end = self.cur_block().lasti; let idx_end = self.cur_block().lasti;
self.edit_code(idx_for_iter + 1, (idx_end - idx_for_iter - 2) / 2); self.edit_code(idx_for_iter + 1, (idx_end - idx_for_iter - 2) / 2);
self.emit_pop_top(); // self.emit_pop_top();
self.stack_dec();
self.emit_load_const(ValueObj::None); self.emit_load_const(ValueObj::None);
} }
@ -1661,11 +1679,10 @@ impl CodeGenerator {
Name, Name,
); );
} }
let init_stack_len = self.cur_block().stack_len;
for expr in block.into_iter() { for expr in block.into_iter() {
self.emit_expr(expr); self.emit_expr(expr);
// TODO: discard if self.cur_block().stack_len > init_stack_len {
// 最終的に帳尻を合わせる(コード生成の順番的にスタックの整合性が一時的に崩れる場合がある)
if self.cur_block().stack_len == 1 {
self.emit_pop_top(); self.emit_pop_top();
} }
} }
@ -1681,10 +1698,11 @@ impl CodeGenerator {
Name, Name,
); );
} }
let init_stack_len = self.cur_block().stack_len;
for expr in block.into_iter() { for expr in block.into_iter() {
self.emit_expr(expr); self.emit_expr(expr);
// __exit__, __enter__() are on the stack // __exit__, __enter__() are on the stack
if self.cur_block().stack_len != 2 { if self.cur_block().stack_len > init_stack_len {
self.emit_pop_top(); self.emit_pop_top();
} }
} }
@ -1852,19 +1870,20 @@ impl CodeGenerator {
&name, &name,
firstlineno, firstlineno,
)); ));
let init_stack_len = self.cur_block().stack_len;
for expr in block.into_iter() { for expr in block.into_iter() {
self.emit_expr(expr); self.emit_expr(expr);
// NOTE: 各行のトップレベルでは0個または1個のオブジェクトが残っている // NOTE: 各行のトップレベルでは0個または1個のオブジェクトが残っている
// Pythonの場合使わなかったオブジェクトはそのまま捨てられるが、Ergではdiscardを使う必要がある // Pythonの場合使わなかったオブジェクトはそのまま捨てられるが、Ergではdiscardを使う必要がある
// TODO: discard // TODO: discard
if self.cur_block().stack_len == 1 { if self.cur_block().stack_len > init_stack_len {
self.emit_pop_top(); self.emit_pop_top();
} }
} }
self.cancel_pop_top(); // 最後の値は戻り値として取っておく self.cancel_pop_top(); // 最後の値は戻り値として取っておく
if self.cur_block().stack_len == 0 { if self.cur_block().stack_len == init_stack_len {
self.emit_load_const(ValueObj::None); self.emit_load_const(ValueObj::None);
} else if self.cur_block().stack_len > 1 { } else if self.cur_block().stack_len > init_stack_len + 1 {
let block_id = self.cur_block().id; let block_id = self.cur_block().id;
let stack_len = self.cur_block().stack_len; let stack_len = self.cur_block().stack_len;
CompileError::stack_bug( CompileError::stack_bug(

View file

@ -1283,6 +1283,8 @@ impl Context {
str_iterator.register_superclass(Obj, &obj); str_iterator.register_superclass(Obj, &obj);
let mut array_iterator = Self::builtin_poly_class("ArrayIterator", vec![PS::t_nd("T")], 1); let mut array_iterator = Self::builtin_poly_class("ArrayIterator", vec![PS::t_nd("T")], 1);
array_iterator.register_superclass(Obj, &obj); array_iterator.register_superclass(Obj, &obj);
let mut range_iterator = Self::builtin_poly_class("RangeIterator", vec![PS::t_nd("T")], 1);
range_iterator.register_superclass(Obj, &obj);
/* Float_mut */ /* Float_mut */
let mut float_mut = Self::builtin_mono_class("Float!", 2); let mut float_mut = Self::builtin_mono_class("Float!", 2);
float_mut.register_superclass(Float, &float); float_mut.register_superclass(Float, &float);
@ -1523,6 +1525,15 @@ impl Context {
Public, Public,
); );
range.register_trait(range_t.clone(), range_eq); range.register_trait(range_t.clone(), range_eq);
let mut range_iterable =
Self::builtin_methods(Some(poly("Iterable", vec![ty_tp(mono_q("T"))])), 2);
range_iterable.register_builtin_impl(
"iter",
fn0_met(Str, mono("RangeIterator")),
Immutable,
Public,
);
range.register_trait(range_t.clone(), range_iterable);
/* Proc */ /* Proc */
let mut proc = Self::builtin_mono_class("Proc", 2); let mut proc = Self::builtin_mono_class("Proc", 2);
proc.register_superclass(Obj, &obj); proc.register_superclass(Obj, &obj);
@ -1589,6 +1600,13 @@ impl Context {
Const, Const,
Some("array_iterator"), Some("array_iterator"),
); );
self.register_builtin_type(
poly("RangeIterator", vec![ty_tp(mono_q("T"))]),
range_iterator,
Private,
Const,
Some("RangeIterator"),
);
self.register_builtin_type(mono("Int!"), int_mut, Private, Const, Some("int")); self.register_builtin_type(mono("Int!"), int_mut, Private, Const, Some("int"));
self.register_builtin_type(mono("Nat!"), nat_mut, Private, Const, Some("Nat")); self.register_builtin_type(mono("Nat!"), nat_mut, Private, Const, Some("Nat"));
self.register_builtin_type(mono("Float!"), float_mut, Private, Const, Some("float")); self.register_builtin_type(mono("Float!"), float_mut, Private, Const, Some("float"));

View file

@ -1 +1 @@
.expanduser!: (path: PathLike,) => NoneType .expanduser!: (path: PathLike,) => Str

View file

@ -0,0 +1,6 @@
.copyfile!: (src: PathLike, dst: PathLike,) => NoneType
.copy!: (src: PathLike, dst: PathLike,) => NoneType
.copytree!: (src: PathLike, dst: PathLike,) => NoneType
.rmtree!: (path: PathLike,) => NoneType
.move!: (src: PathLike, dst: PathLike) => NoneType
.which!: (cmd: Str,) => Str or NoneType

View file

@ -1,7 +1,8 @@
.ZipFile!: ClassType .ZipFile!: ClassType
.ZipFile! <: FileLike! .ZipFile! <: FileLike!
.ZipFile!.open!: (path: PathLike or FileLike!, mode := Str) => .ZipFile! .open! = 'ZipFile': (path: PathLike or FileLike!, mode := Str) => .ZipFile!
.ZipFile!.open!: (name: PathLike, mode := Str) => .ZipFile!
.ZipFile!.add!: (self: RefMut(.ZipFile!), name: PathLike, arcname: PathLike or NoneType := NoneType, recursive := Bool) => NoneType .ZipFile!.add!: (self: RefMut(.ZipFile!), name: PathLike, arcname: PathLike or NoneType := NoneType, recursive := Bool) => NoneType
.ZipFile!.close!: (self: .ZipFile!,) => NoneType .ZipFile!.close!: (self: .ZipFile!,) => NoneType
.ZipFile!.extractall!: (self: RefMut(.ZipFile!), path := PathLike, members: [Str; _] or NoneType := NoneType, numeric_owner := Bool) => NoneType .ZipFile!.extractall!: (self: RefMut(.ZipFile!), path := PathLike, members: [Str; _] or NoneType := NoneType, numeric_owner := Bool) => NoneType

View file

@ -67,7 +67,6 @@ class Bool(Nat):
class Str(str): class Str(str):
def __instancecheck__(cls, obj): def __instancecheck__(cls, obj):
print(cls, obj)
return obj == Str or obj == str return obj == Str or obj == str
def try_new(s: str): # -> Result[Nat] def try_new(s: str): # -> Result[Nat]
@ -133,10 +132,10 @@ class RangeIterator:
def __init__(self, rng): def __init__(self, rng):
self.rng = rng self.rng = rng
self.needle = self.rng.start self.needle = self.rng.start
if type(self.rng.start) == int: if issubclass(Nat, type(self.rng.start)):
if not(self.needle in self.rng): if not(self.needle in self.rng):
self.needle += 1 self.needle += 1
elif type(self.rng.start) == str: elif issubclass(Str, type(self.rng.start)):
if not(self.needle in self.rng): if not(self.needle in self.rng):
self.needle = chr(ord(self.needle) + 1) self.needle = chr(ord(self.needle) + 1)
else: else:
@ -147,12 +146,12 @@ class RangeIterator:
return self return self
def __next__(self): def __next__(self):
if type(self.rng.start) == int: if issubclass(Nat, type(self.rng.start)):
if self.needle in self.rng: if self.needle in self.rng:
result = self.needle result = self.needle
self.needle += 1 self.needle += 1
return result return result
elif type(self.rng.start) == str: elif issubclass(Str, type(self.rng.start)):
if self.needle in self.rng: if self.needle in self.rng:
result = self.needle result = self.needle
self.needle = chr(ord(self.needle) + 1) self.needle = chr(ord(self.needle) + 1)