{ "cells": [ { "cell_type": "code", "execution_count": 3, "id": "9adfcb20", "metadata": {}, "outputs": [], "source": [ "import re" ] }, { "cell_type": "code", "execution_count": 4, "id": "de910107", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'if > then'" ] }, "execution_count": 4, "metadata": {}, "output_type": "execute_result" } ], "source": [ "stmt=\"if > then\"\n", "s = stmt.lower().strip()\n", "# 1) strip ALL balanced <…>\n", "while s.startswith(\"<\") and s.endswith(\">\"):\n", " s = s[1:-1].strip()\n", "# 2) strip stray unmatched < or >\n", "while s.startswith(\"<\") and not s.endswith(\">\"):\n", " s = s[1:].strip()\n", "while s.endswith(\">\") and not s.startswith(\"<\"):\n", " s = s[:-1].strip()\n", " \n", "s" ] }, { "cell_type": "code", "execution_count": 20, "id": "af367513", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "None\n", "the stmt was this if < and > then and parsed was this if < and > then\n" ] }, { "ename": "SyntaxError", "evalue": "'return' outside function (234319892.py, line 51)", "output_type": "error", "traceback": [ " \u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[20]\u001b[39m\u001b[32m, line 51\u001b[39m\n\u001b[31m \u001b[39m\u001b[31mreturn {\"kind\": \"block\", \"block\": block_id}\u001b[39m\n ^\n\u001b[31mSyntaxError\u001b[39m\u001b[31m:\u001b[39m 'return' outside function\n" ] } ], "source": [ "import re\n", "\n", "s = \"if > then\"\n", "\n", "m_touch = re.fullmatch(r\"touching\\s*\\[\\s*([^\\]]+)\\s*v\\]\\??\", s, re.IGNORECASE)\n", "print(m_touch)\n", "if m_touch:\n", " sprite = m_touch.group(1).strip()\n", " val = {'mouse-pointer':'_mouse_', 'edge':'_edge_'}.get(sprite, sprite)\n", " mid = _register_block(\n", " \"sensing_touchingobjectmenu\", parent_key, True, pick_key_func, all_generated_blocks,\n", " fields={\"TOUCHINGOBJECTMENU\":[val, None]}\n", " )\n", " bid = _register_block(\n", " \"sensing_touchingobject\", parent_key, False, pick_key_func, all_generated_blocks,\n", " inputs={\"TOUCHINGOBJECTMENU\":[1, mid]}\n", " )\n", " #all_generated_blocks[mid][\"parent\"] = bid \n", " print(bid)\n", " #return {\"kind\":\"block\",\"block\":bid}\n", "\n", "s = stmt.lower().strip()\n", "#s = strip_outer_angle_brackets(s)\n", "# 1) strip ALL balanced <…>\n", "while s.startswith(\"<\") and s.endswith(\">\"):\n", " s = s[1:-1].strip()\n", "# 2) strip stray unmatched < or >\n", "while s.startswith(\"<\") and not s.endswith(\">\"):\n", " s = s[1:].strip()\n", "while s.endswith(\">\") and not s.startswith(\"<\"):\n", " s = s[:-1].strip()\n", " \n", "print(f\"the stmt was this {stmt} and parsed was this {s}\")\n", "# 1a) Comparisons with explicit angle wrappers: < (...) op (...) >\n", "m = re.fullmatch(\n", " r\"\\s*<\\s*(.+?)\\s*(?P<|=|>)\\s*(.+?)\\s*>\\s*\",\n", " s,\n", " re.VERBOSE\n", ")\n", "if m:\n", " left_txt, right_txt = m.group(1), m.group(3)\n", " operand1_obj = parse_reporter_or_value(unparen(left_txt), None, pick_key_func, all_generated_blocks)\n", " operand2_obj = parse_reporter_or_value(unparen(right_txt), None, pick_key_func, all_generated_blocks)\n", " op_map = {'<': 'operator_lt', '=': 'operator_equals', '>': 'operator_gt'}\n", " \n", " inputs = {\"OPERAND1\": operand1_obj, \"OPERAND2\": operand2_obj}\n", " block_id = _register_block(op_map[m.group('op')], parent_key, False, pick_key_func, all_generated_blocks, inputs=inputs)\n", " # Set parents for nested inputs\n", " if operand1_obj.get(\"kind\") == \"block\": all_generated_blocks[operand1_obj[\"block\"]][\"parent\"] = block_id\n", " if operand2_obj.get(\"kind\") == \"block\": all_generated_blocks[operand2_obj[\"block\"]][\"parent\"] = block_id\n", " return {\"kind\": \"block\", \"block\": block_id}\n", "# 1b) Simple comparisons without angle wrappers: A op B\n", "m_simple = re.fullmatch(r\"\\s*(.+?)\\s*(?P<|=|>)\\s*(.+?)\\s*\", s)\n", "if m_simple:\n", " left_txt, right_txt = m_simple.group(1), m_simple.group(3)\n", " operand1_obj = parse_reporter_or_value(unparen(left_txt), None, pick_key_func, all_generated_blocks)\n", " operand2_obj = parse_reporter_or_value(unparen(right_txt), None, pick_key_func, all_generated_blocks)\n", " op_map = {'<': 'operator_lt', '=': 'operator_equals', '>': 'operator_gt'}\n", " \n", " inputs = {\"OPERAND1\": operand1_obj, \"OPERAND2\": operand2_obj}\n", " block_id = _register_block(op_map[m_simple.group('op')], parent_key, False, pick_key_func, all_generated_blocks, inputs=inputs)\n", " if operand1_obj.get(\"kind\") == \"block\": all_generated_blocks[operand1_obj[\"block\"]][\"parent\"] = block_id\n", " if operand2_obj.get(\"kind\") == \"block\": all_generated_blocks[operand2_obj[\"block\"]][\"parent\"] = block_id\n", " return {\"kind\": \"block\", \"block\": block_id}" ] }, { "cell_type": "code", "execution_count": 23, "id": "3a315968", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[TEST] if then\n", "→ Extracted: 'mouse down?'\n", " Expected: 'mouse down?'\n", " ✅ PASS\n", "\n", "[TEST] if > then\n", "→ Extracted: 'not '\n", " Expected: 'not '\n", " ✅ PASS\n", "\n", "[TEST] if < and > then\n", "→ Extracted: 'mouse down?> and > or > >> then\n", "→ Extracted: 'mouse down?>> or '\n", " ❌ FAIL\n", "\n", "[TEST] if <(x position) < (100)> then\n", "→ Extracted: '<(x position) < (100)> then'\n", " Expected: '(x position) < (100)'\n", " ❌ FAIL\n", "\n" ] } ], "source": [ "def extract_condition_balanced(stmt):\n", " stmt = stmt.strip()\n", " if \"if \" in stmt.lower():\n", " stmt = stmt.lower().split(\"if\", 1)[1].strip()\n", "\n", " # Handle bracket balancing\n", " if stmt.startswith(\"<\"):\n", " count = 0\n", " condition = \"\"\n", " for i, ch in enumerate(stmt):\n", " if ch == \"<\":\n", " count += 1\n", " elif ch == \">\":\n", " count -= 1\n", " condition += ch\n", " if count == 0:\n", " break\n", "\n", " # Strip outer brackets recursively\n", " inner = condition\n", " while inner.startswith(\"<\") and inner.endswith(\">\"):\n", " inner = inner[1:-1].strip()\n", "\n", " return inner\n", " return stmt.strip()\n", "\n", "test_cases = [\n", " (\"if then\", \"mouse down?\"),\n", " (\"if > then\", \"not \"),\n", " (\"if < and > then\", \"mouse down? and touching [edge v]?\"),\n", " (\"if <<> or > >> then\", \"mouse down? or not \"),\n", " (\"if <(x position) < (100)> then\", \"(x position) < (100)\"),\n", "]\n", "\n", "for stmt, expected in test_cases:\n", " result = extract_condition_balanced(stmt)\n", " print(f\"[TEST] {stmt}\\n→ Extracted: '{result}'\\n Expected: '{expected}'\\n {'✅ PASS' if result == expected else '❌ FAIL'}\\n\")\n" ] }, { "cell_type": "code", "execution_count": 38, "id": "34ddb52b", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "--- Testing improved function ---\n", "[TEST] if then\n", "→ Extracted: 'mouse down?'\n", " Expected: 'mouse down?'\n", " ✅ PASS\n", "\n", "[TEST] repeat until \n", "→ Extracted: 'touching [edge v]?'\n", " Expected: 'touching [edge v]?'\n", " ✅ PASS\n", "\n", "[TEST] if then\n", "→ Extracted: 'key [left arrow v] pressed?'\n", " Expected: 'key [left arrow v] pressed?'\n", " ✅ PASS\n", "\n", "[TEST] if then\n", "→ Extracted: 'touching [edge v]?'\n", " Expected: 'touching [edge v]?'\n", " ✅ PASS\n", "\n", "[TEST] if < and > then\n", "→ Extracted: ' and '\n", " Expected: 'mouse down? and touching [edge v]?'\n", " ❌ FAIL\n", "\n", "[TEST] if <(x position) < (100)> then\n", "→ Extracted: '(x position) < (100)'\n", " Expected: '(x position) < (100)'\n", " ✅ PASS\n", "\n", "[TEST] if <> then\n", "→ Extracted: ''\n", " Expected: 'mouse down?'\n", " ❌ FAIL\n", "\n", "[TEST] if > then\n", "→ Extracted: 'not<>'\n", " Expected: 'not<>'\n", " ✅ PASS\n", "\n", "[TEST] if <<> or <>> then\n", "→ Extracted: '<> or <>'\n", " Expected: '<> or <>'\n", " ✅ PASS\n", "\n", "[TEST] if <> then\n", "→ Extracted: ''\n", " Expected: ''\n", " ✅ PASS\n", "\n", "[TEST] if mouse down? then\n", "→ Extracted: 'mouse down?'\n", " Expected: 'mouse down?'\n", " ✅ PASS\n", "\n", "[TEST] \n", "→ Extracted: 'mouse down?'\n", " Expected: 'mouse down?'\n", " ✅ PASS\n", "\n" ] } ], "source": [ "import re\n", "\n", "def extract_condition_balanced(stmt):\n", " # 1. Remove \"if\" and \"then\"\n", " stmt = stmt.strip()\n", " if stmt.lower().startswith(\"if \"):\n", " stmt = stmt[3:].strip()\n", " if stmt.lower().startswith(\"repeat until\"):\n", " stmt = stmt[12:].strip()\n", " if stmt.lower().endswith(\" then\"):\n", " stmt = stmt[:-5].strip()\n", "\n", " # Helper to detect and strip single outer balanced angle brackets\n", " def unwrap_balanced(s):\n", " if s.startswith(\"<\") and s.endswith(\">\"):\n", " depth = 0\n", " for i in range(len(s)):\n", " if s[i] == \"<\":\n", " depth += 1\n", " elif s[i] == \">\":\n", " depth -= 1\n", " if depth == 0 and i < len(s) - 1:\n", " return s # Early balance → not a single outer wrapper\n", " if depth == 0:\n", " return s[1:-1].strip()\n", " return s\n", "\n", " # Recursively simplify things like > to not \n", " def simplify(s):\n", " s = unwrap_balanced(s)\n", " s = s.strip()\n", "\n", " # Match > pattern\n", " m = re.fullmatch(r\"not\\s*<(.+)>\", s, re.IGNORECASE)\n", " if m:\n", " inner = m.group(1).strip()\n", " inner = simplify(inner)\n", " return f\"not <{inner}>\"\n", "\n", " # Match comparison operators like <(x position) < (100)>\n", " m_comp = re.fullmatch(r\"<\\s*\\(([^<>]+?)\\)\\s*([<>=])\\s*\\(([^<>]+?)\\)\\s*>\", stmt)\n", " if m_comp:\n", " return f\"({m_comp.group(1).strip()}) {m_comp.group(2)} ({m_comp.group(3).strip()})\"\n", "\n", " return s\n", "\n", " return simplify(stmt)\n", "\n", "# Test cases\n", "# test_cases = [\n", "# (\"if then\", \"mouse down?\"),\n", "# (\"if > then\", \"not \"),\n", "# (\"if < and > then\", \" and \"),\n", "# (\"if < or >> then\", \" or >\"),\n", "# (\"if <(x position) < (100)> then\", \"(x position) < (100)\"),\n", "# ]\n", "test_cases = [\n", " (\"if then\", \"mouse down?\"),\n", " (\"repeat until \", \"touching [edge v]?\"),\n", " (\"if then\", \"key [left arrow v] pressed?\"),\n", " (\"if then\", \"touching [edge v]?\"),\n", " (\"if < and > then\", \"mouse down? and touching [edge v]?\"),\n", " (\"if <(x position) < (100)> then\", \"(x position) < (100)\"),\n", " (\"if <> then\", \"mouse down?\"),\n", " (\"if > then\", \"not<>\"),\n", " (\"if <<> or <>> then\", \"<> or <>\"),\n", " (\"if <> then\", \"\"),\n", " (\"if mouse down? then\", \"mouse down?\"),\n", " (\"\", \"mouse down?\"),\n", "]\n", "\n", "print(\"--- Testing improved function ---\")\n", "for stmt, expected in test_cases:\n", " result = extract_condition_balanced(stmt)\n", " print(f\"[TEST] {stmt}\\n→ Extracted: '{result}'\\n Expected: '{expected}'\\n {'✅ PASS' if result == expected else '❌ FAIL'}\\n\")\n" ] }, { "cell_type": "code", "execution_count": 40, "id": "1ee313ee", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "when I receive [Game Over v]\n", " if <(score) > (High Score)> then\n", " set [High Score v] to (score)\n", " end\n", " switch backdrop to [HighScore v]\n", "end\n" ] } ], "source": [ "txt = \"when I receive [Game Over v]\\n if <(score) > (High Score)> then\\n set [High Score v] to (score)\\n end\\n switch backdrop to [HighScore v]\\nend\"\n", "print(str(txt)) " ] }, { "cell_type": "code", "execution_count": null, "id": "4700799d", "metadata": {}, "outputs": [], "source": [] } ], "metadata": { "kernelspec": { "display_name": "scratch_env", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.12.11" } }, "nbformat": 4, "nbformat_minor": 5 }