feat: add ATL animation timelines and try/raise to the Ren'Py player
Python sandbox - try/except/else/finally, raise (incl. re-raise), assert, for/while ... else - Multi-generator and dict comprehensions - Builtin exception hierarchy; user exceptions subclass it - Inside try, missing keys/indexes, division by zero, attribute access on None and unknown names raise Python exceptions; lookups stay lenient elsewhere - int()/float() raise ValueError on non-numeric strings ATL - converter/atl.py: set/move (linear, ease, easein, easeout), pause, repeat, parallel, choice, block, on show/hide and named transforms become a timeline shipped as game.json "atl"; Move() becomes a linear slide - player/atl.ts: timeline runner wired into the renderer; `on hide` plays before the picture is removed - function, time, contains, matrixcolor and expressions still block the import Tests: exceptions/ATL fixtures and runtime tests, converter ATL tests; README and ARCHITECTURE updated. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
962595c925
commit
ff82d882c0
18 files changed
+1050
-53
No files matched your search
+99
@@ -0,0 +1,99 @@
|
||||
# Source of exceptions.ir.json. Regenerate from backend/ with:
|
||||
# python -m tests.make_ir ../frontend/tests/fixtures/exceptions.py ../frontend/tests/fixtures/exceptions.ir.json
|
||||
|
||||
|
||||
class AppError(Exception):
|
||||
def __init__(self, msg, code=0):
|
||||
super().__init__(msg)
|
||||
self.code = code
|
||||
|
||||
|
||||
def risky(n):
|
||||
if n == 0:
|
||||
raise AppError("zero", code=7)
|
||||
return 10 // n
|
||||
|
||||
|
||||
log = []
|
||||
try:
|
||||
risky(0)
|
||||
except AppError as e:
|
||||
log.append(str(e))
|
||||
result_code = e.code
|
||||
else:
|
||||
log.append("no")
|
||||
finally:
|
||||
log.append("fin")
|
||||
|
||||
try:
|
||||
d = {"a": 1}
|
||||
v = d["b"]
|
||||
except KeyError:
|
||||
result_key = "keyerror"
|
||||
|
||||
try:
|
||||
xs = [1]
|
||||
xs[5]
|
||||
except (IndexError, ValueError):
|
||||
result_index = "indexerror"
|
||||
|
||||
try:
|
||||
int("abc")
|
||||
except ValueError:
|
||||
result_value = "valueerror"
|
||||
|
||||
try:
|
||||
risky(0)
|
||||
except Exception:
|
||||
result_generic = True
|
||||
|
||||
try:
|
||||
result_zero = 1 / 0
|
||||
except ZeroDivisionError:
|
||||
result_zero = "zerodiv"
|
||||
|
||||
|
||||
def retry():
|
||||
for i in range(3):
|
||||
try:
|
||||
if i < 2:
|
||||
raise ValueError("again")
|
||||
return i
|
||||
except ValueError:
|
||||
continue
|
||||
return -1
|
||||
|
||||
|
||||
result_retry = retry()
|
||||
|
||||
found = None
|
||||
for n in [1, 3, 5]:
|
||||
if n % 2 == 0:
|
||||
found = n
|
||||
break
|
||||
else:
|
||||
found = "none"
|
||||
result_forelse = found
|
||||
|
||||
k = 0
|
||||
while k < 3:
|
||||
k += 1
|
||||
else:
|
||||
k = k * 10
|
||||
result_whileelse = k
|
||||
|
||||
try:
|
||||
try:
|
||||
raise RuntimeError("inner")
|
||||
except RuntimeError:
|
||||
raise
|
||||
except RuntimeError as e3:
|
||||
result_reraise = str(e3)
|
||||
|
||||
result_pairs = [(x, y) for x in [1, 2] for y in [3, 4]]
|
||||
result_dictcomp = {a: b for a in [1, 2] for b in [a * 10] if b > 10}
|
||||
|
||||
try:
|
||||
assert 1 == 2, "boom"
|
||||
except AssertionError as e4:
|
||||
result_assert = str(e4)
|
||||
Reference in new issue
Block a user