From 01542e56f589b79b14fd08e0a2c652194b94085f Mon Sep 17 00:00:00 2001
From: Marius Bozga <Marius.Bozga@univ-grenoble-alpes.fr>
Date: Wed, 17 Nov 2021 16:15:40 +0100
Subject: [PATCH] fix state name binding in hierarchical / concurrent states

---
 src/model/action.C | 51 ++++++----------------------------------------
 src/model/state.C  | 31 ++++++++++++++++++++++++++++
 src/model/state.h  |  3 ++-
 3 files changed, 39 insertions(+), 46 deletions(-)

diff --git a/src/model/action.C b/src/model/action.C
index ea18e5b..c6a0f14 100644
--- a/src/model/action.C
+++ b/src/model/action.C
@@ -874,53 +874,14 @@ void IfNextstateAction::PreCompile() {
 
   int ok = 1;
 
-  /*
-   *
-   * state name ~ literal_1 @ literal_2 @ ... @ literal_n
-   *
-   * implemented too early ;-)
-
-  IfState* base[3] = {NULL, NULL, NULL};
-
-  base[0] = (IfState*) CONTEXT.Top(-3);
-  base[1] = ((IfProcessEntity*) CONTEXT[1])->GetEntry();
-  if (base[0] == base[1]) base[1] = NULL;
-
-  for(int i = 0; base[i]; i++) {
-
-    IfState* current = base[i];
-    for(int k = 0, j;; ) {
-
-      char literal[256] = "";
-      for(j = 0; m_pStateName[k] != '\0' &&
-                 m_pStateName[k] != '@'; j++, k++) 
-        literal[j] = m_pStateName[k];
-      literal[j] = '\0';
-      
-      if (m_pStateName[k] == '@')
-        k++;
-
-      current = current->GetStates()->Find(literal);
-      if (current == NULL)
-        break;
-
-      if (m_pStateName[k] == '\0') {
-        m_pState = current;  
-        break;
-      }
-    }
-    
-    if (m_pState)
+  IfState* context_state = NULL;
+  for(int i = CONTEXT.GetCount() - 1; i >= 0; i--)
+    if (CONTEXT[i]->IsState()) {
+      context_state = (IfState*) CONTEXT[i];
       break;
-  }
-
-   *
-   *
-   */
+    }
   
-  IfState* top = ((IfProcessEntity*) CONTEXT[1])->GetEntry();
-
-  m_pState = top->Find(m_pStateName);
+  m_pState = context_state->FindVisible(m_pStateName);
   
   ok &= m_pState != NULL;
       
diff --git a/src/model/state.C b/src/model/state.C
index 203541d..007ef79 100644
--- a/src/model/state.C
+++ b/src/model/state.C
@@ -96,6 +96,37 @@ IfState* IfState::Find(const char* Name) const {
   return state;
 }
 
+IfState* IfState::FindVisibleRec(const char* Name) const {
+  IfState* state = NULL;
+  if (!strcmp(m_pName, Name))
+    state = (IfState*) this;
+  if (!state && !IsConcurrent())
+    for(int i = 0; i < m_pStates->GetCount() && !state; i++)
+      state = m_pStates->GetAt(i)->FindVisibleRec(Name);
+  return state;
+}
+
+IfState* IfState::FindVisible(const char* Name) const {
+  IfState* state = NULL;
+  if (!strcmp(m_pName, Name))
+    state = (IfState*) this;
+  if (!state && m_pParent != NULL && !m_pParent->IsConcurrent())
+    for(int i = 0; i < m_pParent->GetStates()->GetCount() && !state; i++) {
+      IfState* brother = m_pParent->GetStates()->GetAt(i);
+      if (!strcmp(brother->GetName(), Name))
+	state = brother;
+    }
+  if (!state)
+    state = this->FindVisibleRec(Name);
+  if (!state && m_pParent != NULL && !m_pParent->IsConcurrent()) {
+    IfState* ancestor = m_pParent;
+    while (ancestor->m_pParent != NULL && !ancestor->m_pParent->IsConcurrent())
+      ancestor = ancestor->m_pParent;
+    state = ancestor->FindVisibleRec(Name);
+  }
+  return state;
+}
+
 void IfState::Dump(FILE* file) const {
   fprintf(file, "%sstate %s%s%s%s%s%s;\n", indent(DEPTH), m_pName,
           IsStart() ? " #start " : "", 
diff --git a/src/model/state.h b/src/model/state.h
index 893060c..755f997 100644
--- a/src/model/state.h
+++ b/src/model/state.h
@@ -79,7 +79,8 @@ class IfState : public IfObject {
   inline IfAutomatonEntity* GetProcess() const { return m_pProcess; }
 
   IfState* Find(const char*) const;
-
+  IfState* FindVisible(const char*) const;
+  IfState* FindVisibleRec(const char*) const;
 
   virtual const char* GetClass() const 
     { return "state"; }
-- 
GitLab