|
@@ -157,6 +157,48 @@ class AnalysisState(object):
|
|
|
|
|
|
def analyze_resolve(self, instruction):
|
|
|
"""Analyzes a 'resolve' instruction."""
|
|
|
+ def __resolve_global_carefully():
|
|
|
+ # We might be resolving a global that does not exist. In that case, we
|
|
|
+ # need to throw. We want to create the following blocks:
|
|
|
+ #
|
|
|
+ # !current_block(...):
|
|
|
+ # ...
|
|
|
+ # $resolved_global = resolve-global global
|
|
|
+ # $nothing = literal None
|
|
|
+ # $condition = binary $resolved_global, 'is', $nothing
|
|
|
+ # select $condition, !no_global_block(), !global_exists_block()
|
|
|
+ #
|
|
|
+ # !no_global_block():
|
|
|
+ # $message = literal <GLOBAL_NOT_FOUND_MESSAGE_FORMAT % instruction.variable.name>
|
|
|
+ # $exception = direct-call "simple-positional" Exception(message=$message)
|
|
|
+ # throw $exception
|
|
|
+ #
|
|
|
+ # !global_exists_block():
|
|
|
+ # ...
|
|
|
+ #
|
|
|
+ no_global_block = cfg_ir.BasicBlock(self.counter)
|
|
|
+ global_exists_block = cfg_ir.BasicBlock(self.counter)
|
|
|
+
|
|
|
+ resolved_global = self.current_block.append_definition(
|
|
|
+ cfg_ir.ResolveGlobal(instruction.variable))
|
|
|
+ nothing = self.current_block.append_definition(cfg_ir.Literal(None))
|
|
|
+ condition = self.current_block.append_definition(
|
|
|
+ cfg_ir.Binary(resolved_global, 'is', nothing))
|
|
|
+ self.current_block.flow = cfg_ir.SelectFlow(
|
|
|
+ condition, cfg_ir.Branch(no_global_block), cfg_ir.Branch(global_exists_block))
|
|
|
+
|
|
|
+ message = no_global_block.append_definition(
|
|
|
+ cfg_ir.Literal(
|
|
|
+ jit_runtime.GLOBAL_NOT_FOUND_MESSAGE_FORMAT % instruction.variable.name))
|
|
|
+ exception = no_global_block.append_definition(
|
|
|
+ cfg_ir.DirectFunctionCall(
|
|
|
+ 'Exception',
|
|
|
+ [('message', message)],
|
|
|
+ cfg_ir.SIMPLE_POSITIONAL_CALLING_CONVENTION))
|
|
|
+ no_global_block.flow = cfg_ir.ThrowFlow(exception)
|
|
|
+
|
|
|
+ self.current_block = global_exists_block
|
|
|
+ return resolved_global
|
|
|
return self.emit_select(
|
|
|
lambda:
|
|
|
self.current_block.append_definition(
|
|
@@ -164,9 +206,7 @@ class AnalysisState(object):
|
|
|
lambda:
|
|
|
self.current_block.append_definition(
|
|
|
cfg_ir.ResolveLocal(instruction.variable)),
|
|
|
- lambda:
|
|
|
- self.current_block.append_definition(
|
|
|
- cfg_ir.ResolveGlobal(instruction.variable)))
|
|
|
+ __resolve_global_carefully)
|
|
|
|
|
|
def analyze_declare(self, instruction):
|
|
|
"""Analyzes a 'declare' instruction."""
|
|
@@ -175,7 +215,17 @@ class AnalysisState(object):
|
|
|
|
|
|
def analyze_global(self, instruction):
|
|
|
"""Analyzes a 'global' instruction."""
|
|
|
- return self.current_block.append_definition(cfg_ir.DeclareGlobal(instruction.variable))
|
|
|
+ resolved_global = self.current_block.append_definition(
|
|
|
+ cfg_ir.ResolveGlobal(instruction.variable))
|
|
|
+ nothing = self.current_block.append_definition(cfg_ir.Literal(None))
|
|
|
+ return self.emit_select(
|
|
|
+ lambda:
|
|
|
+ self.current_block.append_definition(
|
|
|
+ cfg_ir.Binary(resolved_global, 'is', nothing)),
|
|
|
+ lambda:
|
|
|
+ self.current_block.append_definition(
|
|
|
+ cfg_ir.DeclareGlobal(instruction.variable)),
|
|
|
+ lambda: resolved_global)
|
|
|
|
|
|
def analyze_assign(self, instruction):
|
|
|
"""Analyzes an 'assign' instruction."""
|