Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion scratchattach/editor/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
from .asset import Asset, Costume, Sound
from .project import Project
from .extension import Extensions, Extension
from .mutation import Mutation, Argument, parse_proc_code
from .mutation import Mutation, Argument, ArgumentType, parse_proc_code, construct_proccode, ArgTypes
from .meta import Meta, set_meta_platform
from .sprite import Sprite
from .block import Block
Expand Down
4 changes: 1 addition & 3 deletions scratchattach/editor/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -92,9 +92,7 @@ class SpriteSubComponent(JSONSerializable, ABC):
sprite: module_sprite.Sprite
def __init__(self, _sprite: "commons.SpriteInput" = build_defaulting.SPRITE_DEFAULT):
if _sprite is build_defaulting.SPRITE_DEFAULT:
retrieved_sprite = build_defaulting.current_sprite()
assert retrieved_sprite is not None, "You don't have any sprites."
_sprite = retrieved_sprite
_sprite = build_defaulting.current_sprite()
self.sprite = _sprite

@property
Expand Down
2 changes: 1 addition & 1 deletion scratchattach/editor/build_defaulting.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ def add_block(_block: block.Block | prim.Prim) -> block.Block | prim.Prim:
return current_sprite().add_block(_block)


def add_chain(*chain: Iterable[block.Block, prim.Prim]) -> block.Block | prim.Prim:
def add_chain(*chain: Iterable[block.Block | prim.Prim]) -> block.Block | prim.Prim:
return current_sprite().add_chain(*chain)


Expand Down
70 changes: 60 additions & 10 deletions scratchattach/editor/mutation.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ class ArgumentType(base.Base):
proc_str: str

def __eq__(self, other):
# noinspection PyProtectedMember
if isinstance(other, enums._EnumWrapper):
other = other.value

Expand Down Expand Up @@ -65,25 +66,37 @@ def __lt__(self, other):
class Argument(base.MutationSubComponent):
name: str
default: str = ''
_type: Optional[ArgumentType] = None

_id: str = None
"""
Argument ID: Will be used to replace other parameters during block instantiation.
"""

def __post_init__(self):
super().__init__()

@property
def index(self):
return self.mutation.arguments.index(self)

@property
def type(self) -> None | ArgumentType:
i = 0
goal = self.index
for token in parse_proc_code(self.mutation.proc_code):
if isinstance(token, ArgumentType):
if i == goal:
return token
i += 1
def type(self) -> Optional[ArgumentType]:
if not self._type:
if not self.mutation:
raise ValueError(f"Cannot infer 'type' of {self} when there is no mutation attached. "
f"Consider providing a type manually.")

i = 0
goal = self.index
for token in parse_proc_code(self.mutation.proc_code):
if isinstance(token, ArgumentType):
if i == goal:
self._type = token
break
i += 1

return self._type

@staticmethod
def from_json(data: dict | list | Any):
Expand All @@ -97,12 +110,13 @@ def link_using_mutation(self):
self._id = self.block.new_id


# noinspection PyProtectedMember
class ArgTypes(enums._EnumWrapper):
BOOLEAN = ArgumentType("boolean", "%b")
NUMBER_OR_TEXT = ArgumentType("number or text", "%s")


def parse_proc_code(_proc_code: str) -> list[str, ArgumentType] | None:
def parse_proc_code(_proc_code: str) -> Optional[list[str | ArgumentType]]:
"""
Parse a proccode (part of a mutation) into argument types and strings
"""
Expand All @@ -120,6 +134,10 @@ def parse_proc_code(_proc_code: str) -> list[str, ArgumentType] | None:
token = token[:-1]
# Clip the % sign off the token

if token.endswith(' '):
# A space is required before params, but this should not be part of the parsed output
token = token[:-1]

if token != '':
# Make sure not to append an empty token
tokens.append(token)
Expand All @@ -142,6 +160,37 @@ def parse_proc_code(_proc_code: str) -> list[str, ArgumentType] | None:

return tokens

def construct_proccode(*components: ArgumentType | ArgTypes | Argument | str) -> str:
"""
Create a proccode from strings/ArgumentType enum members/Argument instances

:param components: list of strings/Arguments/ArgumentType instances
:return: A proccode, e.g. 'move %s steps' or 'say %s for %n seconds'
"""

result = ""

for comp in components:
if isinstance(comp, ArgumentType):
result += comp.proc_str

elif isinstance(comp, ArgTypes):
new: ArgumentType = comp.value
result += new.proc_str

elif isinstance(comp, Argument):
result += comp.type.proc_str

elif isinstance(comp, str):
result += comp

else:
raise TypeError(f"Unsupported component type: {type(comp)}")

result += ' '

return result


class Mutation(base.BlockSubComponent):
def __init__(self, _tag_name: str = "mutation", _children: Optional[list] = None, _proc_code: Optional[str] = None,
Expand Down Expand Up @@ -272,7 +321,7 @@ def get(_lst: list | tuple | None, _idx: int):
_arg_name = get(_argument_names, i)
_arg_default = get(_argument_defaults, i)

_arguments.append(Argument(_arg_name, _arg_default, _arg_id))
_arguments.append(Argument(_arg_name, _arg_default, _id=_arg_id))

return Mutation(_tag_name, _children, _proc_code, _is_warp, _arguments, _has_next, _argument_settings)

Expand Down Expand Up @@ -322,3 +371,4 @@ def link_arguments(self):
for _argument in self.arguments:
_argument.mutation = self
_argument.link_using_mutation()