Implement 'add image' screen language statement.

This commit is contained in:
Andy_kl
2024-09-07 00:25:17 +04:00
parent 79bda8a568
commit 48d19bb038
2 changed files with 171 additions and 13 deletions
+100
View File
@@ -1377,6 +1377,106 @@ class SLDisplayable(SLBlock):
i.dump_const(prefix + " ")
class SLAddImage(SLDisplayable):
def __init__(self, loc, name):
super().__init__(loc, None, name=name, unique=False)
def execute(self, context):
debug = context.debug
cache = context.old_cache.get(self.serial, None) or context.miss_cache.get(self.serial, None)
# We use and check 'displayable', 'constant' and 'old_showif'
# fields, and rest are left unchanged.
if not isinstance(cache, SLCache):
cache = SLCache()
context.new_cache[self.serial] = cache
if debug:
self.debug_line()
# Add image does not use style or scope.
if cache.constant is not None:
d = cache.constant
if context.showif is not None:
d = self.wrap_in_showif(d, context, cache)
context.children.append(d)
if debug:
profile_log.write(" reused constant displayable")
return
# Create the context.
ctx = SLContext(context)
# True if we encountered an exception that we're recovering from
# due to being in prediction mode.
fail = False
# Result transform to display.
d = None
try:
ctx.keywords = {}
SLBlock.keywords(self, ctx)
d = ctx.keywords.pop("at")
assert not ctx.keywords, ctx.keywords
if debug:
self.report_arguments(cache, (), {}, None)
d._location = self.location
cache.copy_on_change = False # We no longer need to copy on change.
if debug:
if self.constant:
profile_log.write(" created constant displayable")
else:
profile_log.write(" created displayable")
except Exception:
if not context.predicting:
raise
fail = True
if self.variable is not None:
context.scope[self.variable] = d
old_d = cache.displayable
if old_d is not None:
d.take_state(old_d)
d.take_execution_state(old_d)
# If a failure occurred during prediction, predict main (if known),
# and return.
if fail:
predict_displayable(d)
context.fail = True
return
cache.displayable = d
if ctx.fail:
context.fail = True
else:
if self.constant:
cache.constant = d
if context.showif is not None:
d = self.wrap_in_showif(d, context, cache)
context.children.append(d)
class SLIf(SLNode):
"""
A screen language AST node that corresponds to an If/Elif/Else statement.
+69 -11
View File
@@ -194,21 +194,42 @@ class Parser(object):
self.keyword[i.prefix + j + i.name] = i
elif isinstance(i, Parser):
self.children[i.name] = i
self.children[tuple(i.name.split())] = i
def parse_statement(self, loc, l, layout_mode=False, keyword=True):
word = l.word() or l.match(r'\$')
if word and word in self.children:
if layout_mode:
c = self.children[word].parse_layout(loc, l, self, keyword)
else:
c = self.children[word].parse(loc, l, self, keyword)
return c
# Look for one-line python only once.
if l.match(r'\$'):
if ("$", ) in self.children:
assert not layout_mode, "One-line python can not be in layout mode."
return self.children["$", ].parse(loc, l, self, keyword)
else:
return None
name = ()
while True:
cp = l.checkpoint()
word = l.word()
if not word:
break
# Look for more specialized child parser.
new_name = (*name, word)
if new_name not in self.children:
l.revert(cp)
break
name = new_name
if not name:
return None
if layout_mode:
c = self.children[name].parse_layout(loc, l, self, keyword)
else:
c = self.children[name].parse(loc, l, self, keyword)
return c
def parse_layout(self, loc, l, parent, keyword):
l.error("The %s statement cannot be used as a container for the has statement." % self.name)
@@ -229,7 +250,16 @@ class Parser(object):
raise Exception("Not Implemented")
def parse_contents(self, l, target, layout_mode=False, can_has=False, can_tag=False, block_only=False, keyword=True):
def parse_contents(
self,
l, target,
layout_mode=False,
can_has=False,
can_tag=False,
block_only=False,
keyword=True,
line_only=False,
):
"""
Parses the remainder of the current line of `l`, and all of its subblock,
looking for keywords and children.
@@ -247,6 +277,10 @@ class Parser(object):
`block_only`
If true, only parse the block and not the initial properties.
`line_only`
If true, only parse initial properties and not the block.
Lexer ends before the colon (if any).
"""
seen_keywords = set()
@@ -330,7 +364,13 @@ class Parser(object):
# If not block_only, we allow keyword arguments on the starting
# line.
while True:
cp = l.checkpoint()
if l.match(':'):
# If line_only, we stop before the colon.
if line_only:
l.revert(cp)
block = False
else:
l.expect_eol()
l.expect_block(self.name)
block = True
@@ -700,6 +740,24 @@ class DisplayableParser(Parser):
return rv
class AddImageParser(Parser):
def __init__(self, name):
super().__init__(name)
self.variable = True
def parse(self, loc, l, parent, keyword):
rv = slast.SLAddImage(loc, self.name)
self.parse_contents(l, rv, line_only=True)
l.require(':')
l.expect_eol()
l.expect_block("ATL block")
rv.atl_transform = renpy.atl.parse_atl(l.subblock_lexer()) # type: ignore
return rv
AddImageParser("add image")
class IfParser(Parser):
def __init__(self, name, node_type, parent_contents):