Add PyCodeGenerator::deopt_instr

This commit is contained in:
Shunsuke Shibayama 2023-01-26 14:12:43 +09:00
parent bdfe59ac7c
commit eaded7ac5d
6 changed files with 40 additions and 6 deletions

1
.gitignore vendored
View file

@ -17,6 +17,7 @@
/*/.DS_Store
/.idea/
/timeit.dat
**/__pycache__/
# Nix
.direnv

View file

@ -77,7 +77,7 @@
even for and while expressions are just one of the subroutines, so this is possible.
```python
loop! block = while! do(True), block
loop! block! = while! do! True, block!
# equals to `while! do(True), do! print! "hello"`
loop! do!:
@ -202,7 +202,7 @@ nix build
By enabling the `--features` flag, you can customize the installation and build.
- You can change the language of the error message by using `--features {language}`
```sh
```sh
--features japanese
--features simplified_chinese
--features traditional_chinese

View file

@ -77,7 +77,7 @@
Ergでは特別扱いされる構文要素がとても少なく、例えば予約語が一つもありません。以下のような芸当も可能です。
```python
loop! block = while! do(True), block
loop! block! = while! do! True, block!
# `while! do(True), do! print! "hello"`と同じです
loop! do!:

View file

@ -77,7 +77,7 @@
在Erg中很少有东西被认为是特殊的没有关键字因此for和while表达式也只是子程序之一
```python
loop! block = while! do(True), block
loop! block! = while! do! True, block!
# equals to `while! do(True), do! print! "hello"`
loop! do!:

View file

@ -77,9 +77,9 @@
在Erg中很少有東西被認為是特殊的沒有關鍵字因此for和while表達式也只是子程序之一
```python
loop! block = while! do(True), block
loop! block! = while! do! True, block!
# equals to `while! do(True), do! print! "hello"`
# equals to `while! do! True, do! print! "hello"`
loop! do!:
print! "hello"
```

View file

@ -46,6 +46,18 @@ use crate::ty::{HasType, Type, TypeCode, TypePair};
use erg_common::fresh::fresh_varname;
use AccessKind::*;
#[allow(dead_code)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum ControlKind {
If,
While,
For,
Match,
With,
Discard,
Assert,
}
/// patch method -> function
/// patch attr -> variable
fn debind(ident: &Identifier) -> Option<Str> {
@ -1604,6 +1616,21 @@ impl PyCodeGenerator {
self.emit_load_const(ValueObj::None);
}
fn deopt_instr(&mut self, kind: ControlKind, args: Args) {
if !self.control_loaded {
self.load_control();
}
let local = match kind {
ControlKind::If => Identifier::public("if__"),
ControlKind::For => Identifier::public("for__"),
ControlKind::While => Identifier::public("while__"),
ControlKind::With => Identifier::public("with__"),
ControlKind::Discard => Identifier::public("discard__"),
kind => todo!("{kind:?}"),
};
self.emit_call_local(local, args);
}
fn emit_if_instr(&mut self, mut args: Args) {
log!(info "entered {}", fn_name!());
let init_stack_len = self.stack_len();
@ -1670,6 +1697,9 @@ impl PyCodeGenerator {
fn emit_for_instr(&mut self, mut args: Args) {
log!(info "entered {} ({})", fn_name!(), args);
if !matches!(args.get(1).unwrap(), Expr::Lambda(_)) {
return self.deopt_instr(ControlKind::For, args);
}
let _init_stack_len = self.stack_len();
let iterable = args.remove(0);
self.emit_expr(iterable);
@ -1716,6 +1746,9 @@ impl PyCodeGenerator {
fn emit_while_instr(&mut self, mut args: Args) {
log!(info "entered {} ({})", fn_name!(), args);
if !matches!(args.get(1).unwrap(), Expr::Lambda(_)) {
return self.deopt_instr(ControlKind::While, args);
}
let _init_stack_len = self.stack_len();
// e.g. is_foo!: () => Bool, do!(is_bar)
let cond_block = args.remove(0);