From 73c9b6f282244fec2416c2d8764aef65691bc866 Mon Sep 17 00:00:00 2001
From: rschoene <rene.schoene@tu-dresden.de>
Date: Fri, 29 Nov 2019 15:29:13 +0100
Subject: [PATCH] Polishing.

- Cleanup build.gradle files
- Add circular reachability analysis
- Rename jrag with SCC to ConnectedComponents.jrag
- Add some documentation to attributes in Navigation aspect
- Add links to documentation for lexer and parser
---
 ragdoc-view/.gitignore                        |  3 +-
 ragdoc-view/src/app/data                      |  1 +
 statemachine.base/build.gradle                | 70 +++++++---------
 .../src/main/jastadd/Analysis.jrag            | 14 +++-
 .../src/main/jastadd/ConnectedComponents.jrag | 67 +++++++++++++++
 .../src/main/jastadd/Navigation.jrag          |  5 ++
 .../src/main/jastadd/Reachability.jrag        | 83 -------------------
 .../main/jastadd/StateMachineParser.parser    |  1 +
 .../src/main/jastadd/StateMachineScanner.flex |  1 +
 statemachine.drast/build.gradle               | 21 ++---
 10 files changed, 122 insertions(+), 144 deletions(-)
 create mode 120000 ragdoc-view/src/app/data
 create mode 100644 statemachine.base/src/main/jastadd/ConnectedComponents.jrag
 delete mode 100644 statemachine.base/src/main/jastadd/Reachability.jrag

diff --git a/ragdoc-view/.gitignore b/ragdoc-view/.gitignore
index 5198bf6..a2cbcea 100644
--- a/ragdoc-view/.gitignore
+++ b/ragdoc-view/.gitignore
@@ -1,6 +1,7 @@
 # See http://help.github.com/ignore-files/ for more about ignoring files.
 
