init
This commit is contained in:
commit
38355d2442
9083 changed files with 1225834 additions and 0 deletions
103
.venv/lib/python3.8/site-packages/mypyc/transform/exceptions.py
Normal file
103
.venv/lib/python3.8/site-packages/mypyc/transform/exceptions.py
Normal file
|
|
@ -0,0 +1,103 @@
|
|||
"""Transform that inserts error checks after opcodes.
|
||||
|
||||
When initially building the IR, the code doesn't perform error checks
|
||||
for exceptions. This module is used to insert all required error checks
|
||||
afterwards. Each Op describes how it indicates an error condition (if
|
||||
at all).
|
||||
|
||||
We need to split basic blocks on each error check since branches can
|
||||
only be placed at the end of a basic block.
|
||||
"""
|
||||
|
||||
from typing import List, Optional
|
||||
|
||||
from mypyc.ir.ops import (
|
||||
Value, BasicBlock, LoadErrorValue, Return, Branch, RegisterOp, Integer, ERR_NEVER, ERR_MAGIC,
|
||||
ERR_FALSE, ERR_ALWAYS, NO_TRACEBACK_LINE_NO
|
||||
)
|
||||
from mypyc.ir.func_ir import FuncIR
|
||||
from mypyc.ir.rtypes import bool_rprimitive
|
||||
|
||||
|
||||
def insert_exception_handling(ir: FuncIR) -> None:
|
||||
# Generate error block if any ops may raise an exception. If an op
|
||||
# fails without its own error handler, we'll branch to this
|
||||
# block. The block just returns an error value.
|
||||
error_label = None
|
||||
for block in ir.blocks:
|
||||
can_raise = any(op.can_raise() for op in block.ops)
|
||||
if can_raise:
|
||||
error_label = add_handler_block(ir)
|
||||
break
|
||||
if error_label:
|
||||
ir.blocks = split_blocks_at_errors(ir.blocks, error_label, ir.traceback_name)
|
||||
|
||||
|
||||
def add_handler_block(ir: FuncIR) -> BasicBlock:
|
||||
block = BasicBlock()
|
||||
ir.blocks.append(block)
|
||||
op = LoadErrorValue(ir.ret_type)
|
||||
block.ops.append(op)
|
||||
block.ops.append(Return(op))
|
||||
return block
|
||||
|
||||
|
||||
def split_blocks_at_errors(blocks: List[BasicBlock],
|
||||
default_error_handler: BasicBlock,
|
||||
func_name: Optional[str]) -> List[BasicBlock]:
|
||||
new_blocks: List[BasicBlock] = []
|
||||
|
||||
# First split blocks on ops that may raise.
|
||||
for block in blocks:
|
||||
ops = block.ops
|
||||
block.ops = []
|
||||
cur_block = block
|
||||
new_blocks.append(cur_block)
|
||||
|
||||
# If the block has an error handler specified, use it. Otherwise
|
||||
# fall back to the default.
|
||||
error_label = block.error_handler or default_error_handler
|
||||
block.error_handler = None
|
||||
|
||||
for op in ops:
|
||||
target: Value = op
|
||||
cur_block.ops.append(op)
|
||||
if isinstance(op, RegisterOp) and op.error_kind != ERR_NEVER:
|
||||
# Split
|
||||
new_block = BasicBlock()
|
||||
new_blocks.append(new_block)
|
||||
|
||||
if op.error_kind == ERR_MAGIC:
|
||||
# Op returns an error value on error that depends on result RType.
|
||||
variant = Branch.IS_ERROR
|
||||
negated = False
|
||||
elif op.error_kind == ERR_FALSE:
|
||||
# Op returns a C false value on error.
|
||||
variant = Branch.BOOL
|
||||
negated = True
|
||||
elif op.error_kind == ERR_ALWAYS:
|
||||
variant = Branch.BOOL
|
||||
negated = True
|
||||
# this is a hack to represent the always fail
|
||||
# semantics, using a temporary bool with value false
|
||||
target = Integer(0, bool_rprimitive)
|
||||
else:
|
||||
assert False, 'unknown error kind %d' % op.error_kind
|
||||
|
||||
# Void ops can't generate errors since error is always
|
||||
# indicated by a special value stored in a register.
|
||||
if op.error_kind != ERR_ALWAYS:
|
||||
assert not op.is_void, "void op generating errors?"
|
||||
|
||||
branch = Branch(target,
|
||||
true_label=error_label,
|
||||
false_label=new_block,
|
||||
op=variant,
|
||||
line=op.line)
|
||||
branch.negated = negated
|
||||
if op.line != NO_TRACEBACK_LINE_NO and func_name is not None:
|
||||
branch.traceback_entry = (func_name, op.line)
|
||||
cur_block.ops.append(branch)
|
||||
cur_block = new_block
|
||||
|
||||
return new_blocks
|
||||
Loading…
Add table
Add a link
Reference in a new issue