55 lines
1.2 KiB
Python
55 lines
1.2 KiB
Python
import sys
|
|
|
|
class _Exit:
|
|
def __init__(self, code):
|
|
self.code = code
|
|
|
|
class _Jump:
|
|
def __init__(self, target):
|
|
self.target = target
|
|
|
|
class _Jmp(_Jump):
|
|
pass
|
|
|
|
class _Call(_Jump):
|
|
RETURN = object()
|
|
|
|
class _VM:
|
|
def __init__(self, entry, ctx=None):
|
|
self.current = entry
|
|
self.stack = []
|
|
self.ctx = ctx if ctx is not None else {}
|
|
|
|
def start(self):
|
|
while self.current is not None:
|
|
try:
|
|
self.loop()
|
|
except Exception as e:
|
|
print(f"Error: {e}")
|
|
sys.exit(1)
|
|
|
|
def loop(self):
|
|
action = self.current(self.ctx)
|
|
|
|
if isinstance(action, _Jmp):
|
|
self.current = action.target
|
|
return
|
|
|
|
if isinstance(action, _Call):
|
|
self.stack.append(self.current)
|
|
self.current = action.target
|
|
return
|
|
|
|
if action is _Call.RETURN:
|
|
if not self.stack:
|
|
self.current = None
|
|
return
|
|
self.current = self.stack.pop()
|
|
return
|
|
|
|
if isinstance(action, _Exit):
|
|
sys.exit(action.code)
|
|
|
|
print(f"Unknown action: {action}")
|
|
sys.exit(1)
|