From b59041227d31e000e4f72a4e343a377b2891caec Mon Sep 17 00:00:00 2001
From: George Marchment <georgemarchment@yahoo.fr>
Date: Wed, 19 Feb 2025 15:13:21 +0100
Subject: [PATCH] Added single to multi line condition + added multiple
 analysis when rewriting (to check if this is usefull)

---
 src/code_.py    |  12 ++++++
 src/workflow.py | 105 +++++++++++++++++++++++++++---------------------
 2 files changed, 71 insertions(+), 46 deletions(-)

diff --git a/src/code_.py b/src/code_.py
index 3fd7bd3..b43c9c5 100644
--- a/src/code_.py
+++ b/src/code_.py
@@ -20,6 +20,7 @@ class Code:
         self.code_wo_comments = re.sub(constant.DOUBLE_BACKSLAPSH_JUMP, ' ', self.code_wo_comments)
         self.code_wo_comments = re.sub(constant.BACKSLAPSH_JUMP, ' ', self.code_wo_comments)
         self.code_wo_comments = self.code_wo_comments.replace("||", "$OR$")
+        self.code_wo_comments = self.turn_single_condition_into_multiline(self.code_wo_comments)
 
 
     def check_its_nextflow(self):
@@ -29,6 +30,17 @@ class Code:
                 raise BioFlowInsightError(f"The presence of '{bit_of_code}' is detected{self.get_string_line(bit_of_code)}.", num = 1,origin=self)
             
    
+    def turn_single_condition_into_multiline(self, code):
+        to_replace = []
+        for match in re.finditer(r"if *\((.+)\) *([^{\n]+)\n", code):
+            old = match.group(0)
+            new = f"if ({match.group(1)}) {{\n{match.group(2)}\n}}\n"
+            to_replace.append((old, new))
+        for r in to_replace:
+            old, new = r
+            code = code.replace(old, new)
+        return code
+
     def get_line(self, bit_of_code):
         code = remove_comments(self.code)
         index = code.find(bit_of_code)
diff --git a/src/workflow.py b/src/workflow.py
index eaae290..83906e3 100644
--- a/src/workflow.py
+++ b/src/workflow.py
@@ -565,7 +565,10 @@ George Marchment, Bryan Brancotte, Marie Schmit, Frédéric Lemoine, Sarah Cohen
             if(takes.get_code()!=param.get_code(get_OG = True)):
                 new_header+=f"{takes.get_code()} = {param.get_code(get_OG = True)}"
 
+        temp_code = code
         code = code.replace(OG_call.get_code(get_OG = True), f"{new_header}\n\n{OG_body}", 1)
+        if(temp_code==code):
+            raise Exception("Something went wrong: The code hasn't changed")
 
         #REPLACE THE EMITS
         #TODO admittedly this code below is very moche -> but it's functionnal -> update it 
@@ -575,20 +578,23 @@ George Marchment, Bryan Brancotte, Marie Schmit, Frédéric Lemoine, Sarah Cohen
         for exe in all_executors:
             #We don't need to check the case call since the workflow has already been rewriteen -> emits only appear in operations
             if(exe.get_type()=="Operation"):
-                emited = exe.get_origins()
-                if(len(emited)==1):
-                    emited = emited[0]
+                for emited in exe.get_origins():
                     if(emited.get_type()=="Emitted"):
                         if(emited.get_emitted_by().get_first_element_called()==subworklfow):
                             if(emited.get_emits() not in emits):
                                 raise Exception("This shoudn't happen -> since it is the actual subworkflow")
-                            to_replace.append((exe.get_code(get_OG = True), f"{exe.get_gives()[0].get_code()} = {emited.get_emits().get_origins()[0].get_code()}"))
+                            new = exe.get_code(get_OG = True).replace(emited.get_code(), emited.get_emits().get_origins()[0].get_code())
+                            #to_replace.append((exe.get_code(get_OG = True), f"{exe.get_gives()[0].get_code()} = {emited.get_emits().get_origins()[0].get_code()}"))
+                            to_replace.append((exe.get_code(get_OG = True), new))
         for r in to_replace:
             old, new = r
-            #Case of channel == channel
+            temp_code = code
+            #Case of channel = channel
             if(new.split("=")[0].strip()==new.split("=")[1].strip()):
                 new = ''
             code = code.replace(old, new)
+            if(temp_code==code):
+                raise Exception("Something went wrong: The code hasn't changed")
         
         return code
 
@@ -662,38 +668,39 @@ George Marchment, Bryan Brancotte, Marie Schmit, Frédéric Lemoine, Sarah Cohen
             code = self.simplify_workflow_code()
             self.rewrite_and_initialise(code)
             
-            #Get the clusters and the code
-            self.check_relevant_processes_in_workflow(relevant_processes)
-            self.generate_user_view(relevant_processes = relevant_processes, processes_2_remove =  [])
-            clusters = self.graph.get_clusters_from_user_view()
+            
             
             #DETERMING WHICH SUBWORKFLOWS ARE BROKEN WITH THE CLUSTER
