diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 88907420eabc71f41a10b13cd76de0738cf2d5df..71fba4155eb9ee80538e42b1746c79a1f19b0ede 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -2,11 +2,10 @@ variables: GIT_SUBMODULE_STRATEGY: recursive stages: - - build - test - ragdoc_build - ragdoc_view - - publish + - deploy before_script: - export GRADLE_USER_HOME=`pwd`/.gradle @@ -16,24 +15,46 @@ cache: - .gradle/wrapper - .gradle/caches -build: - image: openjdk:8 - stage: build +## Hidden jobs, base configurations +.test: + image: openjdk:11 + stage: test script: - - ./gradlew --console=plain --no-daemon assemble + - ./gradlew --console=plain --no-daemon test artifacts: + reports: + junit: build/test-results/test/**/TEST-*.xml paths: - "src/gen" expire_in: 1 week -test: - image: openjdk:8 - stage: test +.publish_dev: + image: openjdk:11 + stage: deploy script: - - ./gradlew --console=plain --no-daemon test - artifacts: - reports: - junit: build/test-results/test/**/TEST-*.xml + - "./gradlew setDevVersionForCI" + - "./gradlew publish" + +## Real jobs +test8: + extends: .test + image: "openjdk:8" + +test11: + extends: .test + image: "openjdk:11" + +publish_dev8: + extends: .publish_dev + image: "openjdk:8" + needs: + - test8 + +publish_dev11: + extends: .publish_dev + image: "openjdk:11" + needs: + - test11 ragdoc_build: image: @@ -41,10 +62,12 @@ ragdoc_build: entrypoint: [""] stage: ragdoc_build needs: - - build + - test8 script: - JAVA_FILES=$(find src/ -name '*.java') - /ragdoc-builder/start-builder.sh -excludeGenerated -d data/ $JAVA_FILES + only: + - master artifacts: paths: - "data/" @@ -62,23 +85,24 @@ ragdoc_view: - OUTPUT_DIR=$(pwd -P)/pages/docs/ragdoc - cd /ragdoc-view/src/ && rm -rf data && ln -s $DATA_DIR - /ragdoc-view/build-view.sh --output-path=$OUTPUT_DIR + only: + - master artifacts: paths: - "pages/docs/ragdoc" pages: image: python:3.8-buster - stage: publish + stage: deploy needs: - ragdoc_view - - test + - test8 before_script: - pip install -U mkdocs mkdocs-macros-plugin mkdocs-git-revision-date-localized-plugin script: - cd pages && mkdocs build -# only: -# - develop -# - master + only: + - master artifacts: paths: - public diff --git a/.gitmodules b/.gitmodules index 7f348667c77aac1df614eddfa1721935c68dddcf..69c2eebb1346bd35222841bfde7ebea1a182f7c5 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,4 @@ [submodule "src/main/jastadd/mustache"] path = src/main/jastadd/mustache url = ../mustache.git + branch = main diff --git a/build-template.gradle b/build-template.gradle deleted file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000 diff --git a/build.gradle b/build.gradle index cc16a72d97cc4efff8a2a44fcba801746c912d07..32a4835d54d57e38279258795fd60930c5c75499 100644 --- a/build.gradle +++ b/build.gradle @@ -1,9 +1,11 @@ plugins { + id 'com.github.ben-manes.versions' version '0.42.0' id 'java-library' id 'application' - id 'org.jastadd' + id 'org.jastadd' version "${jastaddgradle_version}" id 'java' id 'idea' + id 'maven-publish' id 'java-test-fixtures' } @@ -11,14 +13,23 @@ ext { mainClassName = 'org.jastadd.relast.compiler.RelastSourceToSourceCompiler' } +group = 'org.jastadd' + // set the main class name for `gradle run` application.mainClassName = "${mainClassName}" -sourceCompatibility = 1.8 -targetCompatibility = 1.8 - repositories { mavenCentral() + maven { + name 'gitlab-maven' + url 'https://git-st.inf.tu-dresden.de/api/v4/groups/jastadd/-/packages/maven' + } +} + +configurations { + grammar2uml + relast + jss } sourceSets { @@ -27,33 +38,65 @@ sourceSets { srcDir "src/gen/java" } } + main { + compileClasspath += sourceSets.model.output + resources { + srcDir "src/main/jastadd" + } + } + test { + runtimeClasspath += sourceSets.model.output + } +} + +File genSrc = file("src/gen/java") +idea.module.generatedSourceDirs += genSrc + +def versionFile = 'src/main/resources/RelASTPreprocessorVersion.properties' +def oldProps = new Properties() + +try { + file(versionFile).withInputStream { stream -> oldProps.load(stream) } + version = oldProps['version'] +} catch (ignored) { + // this happens, if either the properties file is not present, or cannot be read from + throw new GradleException("File ${versionFile} not found or unreadable. Aborting.") +} + +task newVersion() { + doFirst { + def props = new Properties() + props['version'] = value + props.store(file(versionFile).newWriter(), null) + } } -task modelJar(type: Jar) { - group = "build" - archiveBaseName = 'model' - archiveVersion = '' - from sourceSets.model.output +task printVersion() { + doLast { + println(version) + } } -artifacts { - archives modelJar +task setDevVersionForCI() { + doFirst { + def props = new Properties() + props['version'] = version + "-$System.env.CI_PIPELINE_IID" + props.store(file(versionFile).newWriter(), null) + } } dependencies { - modelImplementation group: 'org.jastadd', name: 'jastadd', version: '2.3.4' modelImplementation group: 'net.sf.beaver', name: 'beaver-rt', version: '0.9.11' - implementation files(modelJar.archiveFile.get()) - api group: 'org.jastadd', name: 'jastadd', version: '2.3.4' + grammar2uml group: 'de.tudresden.inf.st', name: 'grammar2uml', version: "${grammar2uml_version}" + relast group: 'org.jastadd', name: 'relast', version: "${relast_version}" + + api group: 'org.jastadd', name: 'jastadd', version: '2.3.5' api group: 'net.sf.beaver', name: 'beaver-rt', version: '0.9.11' - implementation group: 'com.github.jknack', name: 'handlebars', version: '4.2.0' + implementation group: 'com.github.jknack', name: 'handlebars', version: '4.3.0' implementation group: 'org.yaml', name: 'snakeyaml', version: '1.27' - // test - testRuntimeClasspath files(modelJar.archiveFile.get()) - // test fixtures testFixturesApi group: 'org.slf4j', name: 'slf4j-jdk14', version: '1.7.30' testFixturesApi group: 'org.junit.jupiter', name: 'junit-jupiter-engine', version: '5.7.0' @@ -64,25 +107,8 @@ dependencies { testFixturesApi group: 'commons-io', name: 'commons-io', version: '2.8.0' } -def versionFile = 'src/main/resources/preprocessor.properties' -def versionProps = new Properties() - -try { - file(versionFile).withInputStream { stream -> versionProps.load(stream) } - version = versionProps['version'] -} catch (e) { - // this happens, if either the properties file is not present, or cannot be read from - throw new GradleException("File ${versionFile} not found or unreadable. Aborting.", e) -} - jar { - manifest { - attributes "Main-Class": "${mainClassName}" - } - - from { - configurations.runtimeClasspath.collect { it.isDirectory() ? it : zipTree(it) } - } + archiveAppendix = "base" } test { @@ -104,8 +130,9 @@ def relastOutputFiles = [ ] task relast(type: JavaExec) { - classpath = files("libs/relast.jar") group = 'Build' + classpath = configurations.relast + mainClass = 'org.jastadd.relast.compiler.Compiler' doFirst { delete relastOutputFiles @@ -184,12 +211,34 @@ jastadd { jastaddOptions = ["--lineColumnNumbers", "--List=JastAddList", "--safeLazy", "--visitCheck=true", "--rewrite=cnta", "--cache=all"] } -generateAst.dependsOn relast +// publish gitlab project +publishing { + publications { + maven(MavenPublication) { + artifactId = project.getName() + (JavaVersion.current() == JavaVersion.VERSION_1_8 ? '-java8' : '') -clean.dependsOn(cleanGen) + from components.java + } + } + repositories { + maven { + url "https://git-st.inf.tu-dresden.de/api/v4/projects/$System.env.CI_PROJECT_ID/packages/maven" + // Uncomment the following lines to publish manually (and comment out the other credentials section) +// credentials(HttpHeaderCredentials) { +// name = "Private-Token" +// value = gitLabPrivateToken // the variable resides in ~/.gradle/gradle.properties +// } + credentials(HttpHeaderCredentials) { + name = 'Job-Token' + value = System.getenv('CI_JOB_TOKEN') + } + authentication { + header(HttpHeaderAuthentication) + } + } -modelJar.dependsOn(generateAst, modelClasses) -modelClasses.dependsOn(generateAst) -compileJava.dependsOn(modelJar) + } +} -jar.dependsOn(modelJar) +generateAst.dependsOn relast +clean.dependsOn cleanGen diff --git a/gradle.properties b/gradle.properties new file mode 100644 index 0000000000000000000000000000000000000000..0e0cc086ffe4f79f86c59464b82fb53d4e99d4cb --- /dev/null +++ b/gradle.properties @@ -0,0 +1,6 @@ +relast_version = 0.4.0 +relast2uml_version = 0.3.7-59 +jupyter_version = 5.8.2 +assertj_version = 3.22.0 +grammar2uml_version = 0.2.1 +jastaddgradle_version = 1.14.5 diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index f3d88b1c2faf2fc91d853cd5d4242b5547257070..e708b1c023ec8b20f512888fe07c5bd3ff77bb8f 100644 Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index be52383ef49cdf484098989f96738b3d82d7810d..41dfb87909a877d96c3af4adccce4c7a301b55a2 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-6.7-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew index 2fe81a7d95e4f9ad2c9b2a046707d36ceb3980b3..4f906e0c811fc9e230eb44819f509cd0627f2600 100755 --- a/gradlew +++ b/gradlew @@ -82,6 +82,7 @@ esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + # Determine the Java command to use to start the JVM. if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then @@ -129,6 +130,7 @@ fi if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then APP_HOME=`cygpath --path --mixed "$APP_HOME"` CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + JAVACMD=`cygpath --unix "$JAVACMD"` # We build the pattern for arguments to be converted via cygpath diff --git a/gradlew.bat b/gradlew.bat index 24467a141f791695fc1009c78d913b2c849d1412..ac1b06f93825db68fb0c0b5150917f340eaa5d02 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -29,6 +29,9 @@ if "%DIRNAME%" == "" set DIRNAME=. set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" @@ -37,7 +40,7 @@ if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto init +if "%ERRORLEVEL%" == "0" goto execute echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. @@ -51,7 +54,7 @@ goto fail set JAVA_HOME=%JAVA_HOME:"=% set JAVA_EXE=%JAVA_HOME%/bin/java.exe -if exist "%JAVA_EXE%" goto init +if exist "%JAVA_EXE%" goto execute echo. echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% @@ -61,28 +64,14 @@ echo location of your Java installation. goto fail -:init -@rem Get command-line arguments, handling Windows variants - -if not "%OS%" == "Windows_NT" goto win9xME_args - -:win9xME_args -@rem Slurp the command line arguments. -set CMD_LINE_ARGS= -set _SKIP=2 - -:win9xME_args_slurp -if "x%~1" == "x" goto execute - -set CMD_LINE_ARGS=%* - :execute @rem Setup the command line set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + @rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* :end @rem End local scope for the variables with windows NT shell diff --git a/libs/relast.jar b/libs/relast.jar deleted file mode 100644 index 9f1d60c7c99a1e35d9cf5558d5f329c5aa7ba66e..0000000000000000000000000000000000000000 Binary files a/libs/relast.jar and /dev/null differ diff --git a/pages/docs/using.md b/pages/docs/using.md index a42891831f635201bd179762e0fa9fc01ed91774..5377ecae0873e6eed048be75a5381e2cd4a5e001 100644 --- a/pages/docs/using.md +++ b/pages/docs/using.md @@ -44,8 +44,9 @@ def relastOutputFiles = [ ] task relast(type: JavaExec) { - classpath = files("relast.preprocessor/libs/relast.jar") group = 'Build' + classpath = configurations.relast + mainClass = 'org.jastadd.relast.compiler.Compiler' doFirst { delete relastOutputFiles diff --git a/settings.gradle b/settings.gradle index 5f99c5a83ca1b73205acb1de3960ccc501af1cc4..2aeef63375455191b0c0e5fc1f30bb3196c81807 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,5 +1 @@ -pluginManagement { - plugins { - id 'org.jastadd' version '1.13.3' - } -} +rootProject.name = 'relast-preprocessor' \ No newline at end of file diff --git a/src/main/jastadd/GeneratedNavigation.jrag b/src/main/jastadd/GeneratedNavigation.jrag new file mode 100644 index 0000000000000000000000000000000000000000..1034e7b2994bf35d3db51e8ecd725c643e7895c2 --- /dev/null +++ b/src/main/jastadd/GeneratedNavigation.jrag @@ -0,0 +1,315 @@ +aspect Navigation { + + /** Tests if Comment is a WhitespaceComment. + * @return 'true' if this is a WhitespaceComment, otherwise 'false' + */ + syn boolean Comment.isWhitespaceComment() = false; + eq WhitespaceComment.isWhitespaceComment() = true; + + /** Tests if Comment is a SingleLineComment. + * @return 'true' if this is a SingleLineComment, otherwise 'false' + */ + syn boolean Comment.isSingleLineComment() = false; + eq SingleLineComment.isSingleLineComment() = true; + + /** Tests if Comment is a MultiLineComment. + * @return 'true' if this is a MultiLineComment, otherwise 'false' + */ + syn boolean Comment.isMultiLineComment() = false; + eq MultiLineComment.isMultiLineComment() = true; + + /** Tests if Comment is a DocComment. + * @return 'true' if this is a DocComment, otherwise 'false' + */ + syn boolean Comment.isDocComment() = false; + eq DocComment.isDocComment() = true; + + /** Tests if DirectedRelation is a LeftDirectedRelation. + * @return 'true' if this is a LeftDirectedRelation, otherwise 'false' + */ + syn boolean DirectedRelation.isLeftDirectedRelation() = false; + eq LeftDirectedRelation.isLeftDirectedRelation() = true; + + /** Tests if DirectedRelation is a RightDirectedRelation. + * @return 'true' if this is a RightDirectedRelation, otherwise 'false' + */ + syn boolean DirectedRelation.isRightDirectedRelation() = false; + eq RightDirectedRelation.isRightDirectedRelation() = true; + + /** Tests if TypeComponent is a NormalComponent. + * @return 'true' if this is a NormalComponent, otherwise 'false' + */ + syn boolean TypeComponent.isNormalComponent() = false; + eq NormalComponent.isNormalComponent() = true; + + /** Tests if TypeComponent is a ListComponent. + * @return 'true' if this is a ListComponent, otherwise 'false' + */ + syn boolean TypeComponent.isListComponent() = false; + eq ListComponent.isListComponent() = true; + + /** Tests if TypeComponent is a OptComponent. + * @return 'true' if this is a OptComponent, otherwise 'false' + */ + syn boolean TypeComponent.isOptComponent() = false; + eq OptComponent.isOptComponent() = true; + + /** Tests if Grammar is a GrammarFile. + * @return 'true' if this is a GrammarFile, otherwise 'false' + */ + syn boolean Grammar.isGrammarFile() = false; + eq GrammarFile.isGrammarFile() = true; + + /** Tests if NavigableRole is a NormalRole. + * @return 'true' if this is a NormalRole, otherwise 'false' + */ + syn boolean NavigableRole.isNormalRole() = false; + eq NormalRole.isNormalRole() = true; + + /** Tests if NavigableRole is a ListRole. + * @return 'true' if this is a ListRole, otherwise 'false' + */ + syn boolean NavigableRole.isListRole() = false; + eq ListRole.isListRole() = true; + + /** Tests if NavigableRole is a OptRole. + * @return 'true' if this is a OptRole, otherwise 'false' + */ + syn boolean NavigableRole.isOptRole() = false; + eq OptRole.isOptRole() = true; + + /** Tests if Component is a TypeComponent. + * @return 'true' if this is a TypeComponent, otherwise 'false' + */ + syn boolean Component.isTypeComponent() = false; + eq TypeComponent.isTypeComponent() = true; + + /** Tests if Component is a TokenComponent. + * @return 'true' if this is a TokenComponent, otherwise 'false' + */ + syn boolean Component.isTokenComponent() = false; + eq TokenComponent.isTokenComponent() = true; + + /** Tests if JavaTypeUse is a SimpleJavaTypeUse. + * @return 'true' if this is a SimpleJavaTypeUse, otherwise 'false' + */ + syn boolean JavaTypeUse.isSimpleJavaTypeUse() = false; + eq SimpleJavaTypeUse.isSimpleJavaTypeUse() = true; + + /** Tests if JavaTypeUse is a ParameterizedJavaTypeUse. + * @return 'true' if this is a ParameterizedJavaTypeUse, otherwise 'false' + */ + syn boolean JavaTypeUse.isParameterizedJavaTypeUse() = false; + eq ParameterizedJavaTypeUse.isParameterizedJavaTypeUse() = true; + + /** Tests if Relation is a DirectedRelation. + * @return 'true' if this is a DirectedRelation, otherwise 'false' + */ + syn boolean Relation.isDirectedRelation() = false; + eq DirectedRelation.isDirectedRelation() = true; + + /** Tests if Relation is a BidirectionalRelation. + * @return 'true' if this is a BidirectionalRelation, otherwise 'false' + */ + syn boolean Relation.isBidirectionalRelation() = false; + eq BidirectionalRelation.isBidirectionalRelation() = true; + + /** Tests if Role is a NavigableRole. + * @return 'true' if this is a NavigableRole, otherwise 'false' + */ + syn boolean Role.isNavigableRole() = false; + eq NavigableRole.isNavigableRole() = true; + + /** Tests if Role is a UnnamedRole. + * @return 'true' if this is a UnnamedRole, otherwise 'false' + */ + syn boolean Role.isUnnamedRole() = false; + eq UnnamedRole.isUnnamedRole() = true; + + /** Tests if Declaration is a EmptyDeclaration. + * @return 'true' if this is a EmptyDeclaration, otherwise 'false' + */ + syn boolean Declaration.isEmptyDeclaration() = false; + eq EmptyDeclaration.isEmptyDeclaration() = true; + + /** Tests if Declaration is a TypeDecl. + * @return 'true' if this is a TypeDecl, otherwise 'false' + */ + syn boolean Declaration.isTypeDecl() = false; + eq TypeDecl.isTypeDecl() = true; + + /** Tests if Declaration is a Relation. + * @return 'true' if this is a Relation, otherwise 'false' + */ + syn boolean Declaration.isRelation() = false; + eq Relation.isRelation() = true; + + /** casts a Comment into a WhitespaceComment if possible. + * @return 'this' cast to a WhitespaceComment or 'null' + */ + syn WhitespaceComment Comment.asWhitespaceComment(); + eq Comment.asWhitespaceComment() = null; + eq WhitespaceComment.asWhitespaceComment() = this; + + /** casts a Comment into a SingleLineComment if possible. + * @return 'this' cast to a SingleLineComment or 'null' + */ + syn SingleLineComment Comment.asSingleLineComment(); + eq Comment.asSingleLineComment() = null; + eq SingleLineComment.asSingleLineComment() = this; + + /** casts a Comment into a MultiLineComment if possible. + * @return 'this' cast to a MultiLineComment or 'null' + */ + syn MultiLineComment Comment.asMultiLineComment(); + eq Comment.asMultiLineComment() = null; + eq MultiLineComment.asMultiLineComment() = this; + + /** casts a Comment into a DocComment if possible. + * @return 'this' cast to a DocComment or 'null' + */ + syn DocComment Comment.asDocComment(); + eq Comment.asDocComment() = null; + eq DocComment.asDocComment() = this; + + /** casts a DirectedRelation into a LeftDirectedRelation if possible. + * @return 'this' cast to a LeftDirectedRelation or 'null' + */ + syn LeftDirectedRelation DirectedRelation.asLeftDirectedRelation(); + eq DirectedRelation.asLeftDirectedRelation() = null; + eq LeftDirectedRelation.asLeftDirectedRelation() = this; + + /** casts a DirectedRelation into a RightDirectedRelation if possible. + * @return 'this' cast to a RightDirectedRelation or 'null' + */ + syn RightDirectedRelation DirectedRelation.asRightDirectedRelation(); + eq DirectedRelation.asRightDirectedRelation() = null; + eq RightDirectedRelation.asRightDirectedRelation() = this; + + /** casts a TypeComponent into a NormalComponent if possible. + * @return 'this' cast to a NormalComponent or 'null' + */ + syn NormalComponent TypeComponent.asNormalComponent(); + eq TypeComponent.asNormalComponent() = null; + eq NormalComponent.asNormalComponent() = this; + + /** casts a TypeComponent into a ListComponent if possible. + * @return 'this' cast to a ListComponent or 'null' + */ + syn ListComponent TypeComponent.asListComponent(); + eq TypeComponent.asListComponent() = null; + eq ListComponent.asListComponent() = this; + + /** casts a TypeComponent into a OptComponent if possible. + * @return 'this' cast to a OptComponent or 'null' + */ + syn OptComponent TypeComponent.asOptComponent(); + eq TypeComponent.asOptComponent() = null; + eq OptComponent.asOptComponent() = this; + + /** casts a Grammar into a GrammarFile if possible. + * @return 'this' cast to a GrammarFile or 'null' + */ + syn GrammarFile Grammar.asGrammarFile(); + eq Grammar.asGrammarFile() = null; + eq GrammarFile.asGrammarFile() = this; + + /** casts a NavigableRole into a NormalRole if possible. + * @return 'this' cast to a NormalRole or 'null' + */ + syn NormalRole NavigableRole.asNormalRole(); + eq NavigableRole.asNormalRole() = null; + eq NormalRole.asNormalRole() = this; + + /** casts a NavigableRole into a ListRole if possible. + * @return 'this' cast to a ListRole or 'null' + */ + syn ListRole NavigableRole.asListRole(); + eq NavigableRole.asListRole() = null; + eq ListRole.asListRole() = this; + + /** casts a NavigableRole into a OptRole if possible. + * @return 'this' cast to a OptRole or 'null' + */ + syn OptRole NavigableRole.asOptRole(); + eq NavigableRole.asOptRole() = null; + eq OptRole.asOptRole() = this; + + /** casts a Component into a TypeComponent if possible. + * @return 'this' cast to a TypeComponent or 'null' + */ + syn TypeComponent Component.asTypeComponent(); + eq Component.asTypeComponent() = null; + eq TypeComponent.asTypeComponent() = this; + + /** casts a Component into a TokenComponent if possible. + * @return 'this' cast to a TokenComponent or 'null' + */ + syn TokenComponent Component.asTokenComponent(); + eq Component.asTokenComponent() = null; + eq TokenComponent.asTokenComponent() = this; + + /** casts a JavaTypeUse into a SimpleJavaTypeUse if possible. + * @return 'this' cast to a SimpleJavaTypeUse or 'null' + */ + syn SimpleJavaTypeUse JavaTypeUse.asSimpleJavaTypeUse(); + eq JavaTypeUse.asSimpleJavaTypeUse() = null; + eq SimpleJavaTypeUse.asSimpleJavaTypeUse() = this; + + /** casts a JavaTypeUse into a ParameterizedJavaTypeUse if possible. + * @return 'this' cast to a ParameterizedJavaTypeUse or 'null' + */ + syn ParameterizedJavaTypeUse JavaTypeUse.asParameterizedJavaTypeUse(); + eq JavaTypeUse.asParameterizedJavaTypeUse() = null; + eq ParameterizedJavaTypeUse.asParameterizedJavaTypeUse() = this; + + /** casts a Relation into a DirectedRelation if possible. + * @return 'this' cast to a DirectedRelation or 'null' + */ + syn DirectedRelation Relation.asDirectedRelation(); + eq Relation.asDirectedRelation() = null; + eq DirectedRelation.asDirectedRelation() = this; + + /** casts a Relation into a BidirectionalRelation if possible. + * @return 'this' cast to a BidirectionalRelation or 'null' + */ + syn BidirectionalRelation Relation.asBidirectionalRelation(); + eq Relation.asBidirectionalRelation() = null; + eq BidirectionalRelation.asBidirectionalRelation() = this; + + /** casts a Role into a NavigableRole if possible. + * @return 'this' cast to a NavigableRole or 'null' + */ + syn NavigableRole Role.asNavigableRole(); + eq Role.asNavigableRole() = null; + eq NavigableRole.asNavigableRole() = this; + + /** casts a Role into a UnnamedRole if possible. + * @return 'this' cast to a UnnamedRole or 'null' + */ + syn UnnamedRole Role.asUnnamedRole(); + eq Role.asUnnamedRole() = null; + eq UnnamedRole.asUnnamedRole() = this; + + /** casts a Declaration into a EmptyDeclaration if possible. + * @return 'this' cast to a EmptyDeclaration or 'null' + */ + syn EmptyDeclaration Declaration.asEmptyDeclaration(); + eq Declaration.asEmptyDeclaration() = null; + eq EmptyDeclaration.asEmptyDeclaration() = this; + + /** casts a Declaration into a TypeDecl if possible. + * @return 'this' cast to a TypeDecl or 'null' + */ + syn TypeDecl Declaration.asTypeDecl(); + eq Declaration.asTypeDecl() = null; + eq TypeDecl.asTypeDecl() = this; + + /** casts a Declaration into a Relation if possible. + * @return 'this' cast to a Relation or 'null' + */ + syn Relation Declaration.asRelation(); + eq Declaration.asRelation() = null; + eq Relation.asRelation() = this; + +} diff --git a/src/main/jastadd/Navigation.jrag b/src/main/jastadd/Navigation.jrag index 5a9e43ffeb17a301c61a53fbbc1f30622a61193a..7834c25eced07c31cc2c3331f05965ead638fb45 100644 --- a/src/main/jastadd/Navigation.jrag +++ b/src/main/jastadd/Navigation.jrag @@ -2,6 +2,8 @@ aspect Navigation { // --- program --- inh Program ASTNode.program(); + eq Grammar.getChild().program() = null; + eq GrammarFile.getChild().program() = program(); eq Program.getChild().program() = this; // --- typeDecls --- @@ -28,66 +30,10 @@ aspect Navigation { // --- containedFile --- inh GrammarFile ASTNode.containedFile(); + eq Grammar.getChild().containedFile() = null; eq Program.getChild().containedFile() = null; eq GrammarFile.getChild().containedFile() = this; // --- containedFileName --- - inh String ASTNode.containedFileName(); - eq GrammarFile.getChild().containedFileName() = getFileName(); - - // --- isTokenComponent --- - syn boolean Component.isTokenComponent() = false; - eq TokenComponent.isTokenComponent() = true; - - // --- asTokenComponent --- - syn TokenComponent Component.asTokenComponent() = null; - eq TokenComponent.asTokenComponent() = this; - - // --- isTypeDecl (should be in preprocessor) --- - syn boolean Declaration.isTypeDecl() = false; - eq TypeDecl.isTypeDecl() = true; - - // --- asTypeDecl (should be in preprocessor) --- - syn TypeDecl Declaration.asTypeDecl() = null; - eq TypeDecl.asTypeDecl() = this; - - // --- isTypeComponent (should be in preprocessor) --- - syn boolean Component.isTypeComponent() = false; - eq TypeComponent.isTypeComponent() = true; - - // --- asTypeComponent (should be in preprocessor) --- - syn TypeComponent Component.asTypeComponent() = null; - eq TypeComponent.asTypeComponent() = this; - - // --- isNormalComponent (should be in preprocessor) --- - syn boolean Component.isNormalComponent() = false; - eq NormalComponent.isNormalComponent() = true; - - // --- asNormalComponent (should be in preprocessor) --- - syn NormalComponent Component.asNormalComponent() = null; - eq NormalComponent.asNormalComponent() = this; - - // --- isListComponent (should be in preprocessor) --- - syn boolean Component.isListComponent() = false; - eq ListComponent.isListComponent() = true; - - // --- asListComponent (should be in preprocessor) --- - syn ListComponent Component.asListComponent() = null; - eq ListComponent.asListComponent() = this; - - // --- isDirectedRelation (should be in preprocessor) --- - syn boolean Relation.isDirectedRelation() = false; - eq DirectedRelation.isDirectedRelation() = true; - - // --- asDirectedRelation (should be in preprocessor) --- - syn DirectedRelation Relation.asDirectedRelation() = null; - eq DirectedRelation.asDirectedRelation() = this; - - // --- asBidirectionalRelation (should be in preprocessor) --- - syn BidirectionalRelation Relation.asBidirectionalRelation() = null; - eq BidirectionalRelation.asBidirectionalRelation() = this; - - // --- isListRole (should be in preprocessor) --- - syn boolean Role.isListRole() = false; - eq ListRole.isListRole() = true; + syn String ASTNode.containedFileName() = containedFile().getFileName(); } diff --git a/src/main/jastadd/backend/AbstractGrammar.jadd b/src/main/jastadd/backend/AbstractGrammar.jadd index 3683fe27c2fba45459a5e7eb325f62ab1ad8e102..6cef6edff2052183efba997bdf25295ce4cedf32 100644 --- a/src/main/jastadd/backend/AbstractGrammar.jadd +++ b/src/main/jastadd/backend/AbstractGrammar.jadd @@ -127,6 +127,7 @@ aspect BackendAbstractGrammar { } public void ParameterizedJavaTypeUse.generateAbstractGrammar(StringBuilder b) { + b.append(getName()); b.append("<"); boolean first = true; for (JavaTypeUse javaTypeUse : getJavaTypeUseList()) { diff --git a/src/main/jastadd/mustache b/src/main/jastadd/mustache index c10bed0d03e3fa18b8133ce1de48de7646899615..b9ad898b4da5d53ede0107c76f9f73fe818073a1 160000 --- a/src/main/jastadd/mustache +++ b/src/main/jastadd/mustache @@ -1 +1 @@ -Subproject commit c10bed0d03e3fa18b8133ce1de48de7646899615 +Subproject commit b9ad898b4da5d53ede0107c76f9f73fe818073a1 diff --git a/src/main/jastadd/parser/RelAst.parser b/src/main/jastadd/parser/RelAst.parser index c4cfd43d096b226f9ee3c98fe5f75975be4f10e1..628e452c42cd935902cd79ef1293b8c46a1fb0b5 100644 --- a/src/main/jastadd/parser/RelAst.parser +++ b/src/main/jastadd/parser/RelAst.parser @@ -1,6 +1,5 @@ GrammarFile goal = comment_list.c grammar_file.f {: f.getDeclarationList().insertChild(new EmptyDeclaration(c), 0); return f; :} - | grammar_file ; GrammarFile grammar_file @@ -16,8 +15,8 @@ Declaration declaration // this method would be create by the JAstAddParser from a usage of // 'comment+' in a rule, but only for the standard list class 'List'. JastAddList comment_list - = comment.n {: return new JastAddList().add(n); :} - | comment_list.l comment.n {: return l.add(n); :} + = comment.c comment_list.l {: l.insertChild(c, 0); return l; :} + | /* epsilon */ {: return new JastAddList(); :} ; Comment comment diff --git a/src/main/jastadd/scanner/Keywords.flex b/src/main/jastadd/scanner/Keywords.flex index 76397b9efcd1c748a3a1eb69675d23dbd4042178..27524e3d2ee6768c8ec6117059967c5780be15ce 100644 --- a/src/main/jastadd/scanner/Keywords.flex +++ b/src/main/jastadd/scanner/Keywords.flex @@ -1,4 +1,4 @@ -<YYINITIAL,DECLARATION> { +<YYINITIAL,COMMENT,DECLARATION> { "abstract" { yybegin(DECLARATION); return sym(Terminals.ABSTRACT); } "rel" { yybegin(DECLARATION); return sym(Terminals.RELATION); } } diff --git a/src/main/jastadd/scanner/RulesPostamble.flex b/src/main/jastadd/scanner/RulesPostamble.flex index 5460a0b87e2002c06430aa5cc88abf0b39f30b9f..37f546ff66770d94feaa71ff8b74bd4462f190d8 100644 --- a/src/main/jastadd/scanner/RulesPostamble.flex +++ b/src/main/jastadd/scanner/RulesPostamble.flex @@ -1,7 +1,7 @@ -<YYINITIAL,DECLARATION> { +<YYINITIAL,COMMENT,DECLARATION> { {ID} { yybegin(DECLARATION); return sym(Terminals.ID); } - [^] { throw new ScannerError((yyline+1) +"," + (yycolumn+1) + ": Illegal character <"+yytext()+">"); } } -<YYINITIAL,DECLARATION,COMMENT> { +<YYINITIAL,COMMENT,DECLARATION> { <<EOF>> { return sym(Terminals.EOF); } -} + [^] { throw new ScannerError((yyline+1) +"," + (yycolumn+1) + ": Illegal character <"+yytext()+">"); } +} \ No newline at end of file diff --git a/src/main/jastadd/scanner/Symbols.flex b/src/main/jastadd/scanner/Symbols.flex index 7f05c115b570fd3681617106bb77bc25bb79d7b2..5ac1c2d1855c91514b2d18483896ae0bb5ba1d08 100644 --- a/src/main/jastadd/scanner/Symbols.flex +++ b/src/main/jastadd/scanner/Symbols.flex @@ -1,4 +1,4 @@ -<YYINITIAL,DECLARATION> { +<YYINITIAL,COMMENT,DECLARATION> { ";" { yybegin(COMMENT); return sym(Terminals.SCOL); } ":" { yybegin(DECLARATION); return sym(Terminals.COL); } "::=" { yybegin(DECLARATION); return sym(Terminals.ASSIGN); } diff --git a/src/main/java/org/jastadd/PreprocessorConfiguration.java b/src/main/java/org/jastadd/PreprocessorConfiguration.java index 39fd43963ecdc1cece0649cf3e1123ed228e4505..913b8b56532b33566db14180377d78be0dae0777 100644 --- a/src/main/java/org/jastadd/PreprocessorConfiguration.java +++ b/src/main/java/org/jastadd/PreprocessorConfiguration.java @@ -140,7 +140,6 @@ public class PreprocessorConfiguration extends org.jastadd.Configuration { allOptions.add(cacheCycleOption); allOptions.add(componentCheckOption); allOptions.add(inhEqCheckOption); - allOptions.add(suppressWarningsOption); allOptions.add(refineLegacyOption); allOptions.add(licenseOption); allOptions.add(debugOption); @@ -180,27 +179,6 @@ public class PreprocessorConfiguration extends org.jastadd.Configuration { // New since 2.3.4 allOptions.add(optimizeImports); - // Deprecated in 2.1.5. - allOptions.add(doxygenOption); - allOptions.add(cacheAllOption); - allOptions.add(noCachingOption); - allOptions.add(cacheNoneOption); - allOptions.add(cacheImplicitOption); - allOptions.add(ignoreLazyOption); - allOptions.add(fullFlushOption); - - // Deprecated in 2.1.9. - allOptions.add(docOption); - allOptions.add(java1_4Option); // Disabled in 2.1.10. - allOptions.add(noLazyMapsOption); - allOptions.add(noVisitCheckOption); - allOptions.add(noCacheCycleOption); - allOptions.add(noRefineLegacyOption); - allOptions.add(noComponentCheckOption); - allOptions.add(noInhEqCheckOption); - allOptions.add(noStaticOption); - allOptions.add(deterministicOption); - return allOptions; } diff --git a/src/main/java/org/jastadd/relast/compiler/Mustache.java b/src/main/java/org/jastadd/relast/compiler/Mustache.java index 24d368abf9d13cbca1882caef1a49084943499a9..e5b09f3922452275ae598c32332af6cf4a0a4722 100644 --- a/src/main/java/org/jastadd/relast/compiler/Mustache.java +++ b/src/main/java/org/jastadd/relast/compiler/Mustache.java @@ -39,9 +39,11 @@ public class Mustache { Handlebars handlebars = new Handlebars(loader); handlebars.prettyPrint(true); // set handlebars to mustache mode (skip some whitespace) + handlebars.infiniteLoops(true); // allow partial recursion Template template = handlebars.compile(templateFileName); try (Writer w = new FileWriter(outputFileName)) { + System.out.println("Writing " + outputFileName); template.apply(context, w); w.flush(); } diff --git a/src/main/java/org/jastadd/relast/compiler/RelAstProcessor.java b/src/main/java/org/jastadd/relast/compiler/RelAstProcessor.java index 943583517f406e9b557e3bb34262b15185b38438..858934970ccb72e5db62ed427210d25b0f0db99e 100644 --- a/src/main/java/org/jastadd/relast/compiler/RelAstProcessor.java +++ b/src/main/java/org/jastadd/relast/compiler/RelAstProcessor.java @@ -25,9 +25,20 @@ public abstract class RelAstProcessor extends AbstractCompiler { super(name, jastAddCompliant); } - protected boolean isGrammarFile(String fileName) { - String extension = fileName.subSequence(fileName.lastIndexOf('.'), fileName.length()).toString(); - return extension.equals(".relast") || extension.equals(".ast"); + protected boolean isGrammarFile(Path path) { + if (path.getFileName() == null) { return false; } + String fileName = path.getFileName().toString(); + int dotIndex = fileName.lastIndexOf('.'); + if (dotIndex < 0) { + printMessage(path + " has no extension, ignoring it."); + return false; + } + String extension = fileName.subSequence(dotIndex, fileName.length()).toString(); + boolean isGrammar = extension.equals(".relast") || extension.equals(".ast"); + if (!isGrammar) { + printMessage(path + " is not a grammar file, ignoring it."); + } + return isGrammar; } @Override @@ -44,14 +55,14 @@ public abstract class RelAstProcessor extends AbstractCompiler { inputBasePath = Paths.get(optionInputBaseDir.value()).toAbsolutePath(); } else { inputBasePath = Paths.get(".").toAbsolutePath(); - printMessage("No input base dir is set. Assuming current directory '" + inputBasePath.toAbsolutePath().toString() + "'."); + printMessage("No input base dir is set. Assuming current directory '" + inputBasePath.toAbsolutePath() + "'."); } if (!inputBasePath.toFile().exists()) { - printMessage("Input path '" + inputBasePath.toAbsolutePath().toString() + "' does not exist. Exiting..."); + printMessage("Input path '" + inputBasePath.toAbsolutePath() + "' does not exist. Exiting..."); System.exit(-1); } else if (!inputBasePath.toFile().isDirectory()) { - printMessage("Input path '" + inputBasePath.toAbsolutePath().toString() + "' is not a directory. Exiting..."); + printMessage("Input path '" + inputBasePath.toAbsolutePath() + "' is not a directory. Exiting..."); System.exit(-1); } @@ -63,29 +74,29 @@ public abstract class RelAstProcessor extends AbstractCompiler { } if (outputBasePath.toFile().exists() && !outputBasePath.toFile().isDirectory()) { - printMessage("Output path '" + inputBasePath.toAbsolutePath().toString() + "' exists, but is not a directory. Exiting..."); + printMessage("Output path '" + inputBasePath.toAbsolutePath() + "' exists, but is not a directory. Exiting..."); } printMessage("Running " + getName()); // gather all files Collection<Path> inputFiles = new ArrayList<>(); - getConfiguration().getFiles().forEach(name -> relativizeFileName(inputBasePath, Paths.get(name)).ifPresent(inputFiles::add)); + getConfiguration().getFiles().forEach(name -> checkFileName(inputBasePath, Paths.get(name)).ifPresent(inputFiles::add)); - Program program = parseProgram(inputFiles); + Program program = parseProgram(inputBasePath, inputFiles); return processGrammar(program, inputBasePath, outputBasePath); } protected abstract int processGrammar(Program program, Path inputBasePath, Path outputBasePath) throws CompilerException; - private Optional<Path> relativizeFileName(Path inputBasePath, Path filePath) { + private Optional<Path> checkFileName(Path inputBasePath, Path filePath) { if (filePath.isAbsolute()) { - if (filePath.startsWith(inputBasePath)) { - return Optional.of(filePath.relativize(inputBasePath)); + if (filePath.normalize().startsWith(inputBasePath.normalize())) { + return Optional.of(filePath); } else { - printMessage("Path '" + filePath + "' is not contained in the base path '" + inputBasePath + "'."); + printMessage("Path '" + filePath + "' is not contained in the base path '" + inputBasePath + "', ignoring it."); return Optional.empty(); } } else { @@ -107,19 +118,18 @@ public abstract class RelAstProcessor extends AbstractCompiler { } } - private Program parseProgram(Collection<Path> inputFiles) { + private Program parseProgram(Path inputBasePath, Collection<Path> inputFiles) { Program program = new Program(); RelAstParser parser = new RelAstParser(); - inputFiles.stream().filter(path -> isGrammarFile(path.toString())).forEach( + inputFiles.stream().filter(this::isGrammarFile).forEach( path -> { try (BufferedReader reader = Files.newBufferedReader(path)) { RelAstScanner scanner = new RelAstScanner(reader); GrammarFile inputGrammar = (GrammarFile) parser.parse(scanner); - inputGrammar.setFileName(path.toString()); + inputGrammar.setFileName(inputBasePath.relativize(path).toString()); program.addGrammarFile(inputGrammar); - inputGrammar.treeResolveAll(); } catch (IOException | beaver.Parser.Exception e) { printMessage("Could not parse grammar file " + path); e.printStackTrace(); @@ -127,6 +137,8 @@ public abstract class RelAstProcessor extends AbstractCompiler { } ); + program.treeResolveAll(); + return program; } } diff --git a/src/main/java/org/jastadd/relast/compiler/RelastSourceToSourceCompiler.java b/src/main/java/org/jastadd/relast/compiler/RelastSourceToSourceCompiler.java index 696c3c17ef59872ffaf174d4b8e4b4b7e8e9bdd1..b3347cc3ec74ca1812805df5e59433ad3066e9ed 100644 --- a/src/main/java/org/jastadd/relast/compiler/RelastSourceToSourceCompiler.java +++ b/src/main/java/org/jastadd/relast/compiler/RelastSourceToSourceCompiler.java @@ -22,12 +22,6 @@ public class RelastSourceToSourceCompiler extends RelAstProcessor { } } - @Override - protected boolean isGrammarFile(String fileName) { - String extension = fileName.subSequence(fileName.lastIndexOf("."), fileName.length()).toString(); - return extension.equals(".relast") || extension.equals(".ast"); - } - @Override protected int processGrammar(Program program, Path inputBasePath, Path outputBasePath) throws CompilerException { @@ -36,7 +30,7 @@ public class RelastSourceToSourceCompiler extends RelAstProcessor { for (GrammarFile grammarFile : program.getGrammarFileList()) { printMessage("Writing output file " + grammarFile.getFileName()); // TODO decide and document what the file name should be, the full path or a simple name? - writeToFile(outputBasePath.resolve(inputBasePath.relativize(Paths.get(grammarFile.getFileName()))), grammarFile.generateAbstractGrammar()); + writeToFile(outputBasePath.resolve(grammarFile.getFileName()), grammarFile.generateAbstractGrammar()); } return 0; } diff --git a/src/main/resources/RelASTPreprocessorVersion.properties b/src/main/resources/RelASTPreprocessorVersion.properties new file mode 100644 index 0000000000000000000000000000000000000000..de55ab654e5845e918eedddeabe2aea9b9518b5c --- /dev/null +++ b/src/main/resources/RelASTPreprocessorVersion.properties @@ -0,0 +1 @@ +version=0.1.0 diff --git a/src/main/resources/preprocessor.properties b/src/main/resources/preprocessor.properties deleted file mode 100644 index fb55bf09edd40713c458341e14b57714f11924db..0000000000000000000000000000000000000000 --- a/src/main/resources/preprocessor.properties +++ /dev/null @@ -1 +0,0 @@ -version=1.0.0-pre-release diff --git a/src/test/resources/GrammarFileOrder/config.yaml b/src/test/resources/GrammarFileOrder/config.yaml new file mode 100644 index 0000000000000000000000000000000000000000..d18791ee656f768847a06afdd6a2501e590f4011 --- /dev/null +++ b/src/test/resources/GrammarFileOrder/config.yaml @@ -0,0 +1,11 @@ +- name: "dependencies between relast files" + args: + - "--inputBaseDir=in" + - "--outputBaseDir=out" + - "Rel.relast" + - "A.relast" + - "B.relast" + - "C.relast" + out: "out" + expected: "in" + compare: true diff --git a/src/test/resources/GrammarFileOrder/in/A.relast b/src/test/resources/GrammarFileOrder/in/A.relast new file mode 100644 index 0000000000000000000000000000000000000000..3089a16f06dc47eb87be35f073bb21d050023730 --- /dev/null +++ b/src/test/resources/GrammarFileOrder/in/A.relast @@ -0,0 +1,3 @@ +A ::= A1 A2; +A1 ::= B; +A2 ::= C; diff --git a/src/test/resources/GrammarFileOrder/in/B.relast b/src/test/resources/GrammarFileOrder/in/B.relast new file mode 100644 index 0000000000000000000000000000000000000000..a98f9404c6c3687aff85b0ad119a2d19d96dbd0a --- /dev/null +++ b/src/test/resources/GrammarFileOrder/in/B.relast @@ -0,0 +1,3 @@ +B ::= B1 B2; +B1 ::= A; +B2 ::= C; diff --git a/src/test/resources/GrammarFileOrder/in/C.relast b/src/test/resources/GrammarFileOrder/in/C.relast new file mode 100644 index 0000000000000000000000000000000000000000..ff70879a33a29cd911905ebd97a010a9c8961d59 --- /dev/null +++ b/src/test/resources/GrammarFileOrder/in/C.relast @@ -0,0 +1,3 @@ +C ::= [C1] [C2]; +C1 ::= A; +C2 ::= B; diff --git a/src/test/resources/GrammarFileOrder/in/Rel.relast b/src/test/resources/GrammarFileOrder/in/Rel.relast new file mode 100644 index 0000000000000000000000000000000000000000..6acc2faab21dba3b4100cc4b52205142c86f39d4 --- /dev/null +++ b/src/test/resources/GrammarFileOrder/in/Rel.relast @@ -0,0 +1,3 @@ +rel A.b? -> B; +rel B.c? -> C; +rel C.a? -> A; diff --git a/src/test/resources/MinimalGrammar/config.yaml b/src/test/resources/MinimalGrammar/config.yaml index 135f6bd74b057a00cc5582b7ca78e83995167e48..6cb1344294db04658dfc2c43e0bb339140017c14 100644 --- a/src/test/resources/MinimalGrammar/config.yaml +++ b/src/test/resources/MinimalGrammar/config.yaml @@ -4,6 +4,7 @@ - "--outputBaseDir=out" - "Example.relast" - "CommentInFront.relast" + - "DefaultTypeOfToken.ast" out: "out" expected: "in" compare: true diff --git a/src/test/resources/MinimalGrammar/in/DefaultTypeOfToken.ast b/src/test/resources/MinimalGrammar/in/DefaultTypeOfToken.ast new file mode 100644 index 0000000000000000000000000000000000000000..ebc30a7668962c74dffd8aa66461576612b6eb7e --- /dev/null +++ b/src/test/resources/MinimalGrammar/in/DefaultTypeOfToken.ast @@ -0,0 +1 @@ +A ::= <B>; diff --git a/src/test/resources/MinimalGrammar/in/Example.relast b/src/test/resources/MinimalGrammar/in/Example.relast index 7c28b7bcd84c826aedd622460eb93da08ee80c3d..64200adaac4461f09ada5fc7342aa5a085032be7 100644 --- a/src/test/resources/MinimalGrammar/in/Example.relast +++ b/src/test/resources/MinimalGrammar/in/Example.relast @@ -11,3 +11,5 @@ Joint ::= <Name> <CurrentPosition:IntPosition>; // normally this would be: <Cur EndEffector : Joint; Coordinate ::= <Position:IntPosition>; + +TestingParameterized : Coordinate ::= <ListPosition:java.util.List<IntPosition>>; diff --git a/src/test/resources/NoWhitespaceAfterRules/config.yaml b/src/test/resources/NoWhitespaceAfterRules/config.yaml new file mode 100644 index 0000000000000000000000000000000000000000..0b4111a0c86ed8510b2a9d72b02a58319e246f7b --- /dev/null +++ b/src/test/resources/NoWhitespaceAfterRules/config.yaml @@ -0,0 +1,9 @@ +- name: "No whitespace/comment between and after rules required" + args: + - "--inputBaseDir=in" + - "--outputBaseDir=out" + - "Grammar.relast" + - "Relation.relast" + out: "out" + expected: "in" + compare: true diff --git a/src/test/resources/NoWhitespaceAfterRules/in/Grammar.relast b/src/test/resources/NoWhitespaceAfterRules/in/Grammar.relast new file mode 100644 index 0000000000000000000000000000000000000000..5ef2b62144e2711ce5bb834bd332088f57725226 --- /dev/null +++ b/src/test/resources/NoWhitespaceAfterRules/in/Grammar.relast @@ -0,0 +1,2 @@ +Person ::= <FullName> <Address> Gender;abstract Gender; +Male : Gender;Female : Gender;Diverse : Gender; \ No newline at end of file diff --git a/src/test/resources/NoWhitespaceAfterRules/in/Relation.relast b/src/test/resources/NoWhitespaceAfterRules/in/Relation.relast new file mode 100644 index 0000000000000000000000000000000000000000..3401591959fee1ffdbdf9d8e83c7c7d63b1045ce --- /dev/null +++ b/src/test/resources/NoWhitespaceAfterRules/in/Relation.relast @@ -0,0 +1 @@ +rel Person.Friend -> Person;rel Person.Child <-> Person.Parent; \ No newline at end of file diff --git a/src/testFixtures/java/org/jastadd/relast/tests/RelAstProcessorTestBase.java b/src/testFixtures/java/org/jastadd/relast/tests/RelAstProcessorTestBase.java index e83746c04a4a85327eabf5db0a1de580e6a42e3c..250295942024ec2badc3a87d538ef60177b80348 100644 --- a/src/testFixtures/java/org/jastadd/relast/tests/RelAstProcessorTestBase.java +++ b/src/testFixtures/java/org/jastadd/relast/tests/RelAstProcessorTestBase.java @@ -8,14 +8,13 @@ import org.apache.commons.io.filefilter.FileFilterUtils; import org.apache.commons.io.filefilter.TrueFileFilter; import org.assertj.core.util.Files; import org.jastadd.relast.tests.config.Configuration; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.DynamicTest; -import org.junit.jupiter.api.TestFactory; +import org.junit.jupiter.api.*; import java.io.*; import java.nio.charset.Charset; import java.nio.file.Path; import java.util.*; +import java.util.stream.Collectors; import java.util.stream.Stream; public class RelAstProcessorTestBase { @@ -77,41 +76,51 @@ public class RelAstProcessorTestBase { return runProcess(workingDirectory, command, outStringBuider, errStringBuilder); } - protected void directoryTest(Class<?> mainClass, Path dir) throws IOException, InterruptedException { + protected Iterator<DynamicNode> directoryTest(Class<?> mainClass, Path dir) { dir = dir.toAbsolutePath(); Path configFile = dir.resolve("config.yaml"); ObjectMapper mapper = new ObjectMapper(new YAMLFactory()); - List<Configuration> configs = mapper.readValue(configFile.toFile(), new TypeReference<List<Configuration>>() { - }); + List<Configuration> configs = null; + try { + configs = mapper.readValue(configFile.toFile(), new TypeReference<List<Configuration>>() { + }); + } catch (IOException e) { + e.printStackTrace(System.err); + return Collections.emptyIterator(); + } - for (Configuration config : configs) { + Path finalDir = dir; - FileUtils.forceMkdir(dir.resolve(config.getOut()).toFile()); - FileUtils.cleanDirectory(dir.resolve(config.getOut()).toFile()); + return configs.stream().map(config -> + (DynamicNode) DynamicTest.dynamicTest(config.getName(), () -> { - StringBuilder outBuilder = new StringBuilder(); - StringBuilder errBuilder = new StringBuilder(); - int returnValue = runJavaProcess(mainClass, dir.toFile(), Arrays.asList(config.getArgs()), outBuilder, errBuilder); - String out = outBuilder.toString(); - String err = errBuilder.toString(); + FileUtils.forceMkdir(finalDir.resolve(config.getOut()).toFile()); + FileUtils.cleanDirectory(finalDir.resolve(config.getOut()).toFile()); - System.out.println(out); - System.err.println(err); + StringBuilder outBuilder = new StringBuilder(); + StringBuilder errBuilder = new StringBuilder(); + int returnValue = runJavaProcess(mainClass, finalDir.toFile(), Arrays.asList(config.getArgs()), outBuilder, errBuilder); + String out = outBuilder.toString(); + String err = errBuilder.toString(); - if (config.shouldFail()) { - Assertions.assertNotEquals(0, returnValue, config.getName() + ": Zero return value of preprocessor for negative test."); - } else { - Assertions.assertEquals(0, returnValue, config.getName() + ": Non-Zero return value of preprocessor for positive test."); - } + System.out.println(out); + System.err.println(err); - checkOutput(config, out, err); + if (config.shouldFail()) { + Assertions.assertNotEquals(0, returnValue, config.getName() + ": Zero return value of preprocessor for negative test."); + } else { + Assertions.assertEquals(0, returnValue, config.getName() + ": Non-Zero return value of preprocessor for positive test."); + } - if (config.shouldCompare()) { - Path outPath = dir.resolve(config.getOut()); - Path expectedPath = dir.resolve(config.getExpected()); - comparePaths(outPath, expectedPath); - } - } + checkOutput(config, out, err); + + if (config.shouldCompare()) { + Path outPath = finalDir.resolve(config.getOut()); + Path expectedPath = finalDir.resolve(config.getExpected()); + comparePaths(outPath, expectedPath); + } + + })).iterator(); } private void checkOutput(Configuration config, String out, String err) { @@ -162,15 +171,18 @@ public class RelAstProcessorTestBase { } @TestFactory - Stream<DynamicTest> testAll() { + Stream<DynamicContainer> testAll() { File baseDir = new File("src/test/resources/"); Assertions.assertTrue(baseDir.exists()); Assertions.assertTrue(baseDir.isDirectory()); File[] files = baseDir.listFiles((FileFilter) FileFilterUtils.directoryFileFilter()); Assertions.assertNotNull(files); - return Arrays.stream(files).map(File::toPath).map(f -> DynamicTest.dynamicTest(f.getFileName().toString(), - () -> directoryTest(mainClass, f))); + return Arrays.stream(files) + // TODO consider also supporting "config.yml" + .filter(f -> Objects.requireNonNull(f.listFiles(x -> x.getName().matches("config\\.yaml"))).length == 1) + .map(File::toPath) + .map(f -> DynamicContainer.dynamicContainer(f.getFileName().toString(), () -> directoryTest(mainClass, f))); } }