From a5fa96ecf4b34a19e60d121a47e0c6cf9a894741 Mon Sep 17 00:00:00 2001 From: Boryana Goncharenko <3010723+boryanagoncharenko@users.noreply.github.com> Date: Tue, 12 Nov 2024 14:06:09 +0200 Subject: [PATCH] Allow if_pressed to work with functions #5749 --- hedy.py | 199 +++++++++++++++++----------- tests/Tester.py | 20 +-- tests/test_level/test_level_05.py | 58 ++++---- tests/test_level/test_level_06.py | 35 +++-- tests/test_level/test_level_07.py | 23 ++-- tests/test_level/test_level_08.py | 138 +++++++++---------- tests/test_level/test_level_09.py | 21 +-- tests/test_level/test_level_10.py | 50 +++++-- tests/test_level/test_level_11.py | 33 ++++- tests/test_level/test_level_12.py | 211 ++++++++++++++++++++++++------ tests/test_level/test_level_15.py | 39 +++--- tests/test_level/test_level_16.py | 12 +- tests/test_level/test_level_17.py | 32 ++--- 13 files changed, 558 insertions(+), 313 deletions(-) diff --git a/hedy.py b/hedy.py index 2301ff97edb..5607bf32a6e 100644 --- a/hedy.py +++ b/hedy.py @@ -550,23 +550,23 @@ def get_only_vars(self): """Returns entries which do not represent list access or function definitions""" return [e for e in self.__entries if e.is_var()] + def try_get_local_scope(self, line): + for (n, s, e) in self.__local_scopes: + if s <= line <= e: + return n, s, e + return None + def get_all_in_scope(self, access_line): """Returns the lookup entries for the scope of the given access line.""" - def get_matching_local_scope(line): - for (s, e) in self.__local_scopes: - if s <= line <= e: - return s, e - return None - def in_global_scope(line): - return not [s for (s, e) in self.__local_scopes if s <= line <= e] + return not [s for (_, s, e) in self.__local_scopes if s <= line <= e] def is_func_definition(entry): - return entry.is_func() and entry.definition_line in [s for (s, _) in self.__local_scopes] + return entry.is_func() and entry.definition_line in [s for (_, s, _) in self.__local_scopes] - local_scope = get_matching_local_scope(access_line) + local_scope = self.try_get_local_scope(access_line) if local_scope: - start, end = local_scope + _, start, end = local_scope # if the variable is in local scope, return the whole local scope combined # with the part of the global scope defined before the local scope loc = [e for e in self.__entries if start <= e.definition_line <= end] @@ -757,7 +757,7 @@ def add_to_lookup(self, name, tree, definition_line, skip_hashing=False): self.lookup_entries.append(entry) def add_local_scope(self, scope_name, start_line, end_line): - self.local_scopes.append((start_line, end_line)) + self.local_scopes.append((scope_name, start_line, end_line)) # The transformer traverses the whole AST and infers the type of each node. It alters the lookup table entries with @@ -1619,11 +1619,12 @@ def decorator(c): @v_args(meta=True) class ConvertToPython(Transformer): - def __init__(self, lookup, language="en", is_debug=False): + def __init__(self, lookup, language="en", is_debug=False, has_pressed=False): super().__init__() self.lookup = lookup self.language = language self.is_debug = is_debug + self.has_pressed = has_pressed def add_debug_breakpoint(self): if self.is_debug: @@ -1717,6 +1718,27 @@ def merge_localization_info(self, args): bool_sys = next((a.bool_sys for a in args if isinstance(a, BaseValue) and a.bool_sys is not None), None) return num_sys, bool_sys + def scoped_var_access_for_fstring(self, name, line): + arg = self.scoped_var_access(name, line) + return f"{{{arg}}}" + + def scoped_var_access(self, name, line): + if self.has_pressed: + loc_scope = self.lookup.try_get_local_scope(line) + if loc_scope: + ls_name = f'local_scope_{loc_scope[0]}_' + return f'{ls_name}.get("{name}") or global_scope_.get("{name}") or {name}' + else: + return f'global_scope_.get("{name}") or {name}' + return f"{name}" + + def scoped_var_assign(self, name, line): + if self.has_pressed: + loc_scope = self.lookup.try_get_local_scope(line) + scope_name = f'local_scope_{loc_scope[0]}_' if loc_scope else 'global_scope_' + return f'{scope_name}["{name}"]' + return f"{name}" + def get_localization_info_from_arg(self, arg, access_line): if self.is_variable(arg, access_line): return f'get_num_sys({escape_var(arg)})' @@ -1725,9 +1747,10 @@ def get_localization_info_from_arg(self, arg, access_line): else: return f'get_num_sys({arg})' - def process_arg_for_data_access(self, arg, access_line=100, use_var_value=True): + def process_arg_for_data_access(self, arg, access_line=100, use_var_value=True, use_scope=True): if self.is_variable(arg, access_line): - return escape_var(arg) + a = escape_var(arg) + return self.scoped_var_access(a, access_line) if use_scope else a if is_quoted(arg): arg = arg[1:-1] return f"'{process_characters_needing_escape(arg)}'" @@ -1811,12 +1834,15 @@ def unpack_if_literal(arg): @source_map_transformer(source_map) class ConvertToPython_1(ConvertToPython): - def __init__(self, lookup, language, is_debug): - super().__init__(lookup, language, is_debug) + def __init__(self, lookup, language, is_debug, has_pressed): + super().__init__(lookup, language, is_debug, has_pressed) __class__.level = 1 def program(self, meta, args): - return '\n'.join([str(c) for c in args]) + lines = [str(a) for a in args] + if self.has_pressed: + lines.insert(0, "global_scope_ = dict()") + return '\n'.join(lines) def command(self, meta, args): return args[0] @@ -2071,7 +2097,7 @@ def play(self, meta, args): time.sleep(0.5)""") + self.add_debug_breakpoint() def assign(self, meta, args): - var_name = args[0] + var_name = self.scoped_var_assign(args[0], meta.line) value = self.unpack(args[1]) exception = self.make_index_error_check_if_list([value]) @@ -2160,7 +2186,7 @@ def process_arg_for_fstring(self, name, access_line=100, var_to_escape=''): name = escape_var(self.unpack(name)) if self.is_variable(name, access_line): - return f"{{{name}}}" + return self.scoped_var_access_for_fstring(name, access_line) if is_quoted(name): name = name[1:-1] @@ -2232,7 +2258,7 @@ def condition(self, meta, args): def condition_spaces(self, meta, args): arg0 = self.process_arg_for_data_access(self.unpack(args[0]), meta.line) - arg1 = self.process_arg_for_data_access(' '.join([self.unpack(a) for a in args[1:]])) + arg1 = self.process_arg_for_data_access(' '.join([self.unpack(a) for a in args[1:]]), meta.line) return f"localize({arg0}) == localize({arg1})" def equality_check(self, meta, args): @@ -2256,8 +2282,11 @@ def not_in_list_check(self, meta, args): # So, to check if a number is not in a list of numbers with diff numeral system, we use localize() return f"localize({arg0}) not in [localize(__la) for __la in {arg1}]" - def make_function_name(self, key_name): - return f"if_pressed_{key_name}_" + def make_function_name(self, key_name, line): + loc_scope = self.lookup.try_get_local_scope(line) + if loc_scope: + return f'if_pressed_{loc_scope[0]}_{key_name}_' + return f'if_pressed_{key_name}_' def make_function(self, function_name, body): return ( @@ -2269,7 +2298,7 @@ def clear_key_mapping(self): return 'if_pressed_mapping = {"else": "if_pressed_default_else"}' def add_if_key_mapping(self, key, function_name): - return f"if_pressed_mapping['{key}'] = '{function_name}'" + return f"if_pressed_mapping[{key}] = '{function_name}'" def add_else_key_mapping(self, function_name): return f"if_pressed_mapping['else'] = '{function_name}'" @@ -2283,14 +2312,13 @@ def if_pressed_without_else(self, meta, args): ) def if_pressed_else(self, meta, args): - self.process_arg_for_data_access(args[0], meta.line) - key = args[0] + key = self.process_arg_for_data_access(args[0], meta.line) if_code = self.if_pressed_code_prepend_global_vars(args[1]) - if_function_name = self.make_function_name(key) + if_function_name = self.make_function_name(args[0], meta.line) else_code = self.if_pressed_code_prepend_global_vars(args[2]) - else_function_name = self.make_function_name('else') + else_function_name = self.make_function_name('else', meta.line) return ( self.clear_key_mapping() + '\n' + @@ -2311,11 +2339,11 @@ def if_pressed(): points = points + 1 """ lines = lines if isinstance(lines, list) else [lines] - variables = [e.name for e in self.lookup.get_only_vars()] - if variables and lines: - variables = sorted(list(set(variables))) - global_vars = f"global {', '.join(variables)}" - lines.insert(0, global_vars) + # variables = [e.name for e in self.lookup.get_only_vars()] + # if variables and lines: + # variables = sorted(list(set(variables))) + # global_vars = f"global {', '.join(variables)}" + # lines.insert(0, global_vars) return '\n'.join(lines) @@ -2396,7 +2424,7 @@ def play(self, meta, args): def process_arg_for_fstring(self, name, access_line=100, var_to_escape=''): if self.is_variable(name, access_line) or self.is_list(name) or self.is_random(name): - return f"{{{escape_var(self.unpack(name))}}}" + return self.scoped_var_access_for_fstring(escape_var(self.unpack(name)), access_line) elif isinstance(name, LiteralValue): return self.process_literal_for_fstring(name) elif isinstance(name, ExpressionValue): @@ -2417,12 +2445,14 @@ def equality_check(self, meta, args): # equality, we convert all args to string and to the default numeral system and then compare the result. return f"localize({left_hand_side}) == localize({right_hand_side})" - def process_arg_for_data_access(self, arg, access_line=100, use_var_value=True): + def process_arg_for_data_access(self, arg, access_line=100, use_var_value=True, use_scope=True): if self.is_variable(arg, access_line): # In some cases, we don't need to use the data of a variable, e.g. `for a in animals` data_part = '.data' if use_var_value else '' - var_name = escape_var(self.unpack(arg)) - return f"{var_name}{data_part}" + a = escape_var(self.unpack(arg)) + var_access = self.scoped_var_access(a, access_line) if use_scope else a + var_access = f'({var_access})' if data_part and ' ' in var_access else var_access + return f"{var_access}{data_part}" elif isinstance(arg, LiteralValue): val = arg.data[1:-1] if is_quoted(arg.data) else arg.data # equality does not have an f string and requires quotes to be added manually @@ -2438,32 +2468,35 @@ def process_arg_for_data_access(self, arg, access_line=100, use_var_value=True): def process_arg_for_func(self, arg, access_line): if self.is_variable_with_definition(arg, access_line): - var_name = escape_var(self.unpack(arg)) + var_name = self.scoped_var_access(escape_var(self.unpack(arg)), access_line) + # var_name = escape_var(self.unpack(arg)) return f"{var_name}" return self.process_assign_argument(arg) def assign(self, meta, args): - left_hand_side = args[0] + left_hand_side = self.scoped_var_assign(args[0], meta.line) right_hand_side = args[1] if self.is_variable(right_hand_side, meta.line): var = escape_var(self.unpack(right_hand_side)) + right_hand_side = self.scoped_var_access(var, meta.line) if self.is_list(var) or self.is_random(var): exception = self.make_index_error_check_if_list([var]) - return f"{exception}{left_hand_side} = {var}{self.add_debug_breakpoint()}" + return f"{exception}{left_hand_side} = {right_hand_side}{self.add_debug_breakpoint()}" else: - return f"{left_hand_side} = {var}" + return f"{left_hand_side} = {right_hand_side}" else: value = self.process_assign_argument(right_hand_side, escape_quotes=True) return f"{left_hand_side} = {value}{self.add_debug_breakpoint()}" def assign_list(self, meta, args): - parameter = args[0] + parameter = self.scoped_var_assign(args[0], meta.line) arguments = [self.process_assign_argument(v, escape_quotes=True) for v in args[1:]] return f"{parameter} = Value([{', '.join(arguments)}]){self.add_debug_breakpoint()}" def process_assign_argument(self, arg, escape_quotes=False): + # TODO: why don't we take into account variables here? if isinstance(arg, LiteralValue): return self.process_literal_to_value(arg, escape=escape_quotes) elif isinstance(arg, ExpressionValue): @@ -2632,12 +2665,11 @@ def ifs(self, meta, args): return "if " + args[0] + ":" + self.add_debug_breakpoint() + "\n" + "\n".join(all_lines) def if_pressed(self, meta, args): - self.process_arg_for_data_access(args[0], meta.line) + key = self.process_arg_for_data_access(args[0], meta.line) args = [a for a in args if a != ""] # filter out in|dedent tokens - key = args[0] if_code = self.if_pressed_code_prepend_global_vars(args[1:]) - if_function_name = self.make_function_name(key) + if_function_name = self.make_function_name(args[0], meta.line) return ( self.clear_key_mapping() + '\n' + @@ -2648,7 +2680,7 @@ def if_pressed(self, meta, args): def if_pressed_elses(self, meta, args): args = [a for a in args if a != ""] # filter out in|dedent tokens else_code = self.if_pressed_code_prepend_global_vars(args) - else_function_name = self.make_function_name('else') + else_function_name = self.make_function_name('else', meta.line) return ( self.add_else_key_mapping(else_function_name) + '\n' + @@ -2668,14 +2700,22 @@ def elses(self, meta, args): @source_map_transformer(source_map) class ConvertToPython_10(ConvertToPython_8_9): def for_list(self, meta, args): - times = self.process_arg_for_data_access(args[0], meta.line, use_var_value=False) + times = self.process_arg_for_data_access(args[0], meta.line, use_var_value=False, use_scope=False) list_name = self.process_arg_for_data_access(args[1], meta.line, use_var_value=True) - body = "\n".join([ConvertToPython.indent(x) for x in args[2:]]) + lines = self.prepend_for_variable_to_body(args[2:], times) + body = "\n".join([self.indent(line) for line in lines]) body = add_sleep_to_command(body, True, self.is_debug, location="after") return f"for {times} in {list_name}:{self.add_debug_breakpoint()}\n{body}" + def prepend_for_variable_to_body(self, lines, for_var): + # if self.has_pressed: + # # TODO this should a local scope if the for-list is in a function + # # Also, this leaks a variable from the loop to the outer scope + # lines.insert(0, f'global_scope_["{escape_var(for_var)}"] = {escape_var(for_var)}') + return lines + @v_args(meta=True) @hedy_transpiler(level=11) @@ -2695,7 +2735,8 @@ def for_loop(self, meta, args): range_end = self.process_for_loop_args(args[2], meta) range_part = (f'[Value({range_var}, num_sys={num_sys}) ' f'for {range_var} in range({range_begin}, {range_end} + {step}, {step})]') - body = "\n".join([ConvertToPython.indent(x) for x in args[3:]]) + lines = self.prepend_for_variable_to_body(args[3:], iterator) + body = "\n".join([self.indent(x) for x in lines]) body = add_sleep_to_command(body, indent=True, is_debug=self.is_debug, location="after") # Adding runtime errors, i.e. int_with_error(arg, 'Very long error message'), can bloat the code a lot. # To overcome this, we only add the runtime error the first time the arg is accessed - in the step definition. @@ -2866,7 +2907,7 @@ def make_forward(self, parameter): 'forward', True, HedyType.float) def assign(self, meta, args): - left_hand_side = args[0] + left_hand_side = self.scoped_var_assign(args[0], meta.line) right_hand_side = args[1] self.is_variable_with_definition(right_hand_side, meta.line) @@ -2905,7 +2946,7 @@ def process_print_ask_args(self, args, meta, var_to_escape=''): def process_arg_for_fstring(self, name, access_line=100, var_to_escape=''): if self.is_variable(name, access_line) or self.is_list(name) or self.is_random(name): - return f"{{{escape_var(self.unpack(name))}}}" + return self.scoped_var_access_for_fstring(escape_var(self.unpack(name)), access_line) elif isinstance(name, LiteralValue): return self.process_literal_for_fstring(name) elif isinstance(name, ExpressionValue): @@ -2997,21 +3038,23 @@ def equality_check(self, meta, args): return f"{left_hand_side} == {right_hand_side}" def for_list(self, meta, args): - times = self.process_arg_for_data_access(args[0], meta.line, use_var_value=False) - list_name = escape_var(args[1]) + times = self.process_arg_for_data_access(args[0], meta.line, use_var_value=False, use_scope=False) + list_name = self.process_arg_for_data_access(args[1], meta.line, use_var_value=True) # add the list to the lookup table, this used now too self.try_register_variable_access(list_name, meta.line) - body = "\n".join([ConvertToPython.indent(x) for x in args[2:]]) + lines = self.prepend_for_variable_to_body(args[2:], times) + body = "\n".join([self.indent(x) for x in lines]) body = add_sleep_to_command(body, is_debug=self.is_debug) - return f"for {times} in {list_name}.data:{self.add_debug_breakpoint()}\n{body}" + return f"for {times} in {list_name}:{self.add_debug_breakpoint()}\n{body}" def for_loop(self, meta, args): iterator = escape_var(args[0]) # iterator is always a used variable self.try_register_variable_access(iterator, meta.line) - body = "\n".join([ConvertToPython.indent(x) for x in args[3:]]) + lines = self.prepend_for_variable_to_body(args[3:], iterator) + body = "\n".join([self.indent(x) for x in lines]) body = add_sleep_to_command(body, is_debug=self.is_debug) step_var_name = self.get_fresh_var('__step') @@ -3027,11 +3070,13 @@ def for_loop(self, meta, args): for {iterator} in {range_part}:{self.add_debug_breakpoint()} """) + body - def process_arg_for_data_access(self, arg, access_line=100, use_var_value=True): + def process_arg_for_data_access(self, arg, access_line=100, use_var_value=True, use_scope=True): if self.is_variable(arg, access_line): # In some cases, we don't need to use the data of a variable, e.g. `for a in animals` data_part = '.data' if use_var_value else '' - var_name = escape_var(self.unpack(arg)) + a = escape_var(self.unpack(arg)) + var_name = self.scoped_var_access(a, access_line) if use_scope else a + var_name = f'({var_name})' if data_part and ' ' in var_name else var_name return f"{var_name}{data_part}" elif isinstance(arg, LiteralValue): if is_quoted(arg.data): @@ -3041,7 +3086,7 @@ def process_arg_for_data_access(self, arg, access_line=100, use_var_value=True): return f'{arg}.data' else: # We end up here when if-pressed receives a Token(LETTER_OR_NUMBER, 'x') - return f"{arg}" + return f"'{arg}'" def process_literal_to_value(self, lv, escape=False): """ Transpiles a Literal Value to a Value instance, which exists in prefixes. For example, @@ -3080,7 +3125,13 @@ def define(self, meta, args): args_str = ", ".join(str(x) for x in args[1].children) if has_args else "" body_start = 2 if has_args else 1 - body = "\n".join(ConvertToPython.indent(line) for line in args[body_start:]) + lines = args[body_start:] + if self.has_pressed: + init_value = 'dict()' + if has_args: + init_value = f'''{{{', '.join(f'"{str(x)}": {str(x)}' for x in args[1].children)}}}''' + lines.insert(0, f'local_scope_{function_name}_ = {init_value}') + body = "\n".join(self.indent(line) for line in lines) return f"def {function_name}({args_str}):\n{body}" @@ -3123,15 +3174,12 @@ def returns(self, meta, args): except ValueError: return Value(f'''{args_str}''')""") - def add_if_key_mapping(self, key, function_name): - return textwrap.dedent(f"""\ - global {function_name} - if_pressed_mapping['{key}'] = '{function_name}'""") - - def add_else_key_mapping(self, function_name): - return textwrap.dedent(f"""\ - global {function_name} - if_pressed_mapping['else'] = '{function_name}'""") + def make_function(self, function_name, body): + return ( + f'global {function_name}' + '\n' + + f'def {function_name}():' + '\n' + + ConvertToPython.indent(body) + ) @v_args(meta=True) @@ -3252,12 +3300,11 @@ def elifs(self, meta, args): return "\nelif " + args[0] + ":" + self.add_debug_breakpoint() + "\n" + "\n".join(all_lines) def if_pressed_elifs(self, meta, args): - self.process_arg_for_data_access(args[0], meta.line) args = [a for a in args if a != ""] # filter out in|dedent tokens - key = args[0] + key = self.process_arg_for_data_access(args[0], meta.line) elif_code = self.if_pressed_code_prepend_global_vars(args[1:]) - elif_function_name = self.make_function_name(key) + elif_function_name = self.make_function_name(args[0], meta.line) return ( self.add_if_key_mapping(key, elif_function_name) + '\n' + @@ -4040,10 +4087,10 @@ def create_AST(input_string, level, lang="en"): if not valid_echo(abstract_syntax_tree): raise exceptions.LonelyEchoException() - lookup_table = create_lookup_table(abstract_syntax_tree, level, lang, input_string) commands = AllCommands(level).transform(program_root) # FH, dec 2023. I don't love how AllCommands works on program root and not on AST, # but his will do for now. One day we should really start to clean up our AST! + lookup_table = create_lookup_table(abstract_syntax_tree, level, lang, input_string) return abstract_syntax_tree, lookup_table, commands @@ -4089,16 +4136,16 @@ def transpile_inner(input_string, level, lang="en", populate_source_map=False, i try: abstract_syntax_tree, lookup_table, commands = create_AST(input_string, level, lang) - # grab the right transpiler from the lookup - convertToPython = MICROBIT_TRANSPILER_LOOKUP[level] if microbit else TRANSPILER_LOOKUP[level] - python = convertToPython(lookup_table, lang, is_debug).transform(abstract_syntax_tree) - has_clear = "clear" in commands has_turtle = "forward" in commands or "turn" in commands or "color" in commands has_pressed = "if_pressed" in commands or "if_pressed_else" in commands has_music = "play" in commands has_sleep = "sleep" in commands + # grab the right transpiler from the lookup + convertToPython = MICROBIT_TRANSPILER_LOOKUP[level] if microbit else TRANSPILER_LOOKUP[level] + python = convertToPython(lookup_table, lang, is_debug, has_pressed).transform(abstract_syntax_tree) + roles_of_variables = determine_roles(lookup_table, input_string, level, lang) parse_result = ParseResult(python, source_map, has_turtle, has_pressed, diff --git a/tests/Tester.py b/tests/Tester.py index 0385ee4feb0..981bc7a7dab 100644 --- a/tests/Tester.py +++ b/tests/Tester.py @@ -148,15 +148,15 @@ def setUpClass(cls): os.environ["ENABLE_SKIP_FAULTY"] = 'True' # Always test with skipping faulty enabled def snippet_already_tested_with_current_hedy_version(self, test_hash): - try: - total_hash_incl_the_hedy_language = create_hash(get_hedy_source_hash(), test_hash) - if total_hash_incl_the_hedy_language is None: - return False - filename = get_hash_filename(total_hash_incl_the_hedy_language) - already_successful = os.path.isfile(filename) - return already_successful - except UnicodeEncodeError: # some tests (generated by Hypothesis) can't be hashed - return False + # try: + # total_hash_incl_the_hedy_language = create_hash(get_hedy_source_hash(), test_hash) + # if total_hash_incl_the_hedy_language is None: + # return False + # filename = get_hash_filename(total_hash_incl_the_hedy_language) + # already_successful = os.path.isfile(filename) + # return already_successful + # except UnicodeEncodeError: # some tests (generated by Hypothesis) can't be hashed + return False @staticmethod @contextmanager @@ -528,7 +528,7 @@ def int_transpiled(self, value): def number_transpiled(value): return f'''number_with_error({value}, {HedyTester.value_exception_transpiled()})''' - def for_loop(self, i, begin, end, num_sys="'Latin'"): + def for_loop(self, i, begin, end, num_sys="'Latin'", scope=''): def for_loop_arg(arg): if self.level >= 12: return arg diff --git a/tests/test_level/test_level_05.py b/tests/test_level/test_level_05.py index b8228ee5a7d..e04d2cab50d 100644 --- a/tests/test_level/test_level_05.py +++ b/tests/test_level/test_level_05.py @@ -1115,6 +1115,7 @@ def test_if_pressed_x_is_letter_key(self): if x is pressed print 'it is a letter key' else print 'it is another letter key'""") expected = self.dedent("""\ + global_scope_ = dict() if_pressed_mapping = {"else": "if_pressed_default_else"} if_pressed_mapping['x'] = 'if_pressed_x_' if_pressed_mapping['else'] = 'if_pressed_else_' @@ -1133,18 +1134,17 @@ def test_if_pressed_x_is_var(self): print x""") expected = self.dedent("""\ - x = 'a' + global_scope_ = dict() + global_scope_["x"] = 'a' if_pressed_mapping = {"else": "if_pressed_default_else"} - if_pressed_mapping['x'] = 'if_pressed_x_' + if_pressed_mapping[global_scope_.get("x") or x] = 'if_pressed_x_' if_pressed_mapping['else'] = 'if_pressed_else_' def if_pressed_x_(): - global x print(f'it is a letter key') def if_pressed_else_(): - global x print(f'it is another letter key') extensions.if_pressed(if_pressed_mapping) - print(f'{x}')""") + print(f'{global_scope_.get("x") or x}')""") self.single_level_tester(code=code, expected=expected) @@ -1155,18 +1155,17 @@ def test_if_pressed_x_is_var_and_var_reassignment(self): print x""") expected = self.dedent("""\ - x = 'a' + global_scope_ = dict() + global_scope_["x"] = 'a' if_pressed_mapping = {"else": "if_pressed_default_else"} - if_pressed_mapping['x'] = 'if_pressed_x_' + if_pressed_mapping[global_scope_.get("x") or x] = 'if_pressed_x_' if_pressed_mapping['else'] = 'if_pressed_else_' def if_pressed_x_(): - global x - x = 'great' + global_scope_["x"] = 'great' def if_pressed_else_(): - global x - x = 'not great' + global_scope_["x"] = 'not great' extensions.if_pressed(if_pressed_mapping) - print(f'{x}')""") + print(f'{global_scope_.get("x") or x}')""") self.single_level_tester(code=code, expected=expected) @@ -1177,18 +1176,17 @@ def test_if_pressed_x_is_var_and_new_var_assignment(self): print m""") expected = self.dedent("""\ - x = 'a' + global_scope_ = dict() + global_scope_["x"] = 'a' if_pressed_mapping = {"else": "if_pressed_default_else"} - if_pressed_mapping['x'] = 'if_pressed_x_' + if_pressed_mapping[global_scope_.get("x") or x] = 'if_pressed_x_' if_pressed_mapping['else'] = 'if_pressed_else_' def if_pressed_x_(): - global m, x - m = 'great' + global_scope_["m"] = 'great' def if_pressed_else_(): - global m, x - m = 'not great' + global_scope_["m"] = 'not great' extensions.if_pressed(if_pressed_mapping) - print(f'{m}')""") + print(f'{global_scope_.get("m") or m}')""") self.single_level_tester(code=code, expected=expected) @@ -1198,6 +1196,7 @@ def test_double_if_pressed(self): if y is pressed print 'second key' else print 'something else'""") expected = self.dedent("""\ + global_scope_ = dict() if_pressed_mapping = {"else": "if_pressed_default_else"} if_pressed_mapping['x'] = 'if_pressed_x_' if_pressed_mapping['else'] = 'if_pressed_else_' @@ -1223,6 +1222,7 @@ def test_if_pressed_has_enter_after_pressed(self): print 'it is a letter key' else print 'something else'""") expected = self.dedent("""\ + global_scope_ = dict() if_pressed_mapping = {"else": "if_pressed_default_else"} if_pressed_mapping['x'] = 'if_pressed_x_' if_pressed_mapping['else'] = 'if_pressed_else_' @@ -1239,6 +1239,7 @@ def test_if_pressed_1_is_number_key(self): if 1 is pressed print 'it is a number key' else print 'something else'""") expected = self.dedent("""\ + global_scope_ = dict() if_pressed_mapping = {"else": "if_pressed_default_else"} if_pressed_mapping['1'] = 'if_pressed_1_' if_pressed_mapping['else'] = 'if_pressed_else_' @@ -1255,6 +1256,7 @@ def test_if_pressed_with_trailing_spaces_after_key(self): if x is pressed print 'trailing spaces!' else print 'something else'""") expected = self.dedent("""\ + global_scope_ = dict() if_pressed_mapping = {"else": "if_pressed_default_else"} if_pressed_mapping['x'] = 'if_pressed_x_' if_pressed_mapping['else'] = 'if_pressed_else_' @@ -1272,6 +1274,7 @@ def test_if_pressed_has_enter_before_else(self): else print 'x is not pressed!'""") expected = self.dedent("""\ + global_scope_ = dict() if_pressed_mapping = {"else": "if_pressed_default_else"} if_pressed_mapping['x'] = 'if_pressed_x_' if_pressed_mapping['else'] = 'if_pressed_else_' @@ -1291,6 +1294,7 @@ def test_if_pressed_has_enter_before_both_prints_and_else(self): print 'x is not pressed!'""") expected = self.dedent("""\ + global_scope_ = dict() if_pressed_mapping = {"else": "if_pressed_default_else"} if_pressed_mapping['x'] = 'if_pressed_x_' if_pressed_mapping['else'] = 'if_pressed_else_' @@ -1309,6 +1313,7 @@ def test_if_pressed_has_enter_before_first_print_and_else(self): else print 'x is not pressed!'""") expected = self.dedent("""\ + global_scope_ = dict() if_pressed_mapping = {"else": "if_pressed_default_else"} if_pressed_mapping['x'] = 'if_pressed_x_' if_pressed_mapping['else'] = 'if_pressed_else_' @@ -1327,6 +1332,7 @@ def test_if_pressed_has_enter_before_second_print_and_else(self): print 'x is not pressed!'""") expected = self.dedent("""\ + global_scope_ = dict() if_pressed_mapping = {"else": "if_pressed_default_else"} if_pressed_mapping['x'] = 'if_pressed_x_' if_pressed_mapping['else'] = 'if_pressed_else_' @@ -1345,6 +1351,7 @@ def test_if_pressed_has_enter_before_both_prints(self): else print 'x is not pressed!'""") expected = self.dedent("""\ + global_scope_ = dict() if_pressed_mapping = {"else": "if_pressed_default_else"} if_pressed_mapping['x'] = 'if_pressed_x_' if_pressed_mapping['else'] = 'if_pressed_else_' @@ -1362,6 +1369,7 @@ def test_if_pressed_else_with_turtle(self): expected = self.dedent( f"""\ + global_scope_ = dict() if_pressed_mapping = {{"else": "if_pressed_default_else"}} if_pressed_mapping['x'] = 'if_pressed_x_' if_pressed_mapping['else'] = 'if_pressed_else_' @@ -1385,6 +1393,7 @@ def test_if_pressed_non_latin(self): if й is pressed print 'russian' else print 'something else'""") expected = textwrap.dedent("""\ + global_scope_ = dict() if_pressed_mapping = {"else": "if_pressed_default_else"} if_pressed_mapping['ض'] = 'if_pressed_ض_' if_pressed_mapping['else'] = 'if_pressed_else_' @@ -1461,6 +1470,7 @@ def test_source_map(self): else print 'The prince was eaten by a hippopotamus 😭'""") expected_code = textwrap.dedent("""\ + global_scope_ = dict() print(f'Do you want a good (g) or bad (b) ending?') if_pressed_mapping = {"else": "if_pressed_default_else"} if_pressed_mapping['g'] = 'if_pressed_g_' @@ -1472,11 +1482,11 @@ def if_pressed_else_(): extensions.if_pressed(if_pressed_mapping)""") expected_source_map = { - '1/1-1/50': '1/1-1/52', - '1/1-3/55': '1/1-9/42', - '2/1-3/54': '2/1-9/42', - '2/17-2/56': '6/3-6/44', - '3/6-3/54': '8/3-8/53' + '1/1-1/50': '2/1-2/52', + '1/1-3/55': '1/1-10/42', + '2/1-3/54': '3/1-10/42', + '2/17-2/56': '7/3-7/44', + '3/6-3/54': '9/3-9/53' } self.single_level_tester(code, expected=expected_code) diff --git a/tests/test_level/test_level_06.py b/tests/test_level/test_level_06.py index b9138b7250d..afbaffad5a5 100644 --- a/tests/test_level/test_level_06.py +++ b/tests/test_level/test_level_06.py @@ -2673,18 +2673,17 @@ def test_if_pressed_x_is_var(self): print x""") expected = self.dedent("""\ - x = Value('a') + global_scope_ = dict() + global_scope_["x"] = Value('a') if_pressed_mapping = {"else": "if_pressed_default_else"} - if_pressed_mapping['x'] = 'if_pressed_x_' + if_pressed_mapping[(global_scope_.get("x") or x).data] = 'if_pressed_x_' if_pressed_mapping['else'] = 'if_pressed_else_' def if_pressed_x_(): - global x print(f'it is a letter key') def if_pressed_else_(): - global x print(f'it is another letter key') extensions.if_pressed(if_pressed_mapping) - print(f'{x}')""") + print(f'{global_scope_.get("x") or x}')""") self.multi_level_tester(code=code, expected=expected, max_level=7) @@ -2695,18 +2694,17 @@ def test_if_pressed_x_is_var_and_var_reassignment(self): print x""") expected = self.dedent("""\ - x = Value('a') + global_scope_ = dict() + global_scope_["x"] = Value('a') if_pressed_mapping = {"else": "if_pressed_default_else"} - if_pressed_mapping['x'] = 'if_pressed_x_' + if_pressed_mapping[(global_scope_.get("x") or x).data] = 'if_pressed_x_' if_pressed_mapping['else'] = 'if_pressed_else_' def if_pressed_x_(): - global x - x = Value('great') + global_scope_["x"] = Value('great') def if_pressed_else_(): - global x - x = Value('not great') + global_scope_["x"] = Value('not great') extensions.if_pressed(if_pressed_mapping) - print(f'{x}')""") + print(f'{global_scope_.get("x") or x}')""") self.multi_level_tester(code=code, expected=expected, max_level=7) @@ -2717,17 +2715,16 @@ def test_if_pressed_x_is_var_and_new_var_assignment(self): print m""") expected = self.dedent("""\ - x = Value('a') + global_scope_ = dict() + global_scope_["x"] = Value('a') if_pressed_mapping = {"else": "if_pressed_default_else"} - if_pressed_mapping['x'] = 'if_pressed_x_' + if_pressed_mapping[(global_scope_.get("x") or x).data] = 'if_pressed_x_' if_pressed_mapping['else'] = 'if_pressed_else_' def if_pressed_x_(): - global m, x - m = Value('great') + global_scope_["m"] = Value('great') def if_pressed_else_(): - global m, x - m = Value('not great') + global_scope_["m"] = Value('not great') extensions.if_pressed(if_pressed_mapping) - print(f'{m}')""") + print(f'{global_scope_.get("m") or m}')""") self.multi_level_tester(code=code, expected=expected, max_level=7) diff --git a/tests/test_level/test_level_07.py b/tests/test_level/test_level_07.py index 50f692b8568..e0da6d829df 100644 --- a/tests/test_level/test_level_07.py +++ b/tests/test_level/test_level_07.py @@ -353,16 +353,17 @@ def test_if_pressed_repeat(self): code = "if x is pressed repeat 5 times print 'doe het 5 keer!' else print 'iets anders'" expected = self.dedent(f"""\ - if_pressed_mapping = {{"else": "if_pressed_default_else"}} - if_pressed_mapping['x'] = 'if_pressed_x_' - if_pressed_mapping['else'] = 'if_pressed_else_' - def if_pressed_x_(): - for __i in range(int_with_error('5', {self.value_exception_transpiled()})): - print(f'doe het 5 keer!') - time.sleep(0.1) - def if_pressed_else_(): - print(f'iets anders') - extensions.if_pressed(if_pressed_mapping)""") + global_scope_ = dict() + if_pressed_mapping = {{"else": "if_pressed_default_else"}} + if_pressed_mapping['x'] = 'if_pressed_x_' + if_pressed_mapping['else'] = 'if_pressed_else_' + def if_pressed_x_(): + for __i in range(int_with_error('5', {self.value_exception_transpiled()})): + print(f'doe het 5 keer!') + time.sleep(0.1) + def if_pressed_else_(): + print(f'iets anders') + extensions.if_pressed(if_pressed_mapping)""") self.single_level_tester( code=code, @@ -375,6 +376,7 @@ def test_if_pressed_multiple(self): if z is pressed print 'doe het 1 keer!' else print 'iets anders'""") expected = self.dedent("""\ + global_scope_ = dict() if_pressed_mapping = {"else": "if_pressed_default_else"} if_pressed_mapping['x'] = 'if_pressed_x_' if_pressed_mapping['else'] = 'if_pressed_else_' @@ -414,6 +416,7 @@ def test_repeat_if_pressed_multiple(self): expected = self.dedent( f"""\ + global_scope_ = dict() for __i in range({self.int_transpiled(3)}): if_pressed_mapping = {{"else": "if_pressed_default_else"}} if_pressed_mapping['x'] = 'if_pressed_x_' diff --git a/tests/test_level/test_level_08.py b/tests/test_level/test_level_08.py index ac372f296b8..f20bd8caeea 100644 --- a/tests/test_level/test_level_08.py +++ b/tests/test_level/test_level_08.py @@ -1138,14 +1138,15 @@ def test_if_pressed_x_print(self): else print 'other key'""") expected = self.dedent("""\ - if_pressed_mapping = {"else": "if_pressed_default_else"} - if_pressed_mapping['x'] = 'if_pressed_x_' - def if_pressed_x_(): - print(f'it is a letter key') - if_pressed_mapping['else'] = 'if_pressed_else_' - def if_pressed_else_(): - print(f'other key') - extensions.if_pressed(if_pressed_mapping)""") + global_scope_ = dict() + if_pressed_mapping = {"else": "if_pressed_default_else"} + if_pressed_mapping['x'] = 'if_pressed_x_' + def if_pressed_x_(): + print(f'it is a letter key') + if_pressed_mapping['else'] = 'if_pressed_else_' + def if_pressed_else_(): + print(f'other key') + extensions.if_pressed(if_pressed_mapping)""") self.multi_level_tester(code=code, expected=expected, max_level=11) def test_if_pressed_x_is_var(self): @@ -1158,18 +1159,17 @@ def test_if_pressed_x_is_var(self): print x""") expected = self.dedent("""\ - x = Value('a') + global_scope_ = dict() + global_scope_["x"] = Value('a') if_pressed_mapping = {"else": "if_pressed_default_else"} - if_pressed_mapping['x'] = 'if_pressed_x_' + if_pressed_mapping[(global_scope_.get("x") or x).data] = 'if_pressed_x_' def if_pressed_x_(): - global x print(f'it is a letter key') if_pressed_mapping['else'] = 'if_pressed_else_' def if_pressed_else_(): - global x print(f'it is another letter key') extensions.if_pressed(if_pressed_mapping) - print(f'{x}')""") + print(f'{global_scope_.get("x") or x}')""") self.multi_level_tester(code=code, expected=expected, max_level=11) @@ -1183,18 +1183,17 @@ def test_if_pressed_x_is_var_and_var_reassignment(self): print x""") expected = self.dedent("""\ - x = Value('a') + global_scope_ = dict() + global_scope_["x"] = Value('a') if_pressed_mapping = {"else": "if_pressed_default_else"} - if_pressed_mapping['x'] = 'if_pressed_x_' + if_pressed_mapping[(global_scope_.get("x") or x).data] = 'if_pressed_x_' def if_pressed_x_(): - global x - x = Value('great') + global_scope_["x"] = Value('great') if_pressed_mapping['else'] = 'if_pressed_else_' def if_pressed_else_(): - global x - x = Value('not great') + global_scope_["x"] = Value('not great') extensions.if_pressed(if_pressed_mapping) - print(f'{x}')""") + print(f'{global_scope_.get("x") or x}')""") self.multi_level_tester(code=code, expected=expected, max_level=11) @@ -1208,18 +1207,17 @@ def test_if_pressed_x_is_var_and_new_var_assignment(self): print m""") expected = self.dedent("""\ - x = Value('a') + global_scope_ = dict() + global_scope_["x"] = Value('a') if_pressed_mapping = {"else": "if_pressed_default_else"} - if_pressed_mapping['x'] = 'if_pressed_x_' + if_pressed_mapping[(global_scope_.get("x") or x).data] = 'if_pressed_x_' def if_pressed_x_(): - global m, x - m = Value('great') + global_scope_["m"] = Value('great') if_pressed_mapping['else'] = 'if_pressed_else_' def if_pressed_else_(): - global m, x - m = Value('not great') + global_scope_["m"] = Value('not great') extensions.if_pressed(if_pressed_mapping) - print(f'{m}')""") + print(f'{global_scope_.get("m") or m}')""") self.multi_level_tester(code=code, expected=expected, max_level=11) @@ -1235,22 +1233,23 @@ def test_double_if_pressed(self): print 'other key'""") expected = self.dedent("""\ - if_pressed_mapping = {"else": "if_pressed_default_else"} - if_pressed_mapping['x'] = 'if_pressed_x_' - def if_pressed_x_(): - print(f'first key') - if_pressed_mapping['else'] = 'if_pressed_else_' - def if_pressed_else_(): - print(f'other key') - extensions.if_pressed(if_pressed_mapping) - if_pressed_mapping = {"else": "if_pressed_default_else"} - if_pressed_mapping['y'] = 'if_pressed_y_' - def if_pressed_y_(): - print(f'second key') - if_pressed_mapping['else'] = 'if_pressed_else_' - def if_pressed_else_(): - print(f'other key') - extensions.if_pressed(if_pressed_mapping)""") + global_scope_ = dict() + if_pressed_mapping = {"else": "if_pressed_default_else"} + if_pressed_mapping['x'] = 'if_pressed_x_' + def if_pressed_x_(): + print(f'first key') + if_pressed_mapping['else'] = 'if_pressed_else_' + def if_pressed_else_(): + print(f'other key') + extensions.if_pressed(if_pressed_mapping) + if_pressed_mapping = {"else": "if_pressed_default_else"} + if_pressed_mapping['y'] = 'if_pressed_y_' + def if_pressed_y_(): + print(f'second key') + if_pressed_mapping['else'] = 'if_pressed_else_' + def if_pressed_else_(): + print(f'other key') + extensions.if_pressed(if_pressed_mapping)""") self.maxDiff = None self.multi_level_tester(code=code, expected=expected, max_level=11) @@ -1263,14 +1262,15 @@ def test_if_pressed_is_number_key_print(self): print 'it is something else'""") expected = self.dedent("""\ - if_pressed_mapping = {"else": "if_pressed_default_else"} - if_pressed_mapping['1'] = 'if_pressed_1_' - def if_pressed_1_(): - print(f'it is a number key') - if_pressed_mapping['else'] = 'if_pressed_else_' - def if_pressed_else_(): - print(f'it is something else') - extensions.if_pressed(if_pressed_mapping)""") + global_scope_ = dict() + if_pressed_mapping = {"else": "if_pressed_default_else"} + if_pressed_mapping['1'] = 'if_pressed_1_' + def if_pressed_1_(): + print(f'it is a number key') + if_pressed_mapping['else'] = 'if_pressed_else_' + def if_pressed_else_(): + print(f'it is something else') + extensions.if_pressed(if_pressed_mapping)""") self.multi_level_tester(code=code, expected=expected, max_level=11) @@ -1287,23 +1287,24 @@ def test_if_pressed_command_in_between(self): print 'other'""") expected = textwrap.dedent("""\ - if_pressed_mapping = {"else": "if_pressed_default_else"} - if_pressed_mapping['a'] = 'if_pressed_a_' - def if_pressed_a_(): - print(f'A is pressed') - if_pressed_mapping['else'] = 'if_pressed_else_' - def if_pressed_else_(): - print(f'other') - extensions.if_pressed(if_pressed_mapping) - print(f'Press another button') - if_pressed_mapping = {"else": "if_pressed_default_else"} - if_pressed_mapping['b'] = 'if_pressed_b_' - def if_pressed_b_(): - print(f'B is pressed') - if_pressed_mapping['else'] = 'if_pressed_else_' - def if_pressed_else_(): - print(f'other') - extensions.if_pressed(if_pressed_mapping)""") + global_scope_ = dict() + if_pressed_mapping = {"else": "if_pressed_default_else"} + if_pressed_mapping['a'] = 'if_pressed_a_' + def if_pressed_a_(): + print(f'A is pressed') + if_pressed_mapping['else'] = 'if_pressed_else_' + def if_pressed_else_(): + print(f'other') + extensions.if_pressed(if_pressed_mapping) + print(f'Press another button') + if_pressed_mapping = {"else": "if_pressed_default_else"} + if_pressed_mapping['b'] = 'if_pressed_b_' + def if_pressed_b_(): + print(f'B is pressed') + if_pressed_mapping['else'] = 'if_pressed_else_' + def if_pressed_else_(): + print(f'other') + extensions.if_pressed(if_pressed_mapping)""") self.maxDiff = None self.multi_level_tester(code=code, expected=expected, max_level=11) @@ -1315,6 +1316,7 @@ def test_if_pressed_missing_else_gives_error(self): print 'missing else!'""") expected = textwrap.dedent("""\ + global_scope_ = dict() pass pass""") diff --git a/tests/test_level/test_level_09.py b/tests/test_level/test_level_09.py index fead4116ca4..a7235f2303f 100644 --- a/tests/test_level/test_level_09.py +++ b/tests/test_level/test_level_09.py @@ -365,16 +365,17 @@ def test_if_pressed_repeat(self): print '1 keertje'""") expected = self.dedent(f"""\ - if_pressed_mapping = {{"else": "if_pressed_default_else"}} - if_pressed_mapping['x'] = 'if_pressed_x_' - def if_pressed_x_(): - for __i in range({self.int_transpiled(5)}): - print(f'doe het 5 keer!') - time.sleep(0.1) - if_pressed_mapping['else'] = 'if_pressed_else_' - def if_pressed_else_(): - print(f'1 keertje') - extensions.if_pressed(if_pressed_mapping)""") + global_scope_ = dict() + if_pressed_mapping = {{"else": "if_pressed_default_else"}} + if_pressed_mapping['x'] = 'if_pressed_x_' + def if_pressed_x_(): + for __i in range({self.int_transpiled(5)}): + print(f'doe het 5 keer!') + time.sleep(0.1) + if_pressed_mapping['else'] = 'if_pressed_else_' + def if_pressed_else_(): + print(f'1 keertje') + extensions.if_pressed(if_pressed_mapping)""") self.multi_level_tester(code=code, expected=expected, max_level=11) diff --git a/tests/test_level/test_level_10.py b/tests/test_level/test_level_10.py index 7e0fc01fd76..d26feeebb47 100644 --- a/tests/test_level/test_level_10.py +++ b/tests/test_level/test_level_10.py @@ -156,21 +156,45 @@ def test_if_pressed_with_list_and_for(self): print 'onbekend dier'""") expected = self.dedent("""\ - lijstje = Value([Value('kip'), Value('haan'), Value('kuiken')]) - if_pressed_mapping = {"else": "if_pressed_default_else"} - if_pressed_mapping['x'] = 'if_pressed_x_' - def if_pressed_x_(): - global dier, lijstje - for dier in lijstje.data: - print(f'{dier}') - time.sleep(0.1) - if_pressed_mapping['else'] = 'if_pressed_else_' - def if_pressed_else_(): - global dier, lijstje - print(f'onbekend dier') - extensions.if_pressed(if_pressed_mapping)""") + global_scope_ = dict() + global_scope_["lijstje"] = Value([Value('kip'), Value('haan'), Value('kuiken')]) + if_pressed_mapping = {"else": "if_pressed_default_else"} + if_pressed_mapping['x'] = 'if_pressed_x_' + def if_pressed_x_(): + for dier in (global_scope_.get("lijstje") or lijstje).data: + print(f'{global_scope_.get("dier") or dier}') + time.sleep(0.1) + if_pressed_mapping['else'] = 'if_pressed_else_' + def if_pressed_else_(): + print(f'onbekend dier') + extensions.if_pressed(if_pressed_mapping)""") self.multi_level_tester( code=code, expected=expected, max_level=11) + + def test_if_pressed_in_for_list(self): + code = textwrap.dedent("""\ + buttons is a, s, d + for button in buttons + if button is pressed + print 'correct! ' button + else + print 'not a match'""") + + expected = self.dedent("""\ + global_scope_ = dict() + global_scope_["buttons"] = Value([Value('a'), Value('s'), Value('d')]) + for button in (global_scope_.get("buttons") or buttons).data: + if_pressed_mapping = {"else": "if_pressed_default_else"} + if_pressed_mapping[(global_scope_.get("button") or button).data] = 'if_pressed_button_' + def if_pressed_button_(): + print(f'correct! {global_scope_.get("button") or button}') + if_pressed_mapping['else'] = 'if_pressed_else_' + def if_pressed_else_(): + print(f'not a match') + extensions.if_pressed(if_pressed_mapping) + time.sleep(0.1)""") + + self.multi_level_tester(code=code, expected=expected, max_level=11) diff --git a/tests/test_level/test_level_11.py b/tests/test_level/test_level_11.py index 06f29526ada..7421841db81 100644 --- a/tests/test_level/test_level_11.py +++ b/tests/test_level/test_level_11.py @@ -338,16 +338,15 @@ def test_if_pressed_works_in_for_loop(self): print 'no!'""") expected = self.dedent( - self.for_loop('i', 1, 10), + "global_scope_ = dict()", + self.for_loop('i', 1, 10, scope='global_scope_'), ("""\ if_pressed_mapping = {"else": "if_pressed_default_else"} if_pressed_mapping['p'] = 'if_pressed_p_' def if_pressed_p_(): - global i print(f'press') if_pressed_mapping['else'] = 'if_pressed_else_' def if_pressed_else_(): - global i print(f'no!') extensions.if_pressed(if_pressed_mapping) time.sleep(0.1)""", ' ')) @@ -356,3 +355,31 @@ def if_pressed_else_(): code=code, expected=expected, ) + + def test_if_pressed_in_for_loop(self): + code = textwrap.dedent("""\ + for i in range 1 to 10 + print i + if i is pressed + r = 'Yes' + else + r = 'No' + print r""") + + expected = self.dedent( + "global_scope_ = dict()", + self.for_loop('i', 1, 10, scope='global_scope_'), + ("""\ + print(f'{global_scope_.get("i") or i}') + if_pressed_mapping = {"else": "if_pressed_default_else"} + if_pressed_mapping[(global_scope_.get("i") or i).data] = 'if_pressed_i_' + def if_pressed_i_(): + global_scope_["r"] = Value('\\'Yes\\'') + if_pressed_mapping['else'] = 'if_pressed_else_' + def if_pressed_else_(): + global_scope_["r"] = Value('\\'No\\'') + extensions.if_pressed(if_pressed_mapping) + print(f'{global_scope_.get("r") or r}') + time.sleep(0.1)""", ' ')) + + self.single_level_tester(code=code, expected=expected) diff --git a/tests/test_level/test_level_12.py b/tests/test_level/test_level_12.py index eda3a386d83..ea4d84c8298 100644 --- a/tests/test_level/test_level_12.py +++ b/tests/test_level/test_level_12.py @@ -2963,24 +2963,23 @@ def test_if_pressed_with_list_and_for(self): lijstje is 'kip', 'haan', 'kuiken' if x is pressed for dier in lijstje - print 'dier' + print dier else print 'onbekend dier'""") expected = self.dedent("""\ - lijstje = Value([Value('kip'), Value('haan'), Value('kuiken')]) + global_scope_ = dict() + global_scope_["lijstje"] = Value([Value('kip'), Value('haan'), Value('kuiken')]) if_pressed_mapping = {"else": "if_pressed_default_else"} - global if_pressed_x_ if_pressed_mapping['x'] = 'if_pressed_x_' + global if_pressed_x_ def if_pressed_x_(): - global dier, lijstje - for dier in lijstje.data: - print(f'''dier''') + for dier in (global_scope_.get("lijstje") or lijstje).data: + print(f'''{global_scope_.get("dier") or dier}''') time.sleep(0.1) - global if_pressed_else_ if_pressed_mapping['else'] = 'if_pressed_else_' + global if_pressed_else_ def if_pressed_else_(): - global dier, lijstje print(f'''onbekend dier''') extensions.if_pressed(if_pressed_mapping)""") @@ -2999,20 +2998,19 @@ def test_if_pressed_x_is_var(self): print x""") expected = self.dedent("""\ - x = Value('a') + global_scope_ = dict() + global_scope_["x"] = Value('a') if_pressed_mapping = {"else": "if_pressed_default_else"} + if_pressed_mapping[(global_scope_.get("x") or x).data] = 'if_pressed_x_' global if_pressed_x_ - if_pressed_mapping['x'] = 'if_pressed_x_' def if_pressed_x_(): - global x print(f'''it is a letter key''') - global if_pressed_else_ if_pressed_mapping['else'] = 'if_pressed_else_' + global if_pressed_else_ def if_pressed_else_(): - global x print(f'''it is another letter key''') extensions.if_pressed(if_pressed_mapping) - print(f'''{x}''')""") + print(f'''{global_scope_.get("x") or x}''')""") self.multi_level_tester(code=code, expected=expected, max_level=16) @@ -3026,20 +3024,19 @@ def test_if_pressed_x_is_var_and_var_reassignment(self): print x""") expected = self.dedent("""\ - x = Value('a') + global_scope_ = dict() + global_scope_["x"] = Value('a') if_pressed_mapping = {"else": "if_pressed_default_else"} + if_pressed_mapping[(global_scope_.get("x") or x).data] = 'if_pressed_x_' global if_pressed_x_ - if_pressed_mapping['x'] = 'if_pressed_x_' def if_pressed_x_(): - global x - x = Value('great') - global if_pressed_else_ + global_scope_["x"] = Value('great') if_pressed_mapping['else'] = 'if_pressed_else_' + global if_pressed_else_ def if_pressed_else_(): - global x - x = Value('not great') + global_scope_["x"] = Value('not great') extensions.if_pressed(if_pressed_mapping) - print(f'''{x}''')""") + print(f'''{global_scope_.get("x") or x}''')""") self.multi_level_tester(code=code, expected=expected, max_level=16) @@ -3053,20 +3050,19 @@ def test_if_pressed_x_is_var_and_new_var_assignment(self): print m""") expected = self.dedent("""\ - x = Value('a') + global_scope_ = dict() + global_scope_["x"] = Value('a') if_pressed_mapping = {"else": "if_pressed_default_else"} + if_pressed_mapping[(global_scope_.get("x") or x).data] = 'if_pressed_x_' global if_pressed_x_ - if_pressed_mapping['x'] = 'if_pressed_x_' def if_pressed_x_(): - global m, x - m = Value('great') - global if_pressed_else_ + global_scope_["m"] = Value('great') if_pressed_mapping['else'] = 'if_pressed_else_' + global if_pressed_else_ def if_pressed_else_(): - global m, x - m = Value('not great') + global_scope_["m"] = Value('not great') extensions.if_pressed(if_pressed_mapping) - print(f'''{m}''')""") + print(f'''{global_scope_.get("m") or m}''')""") self.multi_level_tester(code=code, expected=expected, max_level=16) @@ -3432,22 +3428,157 @@ def test_global_var_should_not_shadow_local_var_in_func(self): print x""") expected = textwrap.dedent("""\ + global_scope_ = dict() def turn(): + local_scope_turn_ = dict() if_pressed_mapping = {"else": "if_pressed_default_else"} - global if_pressed_x_ - if_pressed_mapping['x'] = 'if_pressed_x_' - def if_pressed_x_(): - global x + if_pressed_mapping['x'] = 'if_pressed_turn_x_' + global if_pressed_turn_x_ + def if_pressed_turn_x_(): print(f'''good''') - global if_pressed_else_ - if_pressed_mapping['else'] = 'if_pressed_else_' - def if_pressed_else_(): - global x + if_pressed_mapping['else'] = 'if_pressed_turn_else_' + global if_pressed_turn_else_ + def if_pressed_turn_else_(): print(f'''bad''') extensions.if_pressed(if_pressed_mapping) turn() - x = Value(1 + 1, num_sys='Latin') - print(f'''{x}''')""") + global_scope_["x"] = Value(1 + 1, num_sys='Latin') + print(f'''{global_scope_.get("x") or x}''')""") + + self.multi_level_tester( + code=code, + expected=expected, + max_level=16, + ) + + def test_if_pressed_in_func(self): + code = textwrap.dedent("""\ + define turnz + x is 'a' + if x is pressed + x is 'great' + else + x is 'not great' + print x + + call turnz""") + + expected = textwrap.dedent("""\ + global_scope_ = dict() + def turnz(): + local_scope_turnz_ = dict() + local_scope_turnz_["x"] = Value('a') + if_pressed_mapping = {"else": "if_pressed_default_else"} + if_pressed_mapping[(local_scope_turnz_.get("x") or global_scope_.get("x") or x).data] = 'if_pressed_turnz_x_' + global if_pressed_turnz_x_ + def if_pressed_turnz_x_(): + local_scope_turnz_["x"] = Value('great') + if_pressed_mapping['else'] = 'if_pressed_turnz_else_' + global if_pressed_turnz_else_ + def if_pressed_turnz_else_(): + local_scope_turnz_["x"] = Value('not great') + extensions.if_pressed(if_pressed_mapping) + print(f'''{local_scope_turnz_.get("x") or global_scope_.get("x") or x}''') + turnz()""") + + self.multi_level_tester( + code=code, + expected=expected, + max_level=16, + ) + + def test_if_pressed_in_func_with_arg(self): + code = textwrap.dedent("""\ + define make_turn with direction + if direction = 'left' + turn -90 + else + turn 90 + if l is pressed + call make_turn with 'left' + else + call make_turn with 'right'""") + + expected = textwrap.dedent('''\ + global_scope_ = dict() + def make_turn(direction): + local_scope_make_turn_ = {"direction": direction} + if (local_scope_make_turn_.get("direction") or global_scope_.get("direction") or direction).data == 'left': + __trtl = number_with_error(-90, """Runtime Value Error""") + t.right(min(600, __trtl) if __trtl > 0 else max(-600, __trtl)) + else: + __trtl = number_with_error(90, """Runtime Value Error""") + t.right(min(600, __trtl) if __trtl > 0 else max(-600, __trtl)) + if_pressed_mapping = {"else": "if_pressed_default_else"} + if_pressed_mapping['l'] = 'if_pressed_l_' + global if_pressed_l_ + def if_pressed_l_(): + make_turn(Value('left')) + if_pressed_mapping['else'] = 'if_pressed_else_' + global if_pressed_else_ + def if_pressed_else_(): + make_turn(Value('right')) + extensions.if_pressed(if_pressed_mapping)''') + + self.multi_level_tester( + code=code, + expected=expected, + max_level=16, + ) + + def test_if_pressed_in_two_funcs(self): + code = textwrap.dedent("""\ + x is 'a' + define turnz + if x is pressed + x is 'turn' + else + x is 'do not turn' + print x + + define forwardz + if x is pressed + x is 'go forward' + else + x is 'do not go forward' + print x + + call turnz + call forwardz + print x""") + + expected = textwrap.dedent("""\ + global_scope_ = dict() + global_scope_["x"] = Value('a') + def turnz(): + local_scope_turnz_ = dict() + if_pressed_mapping = {"else": "if_pressed_default_else"} + if_pressed_mapping[(local_scope_turnz_.get("x") or global_scope_.get("x") or x).data] = 'if_pressed_turnz_x_' + global if_pressed_turnz_x_ + def if_pressed_turnz_x_(): + local_scope_turnz_["x"] = Value('turn') + if_pressed_mapping['else'] = 'if_pressed_turnz_else_' + global if_pressed_turnz_else_ + def if_pressed_turnz_else_(): + local_scope_turnz_["x"] = Value('do not turn') + extensions.if_pressed(if_pressed_mapping) + print(f'''{local_scope_turnz_.get("x") or global_scope_.get("x") or x}''') + def forwardz(): + local_scope_forwardz_ = dict() + if_pressed_mapping = {"else": "if_pressed_default_else"} + if_pressed_mapping[(local_scope_forwardz_.get("x") or global_scope_.get("x") or x).data] = 'if_pressed_forwardz_x_' + global if_pressed_forwardz_x_ + def if_pressed_forwardz_x_(): + local_scope_forwardz_["x"] = Value('go forward') + if_pressed_mapping['else'] = 'if_pressed_forwardz_else_' + global if_pressed_forwardz_else_ + def if_pressed_forwardz_else_(): + local_scope_forwardz_["x"] = Value('do not go forward') + extensions.if_pressed(if_pressed_mapping) + print(f'''{local_scope_forwardz_.get("x") or global_scope_.get("x") or x}''') + turnz() + forwardz() + print(f'''{global_scope_.get("x") or x}''')""") self.multi_level_tester( code=code, diff --git a/tests/test_level/test_level_15.py b/tests/test_level/test_level_15.py index 71657af0f67..0fe3bd6118d 100644 --- a/tests/test_level/test_level_15.py +++ b/tests/test_level/test_level_15.py @@ -630,9 +630,10 @@ def test_if_pressed_without_else_works(self): print 'press'""") expected = textwrap.dedent("""\ + global_scope_ = dict() if_pressed_mapping = {"else": "if_pressed_default_else"} - global if_pressed_p_ if_pressed_mapping['p'] = 'if_pressed_p_' + global if_pressed_p_ def if_pressed_p_(): print(f'''press''') extensions.if_pressed(if_pressed_mapping)""") @@ -650,21 +651,20 @@ def test_if_pressed_works_in_while_loop(self): print 'Uit de loop!'""") expected = textwrap.dedent("""\ - stop = Value(0, num_sys='Latin') + global_scope_ = dict() + global_scope_["stop"] = Value(0, num_sys='Latin') while stop.data!=1: if_pressed_mapping = {"else": "if_pressed_default_else"} - global if_pressed_p_ if_pressed_mapping['p'] = 'if_pressed_p_' + global if_pressed_p_ def if_pressed_p_(): - global stop print(f'''press''') extensions.if_pressed(if_pressed_mapping) if_pressed_mapping = {"else": "if_pressed_default_else"} - global if_pressed_s_ if_pressed_mapping['s'] = 'if_pressed_s_' + global if_pressed_s_ def if_pressed_s_(): - global stop - stop = Value(1, num_sys='Latin') + global_scope_["stop"] = Value(1, num_sys='Latin') extensions.if_pressed(if_pressed_mapping) time.sleep(0.1) print(f'''Uit de loop!''')""") @@ -685,18 +685,19 @@ def test_if_pressed_multiple_lines_body(self): print 'lalalalala'""") expected = textwrap.dedent("""\ - if_pressed_mapping = {"else": "if_pressed_default_else"} - global if_pressed_x_ - if_pressed_mapping['x'] = 'if_pressed_x_' - def if_pressed_x_(): - print(f'''x''') - print(f'''lalalalala''') - global if_pressed_else_ - if_pressed_mapping['else'] = 'if_pressed_else_' - def if_pressed_else_(): - print(f'''not x''') - print(f'''lalalalala''') - extensions.if_pressed(if_pressed_mapping)""") + global_scope_ = dict() + if_pressed_mapping = {"else": "if_pressed_default_else"} + if_pressed_mapping['x'] = 'if_pressed_x_' + global if_pressed_x_ + def if_pressed_x_(): + print(f'''x''') + print(f'''lalalalala''') + if_pressed_mapping['else'] = 'if_pressed_else_' + global if_pressed_else_ + def if_pressed_else_(): + print(f'''not x''') + print(f'''lalalalala''') + extensions.if_pressed(if_pressed_mapping)""") self.multi_level_tester( code=code, diff --git a/tests/test_level/test_level_16.py b/tests/test_level/test_level_16.py index 4be1dd4dfc1..8bc98bfdceb 100644 --- a/tests/test_level/test_level_16.py +++ b/tests/test_level/test_level_16.py @@ -930,17 +930,17 @@ def test_if_pressed_with_list_and_for(self): lijstje is ['kip', 'haan', 'kuiken'] if x is pressed for dier in lijstje - print 'dier'""") + print dier""") expected = self.dedent("""\ - lijstje = Value([Value('kip'), Value('haan'), Value('kuiken')]) + global_scope_ = dict() + global_scope_["lijstje"] = Value([Value('kip'), Value('haan'), Value('kuiken')]) if_pressed_mapping = {"else": "if_pressed_default_else"} - global if_pressed_x_ if_pressed_mapping['x'] = 'if_pressed_x_' + global if_pressed_x_ def if_pressed_x_(): - global dier, lijstje - for dier in lijstje.data: - print(f'''dier''') + for dier in (global_scope_.get("lijstje") or lijstje).data: + print(f'''{global_scope_.get("dier") or dier}''') time.sleep(0.1) extensions.if_pressed(if_pressed_mapping)""") diff --git a/tests/test_level/test_level_17.py b/tests/test_level/test_level_17.py index 996f3a01598..0a80c9cf91c 100644 --- a/tests/test_level/test_level_17.py +++ b/tests/test_level/test_level_17.py @@ -578,9 +578,10 @@ def test_if_pressed_with_color(self): expected = self.dedent( f"""\ + global_scope_ = dict() if_pressed_mapping = {{"else": "if_pressed_default_else"}} - global if_pressed_x_ if_pressed_mapping['x'] = 'if_pressed_x_' + global if_pressed_x_ def if_pressed_x_():""", (self.color_transpiled('red'), ' '), "extensions.if_pressed(if_pressed_mapping)") @@ -705,20 +706,21 @@ def test_pressed_elif(self): print 'Other'""") expected = self.dedent("""\ - if_pressed_mapping = {"else": "if_pressed_default_else"} - global if_pressed_a_ - if_pressed_mapping['a'] = 'if_pressed_a_' - def if_pressed_a_(): - print(f'''A''') - global if_pressed_b_ - if_pressed_mapping['b'] = 'if_pressed_b_' - def if_pressed_b_(): - print(f'''B''') - global if_pressed_else_ - if_pressed_mapping['else'] = 'if_pressed_else_' - def if_pressed_else_(): - print(f'''Other''') - extensions.if_pressed(if_pressed_mapping)""") + global_scope_ = dict() + if_pressed_mapping = {"else": "if_pressed_default_else"} + if_pressed_mapping['a'] = 'if_pressed_a_' + global if_pressed_a_ + def if_pressed_a_(): + print(f'''A''') + if_pressed_mapping['b'] = 'if_pressed_b_' + global if_pressed_b_ + def if_pressed_b_(): + print(f'''B''') + if_pressed_mapping['else'] = 'if_pressed_else_' + global if_pressed_else_ + def if_pressed_else_(): + print(f'''Other''') + extensions.if_pressed(if_pressed_mapping)""") self.single_level_tester(code=code, expected=expected)