-            #Creating the clusters with calls instead of processes or subworkflows
-            set_clusters_with_calls = []
-            for c in clusters:
-                tab = []
-                for ele in c:
-                    if(ele.get_type()=="Operation"):
-                        if(ele.get_artificial_status()==False):
-                            tab.append(ele)
-                    else:
-                        call = ele.get_call()
-                        tab.append(call)
-                set_clusters_with_calls.append(set(tab))
+            def get_clusters_with_calls(clusters):
+                #Creating the clusters with calls instead of processes or subworkflows
+                set_clusters_with_calls = []
+                for c in clusters:
+                    tab = []
+                    for ele in c:
+                        if(ele.get_type()=="Operation"):
+                            if(ele.get_artificial_status()==False):
+                                tab.append(ele)
+                        else:
+                            call = ele.get_call()
+                            tab.append(call)
+                    set_clusters_with_calls.append(set(tab))
+                return set_clusters_with_calls
 
             
             #Getting subworkflows to executors
-            subworkflow_2_executors = {}
-            for sub in self.get_subworkflows_called():
-                executors = sub.get_all_executors_in_workflow()
-                subworkflow_2_executors[sub] = []
-                for ele in executors:
-                    #Cannot add calls to subworkflows -> they are already present by definition
-                    if(ele.get_type()=="Call" and ele.get_first_element_called().get_type()=="Subworkflow"):
-                        None
-                        #We don't add it
-                    else:
-                        subworkflow_2_executors[sub].append(ele)
+            def get_subworkflow_2_executors():
+                subworkflow_2_executors = {}
+                for sub in self.get_subworkflows_called():
+                    executors = sub.get_all_executors_in_workflow()
+                    subworkflow_2_executors[sub] = []
+                    for ele in executors:
+                        #Cannot add calls to subworkflows -> they are already present by definition
+                        if(ele.get_type()=="Call" and ele.get_first_element_called().get_type()=="Subworkflow"):
+                            None
+                            #We don't add it
+                        else:
+                            subworkflow_2_executors[sub].append(ele)
+                return subworkflow_2_executors
                 #subworkflow_2_executors[sub.get_name()] = set(list(dico.keys()))
 
             #TODO -> write tests to test this function
@@ -719,18 +726,27 @@ George Marchment, Bryan Brancotte, Marie Schmit, Frédéric Lemoine, Sarah Cohen
                         broken_subworkflows.append(sub)
                 return broken_subworkflows
             
-            broken_subworkflows = get_workflows_broken(subworkflow_2_executors, set_clusters_with_calls)
-            
-
-            #Rewrite broken subworkflows
-            for sub in broken_subworkflows:
-                code = self.rewrite_subworkflow_call(code, sub)
-            
-            #TODO -> this needs to be optimised
-            self.rewrite_and_initialise(code)
             #Get the clusters and the code
+            self.check_relevant_processes_in_workflow(relevant_processes)
             self.generate_user_view(relevant_processes = relevant_processes, processes_2_remove =  [])
             clusters = self.graph.get_clusters_from_user_view()
+            broken_subworkflows = get_workflows_broken(get_subworkflow_2_executors(), get_clusters_with_calls(clusters))
+            #While there still are broken workflows -> need to redo the analysis
+            while(len(broken_subworkflows)>0):
+                #Rewrite broken subworkflows
+                sub = broken_subworkflows[0]
+                code = self.rewrite_subworkflow_call(code, sub)
+                self.rewrite_and_initialise(code)
+                #Get the clusters and the code
+                self.generate_all_graphs()
+                self.generate_user_view(relevant_processes = relevant_processes, processes_2_remove =  [])
+                clusters = self.graph.get_clusters_from_user_view()
+                broken_subworkflows = get_workflows_broken(get_subworkflow_2_executors(), get_clusters_with_calls(clusters))
+            
+            
+    
+
+
 
 
             #Get the clsuters with the corresponding operations inside
@@ -959,7 +975,6 @@ George Marchment, Bryan Brancotte, Marie Schmit, Frédéric Lemoine, Sarah Cohen
                     subworkflow_cluster_calls_to_add.append(subworkfow_call)
                     index_cluster+=1
                     
-
               
             #TODO -> rmoving the conditions which are problematic
             #This might not be the probleme -> when rerunnung the analysis isn't totally robust
@@ -982,10 +997,8 @@ George Marchment, Bryan Brancotte, Marie Schmit, Frédéric Lemoine, Sarah Cohen
                         break 
                 if(still_simplifying_conditions):
                     code = code.replace(to_replace, f"{anker1}\n{anker2}")
-            
-            
         
-
+            
             #Replace the ankers by the calls of the subworkflows  
             for i in range(len(subworkflow_clusters_to_add)):
                 #Extracting the conditions in the code
@@ -1005,7 +1018,7 @@ George Marchment, Bryan Brancotte, Marie Schmit, Frédéric Lemoine, Sarah Cohen
                     subworkflow_call = f"\n}}\n{subworkflow_call}\nif({c}){{\n"
                 code = code.replace(anker, subworkflow_call)
             
-           
+            
             for old, new in channels_to_replace_outside_of_cluster:
                 pattern= fr"[ \(,]({re.escape(old)})"
                 code = replace_group1(code, pattern, new)
-- 
GitLab