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