Repository: hedyorg/hedy

Issue:
Make expansion of lists non-terminals possible in the merger
Several levels now redefine the list of commands with a lot of repetition, for example:

level 3:
`command: print | ask | turtle | assign | assign_list | add | remove | sleep | invalid_space | ask_dep_2 | echo_dep_2 | comment | invalid`

level 4:
`command: print | ask | turtle | assign_list | add | remove | sleep | ask_no_quotes| assign | print_no_quotes | comment | invalid
`

Would be nicer if we would define something like += and generate proper Lark in the merger


Discussion:

Resolving patch:
diff --git a/hedy.py b/hedy.py
--- a/hedy.py
+++ b/hedy.py
@@ -1595,9 +1595,38 @@ def merge_grammars(grammar_text_1, grammar_text_2):
             name_2, definition_2 = parts[0], ''.join(parts[1]) #get part before are after :
             if name_1 == name_2:
                 override_found = True
-                new_rule = line_2
-                # this rule is now in the grammar, remove form this list
-                remaining_rules_grammar_2.remove(new_rule)
+                # Check if the rule is adding or substracting new rules                
+                has_add_op  = definition_2.startswith('+=') 
+                has_sub_op = has_add_op and '-='  in definition_2
+                has_last_op = has_add_op and '>'  in definition_2
+                if has_sub_op:
+                    # Get the rules we need to substract
+                    part_list = definition_2.split('-=')
+                    add_list, sub_list =  (part_list[0], part_list[1]) if has_sub_op else (part_list[0], '')
+                    add_list = add_list[3:]  
+                    # Get the rules that need to be last
+                    sub_list = sub_list.split('>')  
+                    sub_list, last_list = (sub_list[0], sub_list[1]) if has_last_op  else (sub_list[0], '')
+                    sub_list = sub_list + '|' + last_list
+                    result_cmd_list = get_remaining_rules(definition_1, sub_list)
+                elif has_add_op:
+                     # Get the rules that need to be last
+                    part_list = definition_2.split('>')
+                    add_list, sub_list =  (part_list[0], part_list[1]) if has_last_op else (part_list[0], '')
+                    add_list = add_list[3:]
+                    last_list = sub_list
+                    result_cmd_list = get_remaining_rules(definition_1, sub_list)
+                else:
+                    result_cmd_list = definition_1
+
+                if has_last_op:
+                    new_rule = f"{name_1}: {result_cmd_list} | {add_list} | {last_list}"
+                elif has_add_op:
+                    new_rule = f"{name_1}: {result_cmd_list} | {add_list}"
+                else:
+                    new_rule = line_2
+                #Already procesed so remove it
+                remaining_rules_grammar_2.remove(line_2)
                 break
 
         # new rule found? print that. nothing found? print org rule
@@ -1614,6 +1643,12 @@ def merge_grammars(grammar_text_1, grammar_text_2):
     merged_grammar = sorted(merged_grammar)
     return '\n'.join(merged_grammar)
 
+def get_remaining_rules(orig_def, sub_def):
+    orig_cmd_list     = [command.strip() for command in orig_def.split('|')]                    
+    unwanted_cmd_list = [command.strip() for command in sub_def.split('|')]                    
+    result_cmd_list   = [cmd for cmd in orig_cmd_list if cmd not in unwanted_cmd_list]                    
+    result_cmd_list   = ' | '.join(result_cmd_list) # turn the result list into a string
+    return result_cmd_list
 
 def create_grammar(level, lang="en"):
     # start with creating the grammar for level 1


Test patch: