From a2f1ff3d5a61e9de92e095bb3ca6c314a4ca0afe Mon Sep 17 00:00:00 2001 From: Johannes Mey <johannes.mey@tu-dresden.de> Date: Thu, 2 Jan 2020 00:27:42 +0100 Subject: [PATCH] initial version of modelica, analysis currently empty --- scope4m/.gitignore | 27 ++++ scope4m/build.gradle | 145 ++++++++++++++++++ scope4m/src/gen-res/BuildInfo.properties | 7 + scope4m/src/main/jastadd/ASTPrinting.jadd | 50 ++++++ scope4m/src/main/jastadd/Helpers.jadd | 19 +++ .../src/main/jastadd/ModelicaToScopeTree.jrag | 12 ++ .../main/jastadd/ModelicaToScopeTree.relast | 2 + .../java/org/jmodelica/ScopeAnalysis.java | 143 +++++++++++++++++ settings.gradle | 2 + 9 files changed, 407 insertions(+) create mode 100644 scope4m/.gitignore create mode 100644 scope4m/build.gradle create mode 100644 scope4m/src/gen-res/BuildInfo.properties create mode 100644 scope4m/src/main/jastadd/ASTPrinting.jadd create mode 100644 scope4m/src/main/jastadd/Helpers.jadd create mode 100644 scope4m/src/main/jastadd/ModelicaToScopeTree.jrag create mode 100644 scope4m/src/main/jastadd/ModelicaToScopeTree.relast create mode 100644 scope4m/src/main/java/org/jmodelica/ScopeAnalysis.java diff --git a/scope4m/.gitignore b/scope4m/.gitignore new file mode 100644 index 0000000..d8bcc39 --- /dev/null +++ b/scope4m/.gitignore @@ -0,0 +1,27 @@ +# Compiled class file +*.class + +# Log file +*.log + +# Package Files # +*.jar +*.war +*.nar +*.ear +*.zip +*.tar.gz +*.rar + +# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml +hs_err_pid* + +out/ +*.iml +/.idea/* +!.idea/codeStyles +!libs/relast.jar + +graph/ +src/gen/ +build/ diff --git a/scope4m/build.gradle b/scope4m/build.gradle new file mode 100644 index 0000000..e49253b --- /dev/null +++ b/scope4m/build.gradle @@ -0,0 +1,145 @@ +buildscript { + repositories.mavenLocal() + repositories.mavenCentral() + dependencies { + classpath 'org.jastadd:jastaddgradle:1.13.3' + } +} + +apply plugin: 'java' +apply plugin: 'application' +apply plugin: 'jastadd' +apply plugin: 'idea' + +repositories { + mavenLocal() +} + +idea { + module { + generatedSourceDirs += file('./src/gen/java') + sourceDirs += file('../jmodelica/src/main/java') + } +} + +test { + useJUnitPlatform {} +} + +sourceSets.main { + java { + srcDir 'src/gen/java' + srcDir '../jmodelica/src/main/java' + } + resources { + srcDir '../jmodelica/src/main/resources' + srcDir jastadd.buildInfoDir + } +} + +dependencies { + compile group: 'net.sf.beaver', name: 'beaver-rt', version: '0.9.11' + compile group: 'junit', name: 'junit', version: '4.12' + testImplementation 'org.junit.jupiter:junit-jupiter-api:5.4.2' + testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.4.2' + testCompile 'org.junit.platform:junit-platform-runner:1.4.2' + testImplementation 'org.junit.jupiter:junit-jupiter-params:5.4.2' +} + +jastadd { + configureModuleBuild() + + modules { + include("../jmodelica/jastadd_modules") + + module "dependencyanalysis", { + + imports "jmodelica" + + jastadd { + basedir ".." + include "scope4m/src/gen/jastadd/Modelica.ast" + include "scope4m/src/gen/jastadd/Modelica.jadd" + include "scope4m/src/main/jastadd/*.jrag" + include "scope4m/src/main/jastadd/*.jadd" + include "scope/src/main/jastadd/*.jrag" + include "scope/src/main/jastadd/*.jadd" + + excludeFrom "jmodelica", "ast/BaseAST.ast" + excludeFrom "jmodelica", "ast/Error.ast" + excludeFrom "jmodelica", "ast/Modelica.ast" + } + + java { + basedir "src/main/java/" + include "**/*.java" + excludeFrom "jmodelica", "gen/java/**/*.java" + } + + } + + } + + + + buildInfoDir = 'src/gen-res' + + // Target module to build: + module = 'dependencyanalysis' + + astPackage = 'org.jmodelica.compiler' + parser.name = 'ModelicaParser' + scanner.name = 'OriginalScanner' + + genDir = 'src/gen/java' + parser.genDir = 'src/gen/java/org/jmodelica/parser' + scanner.genDir = 'src/gen/java/org/jmodelica/scanner' + + jastaddOptions = ["--rewrite=cnta", "--safeLazy", "--tracing=api", "--visitCheck=false"] +} + +run { + mainClassName = 'org.jmodelica.SimpleMain' +} + +task preprocess(type: JavaExec) { + group = 'Build' + main = "-jar" + + doFirst { + delete "src/gen/jastadd" + mkdir "src/gen/jastadd" + } + + args = [ + "../tools/relast.jar", + "src/main/jastadd/ModelicaToScopeTree.relast", + "../scope/src/main/jastadd/ScopeTree.relast", + "../jmodelica/src/main/jastadd/ast/BaseAST.ast", + "../jmodelica/src/main/jastadd/ast/Error.ast", + "../jmodelica/src/main/jastadd/ast/Modelica.ast", + "--listClass=ArrayList", + "--useJastAddNames", + "--file", + "--grammarName=src/gen/jastadd/Modelica" + ] + + inputs.files file("../tools/relast.jar"), + file("src/main/jastadd/ModelicaToScopeTree.relast"), + file("../scope/src/main/jastadd/ScopeTree.relast"), + file("../jmodelica/src/main/jastadd/ast/BaseAST.ast"), + file("../jmodelica/src/main/jastadd/ast/Error.ast"), + file("../jmodelica/src/main/jastadd/ast/Modelica.ast") + outputs.files file("src/gen/jastadd/Modelica.ast") + file("src/gen/jastadd/Modelica.jadd") +} + + +generateAst.dependsOn preprocess + +mainClassName = 'org.jmodelica.ScopeAnalysis' +jar.manifest.attributes 'Main-Class': mainClassName +jar.destinationDirectory = projectDir + +sourceCompatibility = '1.8' +targetCompatibility = '1.8' diff --git a/scope4m/src/gen-res/BuildInfo.properties b/scope4m/src/gen-res/BuildInfo.properties new file mode 100644 index 0000000..15116f7 --- /dev/null +++ b/scope4m/src/gen-res/BuildInfo.properties @@ -0,0 +1,7 @@ +#Thu, 02 Jan 2020 00:10:22 +0100 + +moduleId=dependencyanalysis +moduleName=null +moduleVariant=null +timestamp=2020-01-02T00\:10Z +build.date=2020-01-02 diff --git a/scope4m/src/main/jastadd/ASTPrinting.jadd b/scope4m/src/main/jastadd/ASTPrinting.jadd new file mode 100644 index 0000000..0864144 --- /dev/null +++ b/scope4m/src/main/jastadd/ASTPrinting.jadd @@ -0,0 +1,50 @@ +aspect Debugging { + + public String ASTNode.getASTString() { + + String result = this.getClass().getSimpleName() + "\n"; + + for (java.lang.reflect.Method method : this.getClass().getMethods()) { + ASTNodeAnnotation.Token annotation = method.getAnnotation(ASTNodeAnnotation.Token.class); + if (annotation != null) { + try { + String name = annotation.name(); + if (name.startsWith("_impl_")) { + name = "rel " + name.substring(6) + " -> "; + } else { + name += ":= "; + } + result += "|--" + name + method.invoke(this); + } catch (IllegalAccessException e) { + e.printStackTrace(); + } catch (java.lang.reflect.InvocationTargetException e) { + e.printStackTrace(); + } + result += "\n"; + } + } + + for(int childIndex = 0; childIndex < getNumChildNoTransform(); childIndex++) { + + ASTNode<?> child = getChildNoTransform(childIndex); + String childString = "NULL\n"; + if(child != null) { + childString = child.getASTString(); + } + + if(childIndex < getNumChildNoTransform() - 1) { + childString = childString.replaceAll("(?m)^", "| "); + } else { + childString = childString.replaceAll("(?m)^", " "); + } + + result += "|\n|--" + childString.substring(3); + } + + return result; + } + + public void ASTNode.printAST() { + System.out.println(getASTString()); + } +} diff --git a/scope4m/src/main/jastadd/Helpers.jadd b/scope4m/src/main/jastadd/Helpers.jadd new file mode 100644 index 0000000..3e171a6 --- /dev/null +++ b/scope4m/src/main/jastadd/Helpers.jadd @@ -0,0 +1,19 @@ +/** copy of the extendj source location interface */ +aspect SourceLocation { + + protected String ASTNode.sourceFile() { + return retrieveFileName(); + } + + syn int ASTNode.lineNumber() { + ASTNode n = this; + while (n.getParent() != null && n.getStart() == 0) { + n = n.getParent(); + } + return getLine(n.getStart()); + } + + public String ASTNode.sourceLocation() { + return sourceFile() + ":" + lineNumber(); + } +} diff --git a/scope4m/src/main/jastadd/ModelicaToScopeTree.jrag b/scope4m/src/main/jastadd/ModelicaToScopeTree.jrag new file mode 100644 index 0000000..b3c375d --- /dev/null +++ b/scope4m/src/main/jastadd/ModelicaToScopeTree.jrag @@ -0,0 +1,12 @@ +aspect ModelicaToScopeTree { + syn lazy ScopeTree SourceRoot.scopeTree() { + ScopeTree tree = new ScopeTree(); + tree.setSourceRoot(this); + + return tree; + } +} + +aspect ScopeGenerationAttributes { + +} diff --git a/scope4m/src/main/jastadd/ModelicaToScopeTree.relast b/scope4m/src/main/jastadd/ModelicaToScopeTree.relast new file mode 100644 index 0000000..4c47dbc --- /dev/null +++ b/scope4m/src/main/jastadd/ModelicaToScopeTree.relast @@ -0,0 +1,2 @@ +// glue relation for the Java-based variable shadowing analysis +rel ScopeTree.SourceRoot -> SourceRoot; diff --git a/scope4m/src/main/java/org/jmodelica/ScopeAnalysis.java b/scope4m/src/main/java/org/jmodelica/ScopeAnalysis.java new file mode 100644 index 0000000..f7ce25d --- /dev/null +++ b/scope4m/src/main/java/org/jmodelica/ScopeAnalysis.java @@ -0,0 +1,143 @@ +package org.jmodelica; + + +import beaver.Parser; +import org.jmodelica.compiler.*; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.List; +import java.util.*; +import java.util.stream.Collectors; +import org.jmodelica.util.exceptions.CompilerException; + +public class ScopeAnalysis { + + + + public SourceRoot getSourceRoot() { + return sourceRoot; + } + + private SourceRoot sourceRoot; + + /** + * Entry point for the Java checker. + * + * @param args command-line arguments + */ + public static void main(String[] args) { + + List<String> arguments = new ArrayList<>(Arrays.asList(args)); + + boolean debug = arguments.isEmpty() || arguments.remove("--debug"); + boolean tree = arguments.remove("--tree"); + boolean warnings = arguments.remove("--warnings"); + + if (arguments.size() > 1) { + System.out.println("usage: ScopeAnalysis [--debug] [--tree] [--warnings] <directory with java files>"); + System.exit(-1); + } + String path = arguments.isEmpty() ? "../testprograms/modelica" : arguments.get(arguments.size() - 1); + + if (debug) { + new ScopeAnalysis().analyze(path, tree, warnings); + } else { + new ScopeAnalysis().analyzeTimed(path); + } + + } + + public void analyzeTimed(String path) { + try { + List<String> files = Files.walk(Paths.get(path)) + .filter(Files::isRegularFile) + .filter(x -> x.getFileName().toString().endsWith(".mo")).map(Path::toString).collect(Collectors.toList()); + + // measure the time (with parsing) from here + long startMeasurementTime = System.nanoTime(); + + sourceRoot = readProgram(files); + + // measure the time (without parsing) from here + long startGenerationTime = System.nanoTime(); + + ScopeTree scopeTree = sourceRoot.scopeTree(); + + long startAnalysisTime = System.nanoTime(); + + Set<AbstractFinding> findings = scopeTree.variableShadowings(); + + // measure the time until here + long endTime = System.nanoTime(); + + System.out.print("modelica,inner,false," + + files.size() + "," + + scopeTree.numScopes() + "," + + scopeTree.numDeclarations() + "," + + (scopeTree.numScopes() + scopeTree.numDeclarations()) + "," + + findings.size() + ","); + + long parseTime = startGenerationTime - startMeasurementTime; + long generationTime = startAnalysisTime - startGenerationTime; + long analysisTime = endTime - startAnalysisTime; + long fullTime = endTime - startMeasurementTime; + + System.out.print((fullTime / 1000000) + ","); + System.out.print((parseTime / 1000000) + ","); + System.out.print((generationTime / 1000000) + ","); + System.out.print((analysisTime / 1000000) + ","); + System.out.print(((generationTime + analysisTime) / 1000000) + ","); + + } catch (IOException | Parser.Exception | CompilerException e) { + throw new RuntimeException(e); + } + } + + + public Set<AbstractFinding> analyze(String path, boolean tree, boolean warnings) { + try { + List<String> files = Files.walk(Paths.get(path)) + .filter(Files::isRegularFile) + .filter(x -> x.getFileName().toString().endsWith(".mo")).map(Path::toString).collect(Collectors.toList()); + + sourceRoot = readProgram(files); + + ScopeTree scopeTree = sourceRoot.scopeTree(); + + if (tree) { + scopeTree.printAST(); + + } + + // TODO just temp debug output: + sourceRoot.printAST(); + + if (warnings) { + // TODO find out if there are compiler warnings in JModelica + } + + Set<AbstractFinding> findings = scopeTree.variableShadowings(); + + System.out.println("\nScope4J found the following problems:"); + for (AbstractFinding finding : findings) { + System.out.println(finding); + } + System.out.println(); + + return findings; + } catch (IOException | Parser.Exception | CompilerException e) { + throw new RuntimeException(e); + } + } + + private static SourceRoot readProgram(Collection<String> files) throws IOException, beaver.Parser.Exception, CompilerException { + + + ModelicaCompiler mc = new ModelicaCompiler(ModelicaCompiler.createOptions()); + return mc.getParserHandler().parseModel(UtilInterface.create(mc), (files.toArray(new String[]{}))); + + } +} diff --git a/settings.gradle b/settings.gradle index 2dfdf27..5dc7447 100644 --- a/settings.gradle +++ b/settings.gradle @@ -11,10 +11,12 @@ rootProject.name = 'relast-reuse' include 'statemachine' include 'extendj' +include 'jmodelica' include 'dg' include 'deps4j' include 'scope' include 'scope4j' +include 'scope4m' include 'simplecfg' include 'extendj:java4' include 'extendj:java5' -- GitLab