Update utils/block_relation_builder.py
Browse files- utils/block_relation_builder.py +73 -42
utils/block_relation_builder.py
CHANGED
|
@@ -2300,9 +2300,12 @@ def generate_plan(generated_input, opcode_keys, pseudo_code):
|
|
| 2300 |
menu_block_id = _register_block("control_create_clone_of_menu", key, True, pick_key, all_generated_blocks, fields={"CLONE_OPTION": [option_val, None]})
|
| 2301 |
info["inputs"]["CLONE_OPTION"] = {"kind": "block", "block": menu_block_id}
|
| 2302 |
elif opcode in ["sound_playuntildone", "sound_play"]:
|
| 2303 |
-
m = re.search(r"(?:play sound|start sound)\s*\[([^\]]+)\s*v\]", stmt_for_parse, re.IGNORECASE)
|
|
|
|
| 2304 |
if m:
|
| 2305 |
-
option = m.group(1).strip()
|
|
|
|
|
|
|
| 2306 |
menu_block_id = _register_block("sound_sounds_menu", key, True, pick_key, all_generated_blocks, fields={"SOUND_MENU": [option, None]})
|
| 2307 |
info["inputs"]["SOUND_MENU"] = {"kind": "block", "block": menu_block_id}
|
| 2308 |
elif opcode == "looks_switchcostumeto":
|
|
@@ -3147,8 +3150,10 @@ def _find_all_opcodes(code_block: str) -> list[str]:
|
|
| 3147 |
(r"\(?username\)?", "sensing_username"), #(to test muliple bracket and alone should treet as the keyword)
|
| 3148 |
|
| 3149 |
# --- Sound Blocks ---
|
| 3150 |
-
(r"play sound \[.+? v\] until done", "sound_playuntildone"),
|
| 3151 |
-
(r"start sound \[.+? v\]", "sound_play"),
|
|
|
|
|
|
|
| 3152 |
(r"stop all sounds", "sound_stopallsounds"),
|
| 3153 |
(r"change volume by\s*(?:\((.+?)\)|\[(.+?)\]|(.+))", "sound_changevolumeby"),
|
| 3154 |
(r"""set\ volume\ to\s+\(?\s*(?:-?\d+(?:\.\d+)?|\[?[a-zA-Z_][\w\s]*\]?(?:\ v)?)\s*\)?\s*%?""", "sound_setvolumeto"),
|
|
@@ -3252,49 +3257,75 @@ def analyze_opcode_counts(pseudo_code: str) -> list[dict]:
|
|
| 3252 |
#--------------------------------------------------[Helper function to seperate an correct the json]-------------------------------------------------------------
|
| 3253 |
#################################################################################################################################################################
|
| 3254 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3255 |
def separate_scripts(pseudocode_string):
|
| 3256 |
"""
|
| 3257 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3258 |
|
| 3259 |
-
|
| 3260 |
-
|
| 3261 |
-
providing a more robust and reliable separation.
|
| 3262 |
|
| 3263 |
-
|
| 3264 |
-
|
|
|
|
|
|
|
|
|
|
| 3265 |
|
| 3266 |
-
Returns:
|
| 3267 |
-
list: A list of strings, where each string is a complete,
|
| 3268 |
-
separated script.
|
| 3269 |
-
"""
|
| 3270 |
-
# Define the "hat" block patterns with more robust regex.
|
| 3271 |
-
# We use a non-capturing group (?:...) for the patterns.
|
| 3272 |
-
# We use a logical OR (|) to combine them into a single pattern.
|
| 3273 |
-
delimiter_patterns = (
|
| 3274 |
-
r"when green flag clicked|when flag clicked|when \S+ key pressed|"
|
| 3275 |
-
r"when this sprite clicked|when backdrop switches to \[.*?\]|"
|
| 3276 |
-
r"when I receive \[.*?\]|when \[.*?\] > \[.*?\]"
|
| 3277 |
-
)
|
| 3278 |
-
|
| 3279 |
-
# Use re.finditer to get an iterator of all hat block matches.
|
| 3280 |
-
# The `re.DOTALL` flag allows the '.' to match newlines.
|
| 3281 |
-
matches = list(re.finditer(delimiter_patterns, pseudocode_string, flags=re.DOTALL | re.IGNORECASE))
|
| 3282 |
-
|
| 3283 |
-
scripts = []
|
| 3284 |
-
# If no matches are found, return an empty list.
|
| 3285 |
-
if not matches:
|
| 3286 |
-
return []
|
| 3287 |
-
|
| 3288 |
-
# Iterate through the matches to slice the original string.
|
| 3289 |
-
for i in range(len(matches)):
|
| 3290 |
-
start = matches[i].start()
|
| 3291 |
-
end = matches[i+1].start() if i + 1 < len(matches) else len(pseudocode_string)
|
| 3292 |
-
|
| 3293 |
-
# Slice the pseudocode string from the start of one match to the start
|
| 3294 |
-
# of the next, or to the end of the string.
|
| 3295 |
-
script = pseudocode_string[start:end]
|
| 3296 |
-
scripts.append(script.strip())
|
| 3297 |
-
|
| 3298 |
return scripts
|
| 3299 |
|
| 3300 |
def transform_logic_to_action_flow(source_data, description=""):
|
|
|
|
| 2300 |
menu_block_id = _register_block("control_create_clone_of_menu", key, True, pick_key, all_generated_blocks, fields={"CLONE_OPTION": [option_val, None]})
|
| 2301 |
info["inputs"]["CLONE_OPTION"] = {"kind": "block", "block": menu_block_id}
|
| 2302 |
elif opcode in ["sound_playuntildone", "sound_play"]:
|
| 2303 |
+
# m = re.search(r"(?:play sound|start sound)\s*\[([^\]]+)\s*v\]", stmt_for_parse, re.IGNORECASE)
|
| 2304 |
+
m = re.search(r"(?:play sound|start sound)\s*(?:\[\s*([^\]]+?)\s*v\]|\(?\s*([^)]+)\s*\)?)",stmt_for_parse,re.IGNORECASE)
|
| 2305 |
if m:
|
| 2306 |
+
# option = m.group(1).strip()
|
| 2307 |
+
option = m.group(1) or m.group(2)
|
| 2308 |
+
print("sounds option content--------->",option)
|
| 2309 |
menu_block_id = _register_block("sound_sounds_menu", key, True, pick_key, all_generated_blocks, fields={"SOUND_MENU": [option, None]})
|
| 2310 |
info["inputs"]["SOUND_MENU"] = {"kind": "block", "block": menu_block_id}
|
| 2311 |
elif opcode == "looks_switchcostumeto":
|
|
|
|
| 3150 |
(r"\(?username\)?", "sensing_username"), #(to test muliple bracket and alone should treet as the keyword)
|
| 3151 |
|
| 3152 |
# --- Sound Blocks ---
|
| 3153 |
+
# (r"play sound \[.+? v\] until done", "sound_playuntildone"),
|
| 3154 |
+
# (r"start sound \[.+? v\]", "sound_play"),
|
| 3155 |
+
(r"play sound\s+(?:\[\s*.+?\s*v\]|\(?\s*.+?\s*\)?)\s+until done", "sound_playuntildone"),
|
| 3156 |
+
(r"start sound\s+(?:\[\s*.+?\s*v\]|\(?\s*.+?\s*\)?)", "sound_play"),
|
| 3157 |
(r"stop all sounds", "sound_stopallsounds"),
|
| 3158 |
(r"change volume by\s*(?:\((.+?)\)|\[(.+?)\]|(.+))", "sound_changevolumeby"),
|
| 3159 |
(r"""set\ volume\ to\s+\(?\s*(?:-?\d+(?:\.\d+)?|\[?[a-zA-Z_][\w\s]*\]?(?:\ v)?)\s*\)?\s*%?""", "sound_setvolumeto"),
|
|
|
|
| 3257 |
#--------------------------------------------------[Helper function to seperate an correct the json]-------------------------------------------------------------
|
| 3258 |
#################################################################################################################################################################
|
| 3259 |
|
| 3260 |
+
# def separate_scripts(pseudocode_string):
|
| 3261 |
+
# """
|
| 3262 |
+
# Separates a block of Scratch pseudocode into a list of individual scripts.
|
| 3263 |
+
|
| 3264 |
+
# This function finds the start of each "hat" block and slices the
|
| 3265 |
+
# original string to capture the full code block for each script,
|
| 3266 |
+
# providing a more robust and reliable separation.
|
| 3267 |
+
|
| 3268 |
+
# Args:
|
| 3269 |
+
# pseudocode_string (str): A string containing Scratch pseudocode.
|
| 3270 |
+
|
| 3271 |
+
# Returns:
|
| 3272 |
+
# list: A list of strings, where each string is a complete,
|
| 3273 |
+
# separated script.
|
| 3274 |
+
# """
|
| 3275 |
+
# # Define the "hat" block patterns with more robust regex.
|
| 3276 |
+
# # We use a non-capturing group (?:...) for the patterns.
|
| 3277 |
+
# # We use a logical OR (|) to combine them into a single pattern.
|
| 3278 |
+
# delimiter_patterns = (
|
| 3279 |
+
# r"when green flag clicked|when flag clicked|when \S+ key pressed|"
|
| 3280 |
+
# r"when this sprite clicked|when backdrop switches to \[.*?\]|"
|
| 3281 |
+
# r"when I receive \[.*?\]|when \[.*?\] > \[.*?\]"
|
| 3282 |
+
# )
|
| 3283 |
+
|
| 3284 |
+
# # Use re.finditer to get an iterator of all hat block matches.
|
| 3285 |
+
# # The `re.DOTALL` flag allows the '.' to match newlines.
|
| 3286 |
+
# matches = list(re.finditer(delimiter_patterns, pseudocode_string, flags=re.DOTALL | re.IGNORECASE))
|
| 3287 |
+
|
| 3288 |
+
# scripts = []
|
| 3289 |
+
# # If no matches are found, return an empty list.
|
| 3290 |
+
# if not matches:
|
| 3291 |
+
# return []
|
| 3292 |
+
|
| 3293 |
+
# # Iterate through the matches to slice the original string.
|
| 3294 |
+
# for i in range(len(matches)):
|
| 3295 |
+
# start = matches[i].start()
|
| 3296 |
+
# end = matches[i+1].start() if i + 1 < len(matches) else len(pseudocode_string)
|
| 3297 |
+
|
| 3298 |
+
# # Slice the pseudocode string from the start of one match to the start
|
| 3299 |
+
# # of the next, or to the end of the string.
|
| 3300 |
+
# script = pseudocode_string[start:end]
|
| 3301 |
+
# scripts.append(script.strip())
|
| 3302 |
+
|
| 3303 |
+
# return scripts
|
| 3304 |
def separate_scripts(pseudocode_string):
|
| 3305 |
"""
|
| 3306 |
+
Split a block of Scratch pseudocode into individual scripts.
|
| 3307 |
+
Each script starts at a 'when ...' hat block that appears at the start
|
| 3308 |
+
of a line (leading whitespace allowed).
|
| 3309 |
+
"""
|
| 3310 |
+
# Robust, non-capturing hat-block patterns (no capturing groups!)
|
| 3311 |
+
patterns = [
|
| 3312 |
+
r"when\s+(?:green\s+flag\s+)?click(?:ed)?\b", # when flag clicked / when green flag clicked
|
| 3313 |
+
r"when\s+(?:\S+(?:\s+\S+)*)\s+key\s+press(?:ed)?\b", # when space key pressed / when up arrow key press
|
| 3314 |
+
r"when\s+this\s+sprite\s+click(?:ed)?\b", # when this sprite clicked
|
| 3315 |
+
r"when\s+backdrop\s+switch(?:es|ed)?\s+to\s*\[[^\]]*\]", # when backdrop switches to [..]
|
| 3316 |
+
r"when\s+I\s+receive(?:d)?\s*\[[^\]]*\]", # when I receive [..] / when I received [..]
|
| 3317 |
+
r"when\s*\[[^\]]*\]\s*>\s*\[[^\]]*\]" # when [sensor] > [value]
|
| 3318 |
+
]
|
| 3319 |
|
| 3320 |
+
# Build a lookahead that finds positions just before a hat block at line-start
|
| 3321 |
+
lookahead = r"(?=^\s*(?:{}))".format("|".join(patterns))
|
|
|
|
| 3322 |
|
| 3323 |
+
# Use MULTILINE so ^ matches start of lines, DOTALL to allow patterns that may include brackets/newlines as needed
|
| 3324 |
+
parts = re.split(lookahead, pseudocode_string, flags=re.IGNORECASE | re.MULTILINE | re.DOTALL)
|
| 3325 |
+
|
| 3326 |
+
# Filter out empties and strip leading/trailing whitespace/newlines
|
| 3327 |
+
scripts = [p.strip() for p in parts if p and p.strip()]
|
| 3328 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3329 |
return scripts
|
| 3330 |
|
| 3331 |
def transform_logic_to_action_flow(source_data, description=""):
|