Repository: hedyorg/hedy

Issue:
[BUG] add works with variables only, and remove doesn't work yet
Level 3
You can't add a word to a list: 
![image](https://user-images.githubusercontent.com/80678586/149317310-2efda2d1-24c1-4256-abf2-80cccbdef524.png)

But you can add a variable: 
![image](https://user-images.githubusercontent.com/80678586/149317451-ec70de3e-2710-423c-bbee-bd806fa1cdc1.png)

Remove has the same problem:
![image](https://user-images.githubusercontent.com/80678586/149317596-bd35a0dc-b4d5-4935-b512-dfdd63538a0d.png)

But if you turn kip into a variable, it does not give an error message. But it still doesn't remove kip from the list, so it's not just the variable-or-not-problem.
![image](https://user-images.githubusercontent.com/80678586/149317838-bb7bb6a8-005e-4b8e-bb97-649a2619b779.png)



Discussion:
Good catch, this will be fixed soon!

> But if you turn kip into a variable, it does not give an error message. But it still doesn't remove kip from the list, so it's not just the variable-or-not-problem.
> ![image](https://user-images.githubusercontent.com/80678586/149317838-bb7bb6a8-005e-4b8e-bb97-649a2619b779.png)

This one however is very very tricky but actually correct! If you turn kip into a variable and then remove kip, you will remove the variable `kip` (the value 3) which is not in the list.

Do you want an error message if kids remove a not existing value?




Resolving patch:
diff --git a/hedy.py b/hedy.py
--- a/hedy.py
+++ b/hedy.py
@@ -303,6 +303,9 @@ class ExtractAST(Transformer):
     def text(self, args):
         return Tree('text', [''.join([str(c) for c in args])])
 
+    def text_with_spaces(self, args):
+        return Tree('text', [' '.join([str(c) for c in args])])
+
     def INT(self, args):
         return Tree('integer', [str(args)])
 
@@ -547,6 +550,14 @@ def for_loop(self, tree):
     def integer(self, tree):
         return self.to_typed_tree(tree, HedyType.integer)
 
+    def text_with_spaces(self, tree):
+        # under level 12 integers appear as text, so we parse them
+        if self.level < 12:
+            type_ = HedyType.integer if ConvertToPython.is_int(tree.children[0]) else HedyType.string
+        else:
+            type_ = HedyType.string
+        return self.to_typed_tree(tree, type_)
+
     def text(self, tree):
         # under level 12 integers appear as text, so we parse them
         if self.level < 12:
@@ -751,6 +762,9 @@ def number(self, args, meta):
 
     def text(self, args, meta):
         return all(args), ''.join([c for c in args]), meta
+      
+    def text_with_spaces(self, args, meta):
+        return all(args), ' '.join([c for c in args])
 
 class UsesTurtle(Transformer):
     # returns true if Forward or Turn are in the tree, false otherwise
@@ -844,6 +858,9 @@ def NUMBER(self, args):
     def text(self, args):
         return []
 
+    def text_with_spaces(self, args):
+        return []
+
 def all_commands(input_string, level, lang='en'):
     input_string = process_input_string(input_string, level)
     program_root = parse_input(input_string, level, lang)
@@ -878,6 +895,9 @@ def NUMBER(self, args):
     def text(self, args):
         return ''.join(args)
 
+    def text_with_spaces(self, args):
+        return ''.join(args)
+
 
 def all_print_arguments(input_string, level, lang='en'):
     input_string = process_input_string(input_string, level)
@@ -1115,6 +1135,10 @@ def command(self, args):
 
     def text(self, args):
         return ''.join([str(c) for c in args])
+
+    def text_with_spaces(self, args):
+        return ' '.join([str(c) for c in args])
+
     def integer(self, args):
         return str(args[0])
 
@@ -1273,11 +1297,11 @@ def list_access(self, args):
         else:
             return args[0] + '[' + args[1] + '-1]'
     def add(self, args):
-        var = args[0]
+        var = self.process_variable(args[0])
         list = args[1]
         return f"{list}.append({var})"
     def remove(self, args):
-        var = args[0]
+        var = self.process_variable(args[0])
         list = args[1]
         return textwrap.dedent(f"""\
         try:
@@ -1294,9 +1318,6 @@ def var_access(self, args):
         name = args[0]
         return hash_var(name)
 
-    def text(self, args):
-        return ''.join([str(c) for c in args])
-
     def print_ask_args(self, args):
         args = self.check_var_usage(args)
         result = ''


Test patch:
diff --git a/tests/test_level_03.py b/tests/test_level_03.py
--- a/tests/test_level_03.py
+++ b/tests/test_level_03.py
@@ -415,7 +415,60 @@ def test_print_list_var(self):
     )
 
   #add/remove tests
-  def test_add_to_list(self):
+  def test_add_text_to_list(self):
+    code = textwrap.dedent("""\
+    dieren is koe, kiep
+    add muis to dieren
+    print dieren at random""")
+
+    expected = textwrap.dedent("""\
+    dieren = ['koe', 'kiep']
+    dieren.append('muis')
+    print(f'{random.choice(dieren)}')""")
+
+    self.single_level_tester(
+      code=code,
+      expected=expected,
+      extra_check_function = self.result_in(['koe', 'kiep', 'muis']),
+    )
+  def test_remove_text_from_list(self):
+    code = textwrap.dedent("""\
+    dieren is koe, kiep
+    remove kiep from dieren
+    print dieren at random""")
+
+    expected = textwrap.dedent("""\
+    dieren = ['koe', 'kiep']
+    try:
+        dieren.remove('kiep')
+    except:
+       pass
+    print(f'{random.choice(dieren)}')""")
+
+    self.single_level_tester(
+      code=code,
+      expected=expected,
+      extra_check_function=self.result_in(['koe']),
+    )
+
+  def test_add_text_with_spaces_to_list(self):
+    code = textwrap.dedent("""\
+    opties is zeker weten, misschien wel
+    add absoluut niet to opties
+    print opties at random""")
+
+    expected = textwrap.dedent("""\
+    opties = ['zeker weten', 'misschien wel']
+    opties.append('absoluut niet')
+    print(f'{random.choice(opties)}')""")
+
+    self.single_level_tester(
+      # max_level=3,
+      code=code,
+      expected=expected
+    )
+
+  def test_add_ask_to_list(self):
     code = textwrap.dedent("""\
     color is ask what is your favorite color? 
     colors is green, red, blue
@@ -433,7 +486,8 @@ def test_add_to_list(self):
       code=code,
       expected=expected
     )
-  def test_remove_from_list(self):
+
+  def test_remove_ask_from_list(self):
     code = textwrap.dedent("""\
     colors is green, red, blue
     color is ask what color to remove?
diff --git a/tests/test_level_04.py b/tests/test_level_04.py
--- a/tests/test_level_04.py
+++ b/tests/test_level_04.py
@@ -184,6 +184,45 @@ def test_assign_Python_keyword(self):
     self.single_level_tester(code=code, expected=expected)
 
   #add/remove tests
+  #add/remove tests
+  def test_add_text_to_list(self):
+    code = textwrap.dedent("""\
+    dieren is koe, kiep
+    add muis to dieren
+    print dieren at random""")
+
+    expected = textwrap.dedent("""\
+    dieren = ['koe', 'kiep']
+    dieren.append('muis')
+    print(f'{random.choice(dieren)}')""")
+
+    self.multi_level_tester(
+      max_level=11,
+      code=code,
+      expected=expected,
+      extra_check_function = self.result_in(['koe', 'kiep', 'muis']),
+    )
+  def test_remove_text_from_list(self):
+    code = textwrap.dedent("""\
+    dieren is koe, kiep
+    remove kiep from dieren
+    print dieren at random""")
+
+    expected = textwrap.dedent("""\
+    dieren = ['koe', 'kiep']
+    try:
+        dieren.remove('kiep')
+    except:
+       pass
+    print(f'{random.choice(dieren)}')""")
+
+    self.multi_level_tester(
+      max_level=11,
+      code=code,
+      expected=expected,
+      extra_check_function=self.result_in(['koe']),
+    )
+
   def test_add_to_list(self):
     code = textwrap.dedent("""\
     color is ask 'what is your favorite color? '