-/src/data/
+!/src/data
+/src/data/*
 
 # compiled output
 /dist
diff --git a/ragdoc-view/src/app/data b/ragdoc-view/src/app/data
new file mode 120000
index 0000000..33f7f5e
--- /dev/null
+++ b/ragdoc-view/src/app/data
@@ -0,0 +1 @@
+../../../statemachine.base/build/docs/ragdoc/
\ No newline at end of file
diff --git a/statemachine.base/build.gradle b/statemachine.base/build.gradle
index c549365..9657cfb 100644
--- a/statemachine.base/build.gradle
+++ b/statemachine.base/build.gradle
@@ -1,3 +1,4 @@
+// General configuration (plugins, settings, dependencies)
 group 'de.tudresden.inf.st'
 version '0.1'
 
@@ -8,25 +9,24 @@ apply plugin: "idea"
 
 sourceCompatibility = 1.8
 
-repositories {
-    mavenCentral()
-}
+repositories.mavenCentral()
 
-idea {
-    module {
-        generatedSourceDirs += file('src/gen/java')
+buildscript {
+    repositories.mavenLocal()
+    repositories.mavenCentral()
+    dependencies {
+        classpath group: 'org.jastadd', name: 'jastaddgradle', version: '1.13.3'
     }
 }
 
+idea.module.generatedSourceDirs += file('src/gen/java')
+
 configurations {
     ragdoc
 }
 
-sourceSets {
-    main {
-        java.srcDir "src/gen/java"
-    }
-}
+sourceSets.main.java.srcDir "src/gen/java"
+jar.manifest.attributes('Main-Class': 'de.tudresden.inf.st.statemachine.Main')
 
 dependencies {
     implementation group: 'com.fasterxml.jackson.core', name: 'jackson-databind', version: "${jackson_version}"
@@ -36,39 +36,17 @@ dependencies {
     ragdoc files('../libs/rd-builder.jar')
 }
 
+// Default run configuration
 run {
     mainClassName = 'de.tudresden.inf.st.statemachine.Main'
     standardInput = System.in
 }
 
-buildscript {
-    repositories.mavenLocal()
-    repositories.mavenCentral()
-    dependencies {
-        classpath group: 'org.jastadd', name: 'jastaddgradle', version: '1.13.3'
-    }
-}
-
-jar {
-    manifest {
-        attributes(
-                'Main-Class': 'de.tudresden.inf.st.statemachine.Main'
-        )
-    }
-}
-
+// Generated files
 def ecoreFile = "./src/main/resources/StateMachine.ecore"
 def relastFile = "./src/gen/jastadd/StateMachine.relast"
-String[] relastArguments = [
-        "../libs/relast.jar",
-        "--grammarName=./src/gen/jastadd/StateMachine",
-        "--useJastAddNames",
-        "--listClass=ArrayList",
-        "--jastAddList=JastAddList",
-        "--resolverHelper",
-        "--file"
-]
 
+// First phase: Ecore -> RelAst
 task ecoreToRelast(type: JavaExec) {
     group = 'Build'
     main = "-jar"
@@ -85,16 +63,25 @@ task ecoreToRelast(type: JavaExec) {
     outputs.files file(relastFile)
 }
 
-task preprocess(type: JavaExec) {
+// Second phase: RelAst -> JastAdd
+task relastToJastAdd(type: JavaExec) {
     group = 'Build'
     main = "-jar"
 
-    args relastArguments + relastFile
+    args "../libs/relast.jar",
+            "--grammarName=./src/gen/jastadd/StateMachine",
+            "--useJastAddNames",
+            "--listClass=ArrayList",
+            "--jastAddList=JastAddList",
+            "--resolverHelper",
+            "--file",
+            relastFile
 
     inputs.files relastFile
     outputs.files file("./src/gen/jastadd/StateMachine.ast"), file("./src/gen/jastadd/StateMachine.jadd")
 }
 
+// Third phase: JastAdd -> Java (using JastAdd Gradle plugin)
 jastadd {
     configureModuleBuild()
     modules {
@@ -144,11 +131,12 @@ jastadd {
     scanner.genDir = "src/gen/java/de/tudresden/inf/st/statemachine/jastadd/scanner"
     parser.genDir = "src/gen/java/de/tudresden/inf/st/statemachine/jastadd/parser"
 
-    jastaddOptions = ['--List=JastAddList']
+    extraJastAddOptions = ['--List=JastAddList']
 }
 
-preprocess.dependsOn ecoreToRelast
-generateAst.dependsOn preprocess
+// Workflow configuration for phases
+relastToJastAdd.dependsOn ecoreToRelast
+generateAst.dependsOn relastToJastAdd
 
 //// always run jastadd
 //jastadd.outputs.upToDateWhen {false}
diff --git a/statemachine.base/src/main/jastadd/Analysis.jrag b/statemachine.base/src/main/jastadd/Analysis.jrag
index 872fa7c..fd38416 100644
--- a/statemachine.base/src/main/jastadd/Analysis.jrag
+++ b/statemachine.base/src/main/jastadd/Analysis.jrag
@@ -1,5 +1,5 @@
 aspect Analysis {
-  syn Set<State> State.reachableWithin(int n) { //circular [new HashSet<>()]
+  syn Set<State> State.reachableWithin(int n) {
     if (n == 0) {
       return new HashSet<>();
     }
@@ -11,8 +11,16 @@ aspect Analysis {
     return result;
   }
 
+  syn Set<State> State.reachable() circular [new HashSet<State>()] {
+    Set<State> result = new HashSet<>();
+    result.addAll(successors());
+    for (State s : successors()) {
+      result.addAll(s.reachable());
+    }
+    return result;
+  }
+
   public void StateMachine.printSomeAnalysis() {
-    // analysis
     Set<Set<State>> sccs = this.SCC();
     System.out.println("SCCs found:");
     for (Set<State> scc : sccs) {
@@ -20,7 +28,7 @@ aspect Analysis {
     }
 
     for (State s : this.states()) {
-      System.out.println(s + ".successors() = " + s.successors());
+      System.out.println(s + ": successors() = " + s.successors() + ", reachable() = " + s.reachable());
     }
 
     Set<State> current;
diff --git a/statemachine.base/src/main/jastadd/ConnectedComponents.jrag b/statemachine.base/src/main/jastadd/ConnectedComponents.jrag
new file mode 100644
index 0000000..406e5f5
--- /dev/null
+++ b/statemachine.base/src/main/jastadd/ConnectedComponents.jrag
@@ -0,0 +1,67 @@
+aspect ConnectedComponents {
+//  syn Set<State> State.successors() circular [new HashSet<>()] {
+//    Set<State> result = new HashSet<>();
+//    for (Transition t : getOutgoingList()) {
+//      State s = t.getTo();
+//      result.add(s);
+//      result.addAll(s.successors());
+//    }
+//    return result;
+//  }
+
+//  syn Set<State> State.predecessors() circular [new HashSet<>()] {
+//    Set<State> result = new HashSet<>();
+//    for (Transition t : getIncomingList()) {
+//      State s = t.getFrom();
+//      result.add(s);
+//      result.addAll(s.predecessors());
+//    }
+//    return result;
+//  }
+
+//  syn boolean State.hasCycle() = successors().contains(this);
+
+//  syn Set<State> State.SCC() {
+//    Set<State> result = new HashSet<>(successors());
+//    result.retainAll(predecessors());
+//    return result;
+//  }
+
+//  coll HashSet<Set<State>> StateMachine.SCC() with add root StateMachine;
+//  State contributes SCC() when SCC().size() > 0 to StateMachine.SCC();
+
+  /**
+   * Kosaraju's algorithm
+   */
+  syn Set<Set<State>> StateMachine.SCC() {
+    Map<State, Set> visited = new HashMap<>();
+    LinkedList<State> locked = new LinkedList<>();
+
+    for (State n : states())
+      if (!visited.containsKey(n))
+        n.visit(visited, locked);              // forward search
+
+    for (State n : locked)
+      if (visited.get(n) == null)
+        n.assign(visited, new HashSet());      // backward search
+
+    return new HashSet(visited.values());
+  }
+
+  void State.visit(Map<State, Set> visited, LinkedList<State> locked) {
+    visited.put(this, null);
+    for (Transition t : getOutgoingList())
+      if (!visited.containsKey(t.getTo()))
+        t.getTo().visit(visited, locked);
+    locked.addFirst(this);
+  }
+
+  void State.assign(Map<State, Set> visited, Set root) {
+    root.add(this);
+    visited.put(this, root);
+    for (Transition t : getIncomingList())
+      if (visited.get(t.getFrom()) == null)
+        t.getFrom().assign(visited, root);
+  }
+
+}
diff --git a/statemachine.base/src/main/jastadd/Navigation.jrag b/statemachine.base/src/main/jastadd/Navigation.jrag
index 0ccd14a..8aa18c0 100644
--- a/statemachine.base/src/main/jastadd/Navigation.jrag
+++ b/statemachine.base/src/main/jastadd/Navigation.jrag
@@ -1,17 +1,22 @@
 aspect Navigation {
 
+  /** Check, whether an this element is a state */
   syn boolean Element.isState() = false;
   eq State.isState() = true;
 
+  /** View this element as a state */
   syn State Element.asState() = null;
   eq State.asState() = this;
 
+  /** Check, whether an this element is a transition */
   syn boolean Element.isTransition() = false;
   eq Transition.isTransition() = true;
 
+  /** View this element as a transition */
   syn Transition Element.asTransition() = null;
   eq Transition.asTransition() = this;
 
+  /** Get all states */
   syn List<State> StateMachine.states() {
     List<State> states = new ArrayList<>();
     for (Element element: getElementList()) {
diff --git a/statemachine.base/src/main/jastadd/Reachability.jrag b/statemachine.base/src/main/jastadd/Reachability.jrag
deleted file mode 100644
index 1d4fc9c..0000000
--- a/statemachine.base/src/main/jastadd/Reachability.jrag
+++ /dev/null
@@ -1,83 +0,0 @@
-aspect Reachability {
-//  syn Set<State> State.successors() circular [new HashSet<>()] {
-//    Set<State> result = new HashSet<>();
-//    for (Transition t : getOutgoingList()) {
-//      State s = t.getTo();
-//      result.add(s);
-//      result.addAll(s.successors());
-//    }
-//    return result;
-//  }
-
-//  syn Set<State> State.predecessors() circular [new HashSet<>()] {
-//    Set<State> result = new HashSet<>();
-//    for (Transition t : getIncomingList()) {
-//      State s = t.getFrom();
-//      result.add(s);
-//      result.addAll(s.predecessors());
-//    }
-//    return result;
-//  }
-
-//  syn boolean State.hasCycle() = successors().contains(this);
-
-//  syn Set<State> State.SCC() {
-//    Set<State> result = new HashSet<>(successors());
-//    result.retainAll(predecessors());
-//    return result;
-//  }
-
-//  coll HashSet<Set<State>> StateMachine.SCC() with add root StateMachine;
-//  State contributes SCC() when SCC().size() > 0 to StateMachine.SCC();
-
-
-  /**
-   * Kosaraju's algorithm
-   */
-  syn Set<Set<State>> StateMachine.SCC(){
-    Map<State, Integer> visited = new HashMap<>();
-    Deque<State> locked = new LinkedList<>();
-
-    // visit nodes forward
-    for (Element e : getElementList()){
-      if (e.isState()){
-      	State n=e.asState();
-      	n.visit(visited, locked);
-      }
-		}
-    // assign nodes to SCCs backward
-    int scc = 0;
-    for (State n : locked) {
-      n.assign(visited, scc);
-      scc++;
-    }
-
-    Map<Integer, Set<State>> result = visited.entrySet().stream().collect(
-            Collectors.groupingBy(
-                e -> e.getValue(),
-                Collectors.mapping(e -> e.getKey(), Collectors.toSet())
-            )
-        );
-    return result.values().stream().collect(Collectors.toSet());
-  }
-
-  void State.visit(Map<State, Integer> visited, Deque<State> locked) {
-    if (visited.containsKey(this)) return;
-    visited.put(this, -1);
-    for (Transition t : getOutgoingList()) {
-      State s = t.getTo();
-      s.visit(visited, locked);
-    }
-    locked.addFirst(this);
-  }
-
-  void State.assign(Map<State, Integer> visited, int root) {
-    if (visited.get(this) > -1) return;
-    visited.put(this, root);
-    for (Transition t : getIncomingList()) {
-      State p = t.getFrom();
-      p.assign(visited, root);
-    }
-  }
-
-}
diff --git a/statemachine.base/src/main/jastadd/StateMachineParser.parser b/statemachine.base/src/main/jastadd/StateMachineParser.parser
index 197392e..361e117 100644
--- a/statemachine.base/src/main/jastadd/StateMachineParser.parser
+++ b/statemachine.base/src/main/jastadd/StateMachineParser.parser
@@ -4,6 +4,7 @@ package de.tudresden.inf.st.statemachine.jastadd.parser;
 import de.tudresden.inf.st.statemachine.jastadd.model.*;
 import java.util.*;
 :};
+// Documentation links: http://beaver.sourceforge.net/spec.html and https://bitbucket.org/jastadd/jastaddparser
 
 %embed {:
  // this code is inlined in the generated parser class
diff --git a/statemachine.base/src/main/jastadd/StateMachineScanner.flex b/statemachine.base/src/main/jastadd/StateMachineScanner.flex
index ad86af4..547fb1a 100644
--- a/statemachine.base/src/main/jastadd/StateMachineScanner.flex
+++ b/statemachine.base/src/main/jastadd/StateMachineScanner.flex
@@ -2,6 +2,7 @@ package de.tudresden.inf.st.statemachine.jastadd.scanner;
 
 import de.tudresden.inf.st.statemachine.jastadd.parser.StateMachineParser.Terminals; // The terminals are implicitly defined in the parser
 %%
+// Documentation links: https://www.jflex.de/manual.html and http://beaver.sourceforge.net/scanners.html
 
 // define the signature for the generated scanner
 %public
diff --git a/statemachine.drast/build.gradle b/statemachine.drast/build.gradle
index 8fb4991..fcf3218 100644
--- a/statemachine.drast/build.gradle
+++ b/statemachine.drast/build.gradle
@@ -7,9 +7,7 @@ apply plugin: "idea"
 
 sourceCompatibility = 1.8
 
-repositories {
-    mavenCentral()
-}
+repositories.mavenCentral()
 
 dependencies {
 	implementation project(':statemachine.base')
@@ -17,10 +15,14 @@ dependencies {
     implementation fileTree(dir: "${System.properties['java.home']}", include: '**/jfxrt.jar')
 }
 
+sourceSets.main.java.srcDir "src/main/java"
+
 run {
     mainClassName = 'de.tudresden.inf.st.statemachine.DrAstRunner'
     standardInput = System.in
 }
+run.dependsOn ':statemachine.base:jar'
+run.doFirst { environment 'JAVA_TOOL_OPTIONS', '-Dlog4j2.disableJmx=true' }
 
 task jarDrAst(type: Jar, dependsOn: ':statemachine.base:jar') {
     group = "build"
@@ -34,16 +36,3 @@ task jarDrAst(type: Jar, dependsOn: ':statemachine.base:jar') {
     from { sourceSets.main.runtimeClasspath.collect { it.isDirectory() ? it : zipTree(it) } }
     with jar
 }
-
-task runDrAST(type: JavaExec, dependsOn: [jar, ':statemachine.base:jar']) {
-    group = "application"
-    description = 'run the DrAST visual debugger tool'
-    classpath = sourceSets.main.runtimeClasspath
-    main = 'de.tudresden.inf.st.statemachine.DrAstRunner'
-}
-
-sourceSets {
-    main {
-        java.srcDir "src/main/java"
-    }
-}
-- 
GitLab