diff --git a/.gitignore b/.gitignore
index 59ea87058c768c6d4f9d8434c5f1995368ed2fb4..17f4b40afc3d943c27432f9da771748569331f6d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -6,31 +6,7 @@ src/gen-res/
 src/gen/
 out/
 *.class
-src/test/jastadd/relations/Relations.ast
-src/test/jastadd/relations/Relations.jadd
-src/test/jastadd/relations/Relations2.ast
-src/test/jastadd/relations/Relations2.jadd
-src/test/jastadd/lowerbounds/LowerBounds.ast
-src/test/jastadd/lowerbounds/LowerBounds.jadd
-src/test/jastadd/multiple/Multiple.ast
-src/test/jastadd/multiple/Multiple.jadd
-src/test/jastadd/resolver/Resolver.ast
-src/test/jastadd/resolver/Resolver.jadd
-src/test/jastadd/resolver/ResolverRefResolver.jadd
-src/test/jastadd/resolver/ResolverResolverStubs.jrag
-src/test/jastadd/resolver2/Resolver.ast
-src/test/jastadd/resolver2/Resolver.jadd
-src/test/jastadd/resolver2/ResolverRefResolver.jadd
-src/test/jastadd/resolver2/ResolverResolverStubs.jrag
-src/test/jastadd/listnames/ListNames.ast
-src/test/jastadd/listnames/ListNames.jadd
-src/test/jastadd/serializer/Serializer.ast
-src/test/jastadd/serializer/Serializer.jadd
-src/test/jastadd/serializer/SerializerSerializer.jadd
-src/test/jastadd/serializer/SerializerRefResolver.jadd
-src/test/jastadd/serializer/SerializerResolverStubs.jrag
-src/test/jastadd/serializer-names/Serializer.ast
-src/test/jastadd/serializer-names/Serializer.jadd
-src/test/jastadd/serializer-names/SerializerSerializer.jadd
-src/test/jastadd/serializer-names/SerializerRefResolver.jadd
-src/test/jastadd/serializer-names/SerializerResolverStubs.jrag
\ No newline at end of file
+src/test/jastadd/*/*.ast
+src/test/jastadd/*/*.jadd
+src/test/jastadd/*/*ResolverStubs.jrag
+!src/test/jastadd/*/MyRefResolver.jadd
diff --git a/build.gradle b/build.gradle
index 9c1a469a5993565d84049c56aa5fdb633f55f489..df193293e072d7d3cf8af39d65dd6a652f6e5ce2 100644
--- a/build.gradle
+++ b/build.gradle
@@ -1,7 +1,10 @@
+import org.jastadd.relast.plugin.RelastTest
+
 apply plugin: 'java'
 apply plugin: 'jastadd'
 apply plugin: 'application'
 apply plugin: "idea"
+apply plugin: "org.jastadd.relast.plugin"
 
 sourceCompatibility = 1.8
 
@@ -33,6 +36,7 @@ dependencies {
 sourceSets {
     main {
         java.srcDir "src/gen/java"
+        java.srcDir "buildSrc/gen/java"
     }
     test {
         java.srcDir "src/test/java-gen"
@@ -145,306 +149,94 @@ task compileRelationTest(type: JavaExec, group: 'verification') {
             'src/test/jastadd/Utils.jadd'
 }
 
-task preprocessDefaultNamesTest(type: JavaExec, group: 'verification') {
-
-    doFirst {
-        delete 'src/test/jastadd/relations/Relations.ast', 'src/test/jastadd/relations/Relations.jadd'
-    }
-
-    classpath = sourceSets.main.runtimeClasspath
-    main = 'org.jastadd.relast.compiler.Compiler'
-    args 'src/test/jastadd/relations/Relations.relast', '--file', '--grammarName=src/test/jastadd/relations/Relations'
-}
-
-task compileDefaultNamesTest(type: JavaExec, group: 'verification') {
-
-    doFirst {
-        delete 'src/test/java-gen/relations'
-    }
-
-    classpath = sourceSets.main.runtimeClasspath
-    main = 'org.jastadd.JastAdd'
-    args '--o=src/test/java-gen/', '--package=defaultnames.ast', 'src/test/jastadd/relations/Relations.ast', 'src/test/jastadd/relations/Relations.jadd', 'src/test/jastadd/Utils.jadd'
-}
-
-task preprocessDefaultNamesResolverTest(type: JavaExec, group: 'verification') {
-
-    doFirst {
-        delete 'src/test/jastadd/resolver/Resolver.ast', 'src/test/jastadd/resolver/Resolver.jadd', 'src/test/jastadd/resolver/ResolverRefResolver.jadd'
-    }
-
-    classpath = sourceSets.main.runtimeClasspath
-    main = 'org.jastadd.relast.compiler.Compiler'
-    args 'src/test/jastadd/resolver/Resolver.relast', '--file', '--grammarName=src/test/jastadd/resolver/Resolver', '--resolverHelper'
-}
-
-task compileDefaultNamesResolverTest(type: JavaExec, group: 'verification') {
-
-    doFirst {
-        delete 'src/test/java-gen/resolver'
-    }
-
-    classpath = sourceSets.main.runtimeClasspath
-    main = 'org.jastadd.JastAdd'
-    //noinspection GroovyAssignabilityCheck
-    args '--o=src/test/java-gen/',
-            '--package=defaultnames.resolver.ast',
-            'src/test/jastadd/resolver/Resolver.ast',
-            'src/test/jastadd/resolver/Resolver.jadd',
-            'src/test/jastadd/resolver/ResolverUtils.jadd',
-            'src/test/jastadd/resolver/ResolverResolverStubs.jrag',
-            'src/test/jastadd/resolver/ResolverRefResolver.jadd',
-            'src/test/jastadd/resolver/MyRefResolver.jadd',
-            'src/test/jastadd/Utils.jadd'
-}
-
-task preprocessLowerBoundsTest(type: JavaExec, group: 'verification') {
-
-    doFirst {
-        delete 'src/test/jastadd/lowerbounds/LowerBounds.ast', 'src/test/jastadd/lowerbounds/LowerBounds.jadd'
-    }
-
-    classpath = sourceSets.main.runtimeClasspath
-    main = 'org.jastadd.relast.compiler.Compiler'
-    //noinspection GroovyAssignabilityCheck
-    args 'src/test/jastadd/lowerbounds/LowerBounds.relast', '--useJastAddNames', '--file', '--grammarName=src/test/jastadd/lowerbounds/LowerBounds'
-}
-
-task compileLowerBoundsTest(type: JavaExec, group: 'verification') {
-
-    doFirst {
-        delete 'src/test/java-gen/lowerbounds'
-    }
-
-    classpath = sourceSets.main.runtimeClasspath
-    main = 'org.jastadd.JastAdd'
-    //noinspection GroovyAssignabilityCheck
-    args '--o=src/test/java-gen/', '--package=lowerbounds.ast',
-            'src/test/jastadd/lowerbounds/LowerBounds.ast',
-            'src/test/jastadd/lowerbounds/LowerBounds.jadd',
-            'src/test/jastadd/Utils.jadd'
-}
-
-task preprocessMultipleTest(type: JavaExec, group: 'verification') {
-
-    doFirst {
-        delete 'src/test/jastadd/multiple/Multiple.ast', 'src/test/jastadd/multiple/Multiple.jadd'
-    }
-
-    classpath = sourceSets.main.runtimeClasspath
-    main = 'org.jastadd.relast.compiler.Compiler'
-    //noinspection GroovyAssignabilityCheck
-    args 'src/test/jastadd/multiple/Part1.relast', '--useJastAddNames', 'src/test/jastadd/multiple/Part2.relast', 'src/test/jastadd/multiple/Part3.relast', '--file', '--grammarName=src/test/jastadd/multiple/Multiple'
-}
-
-task compileMultipleTest(type: JavaExec, group: 'verification') {
-
-    doFirst {
-        delete 'src/test/java-gen/multiple'
-    }
-
-    classpath = sourceSets.main.runtimeClasspath
-    main = 'org.jastadd.JastAdd'
-    //noinspection GroovyAssignabilityCheck
-    args '--o=src/test/java-gen/', '--package=multiple.ast',
-            'src/test/jastadd/multiple/Multiple.ast',
-            'src/test/jastadd/multiple/Multiple.jadd',
-            'src/test/jastadd/Utils.jadd'
-}
-
-task preprocessResolverTest(type: JavaExec, group: 'verification') {
-
-    doFirst {
-        delete 'src/test/jastadd/resolver/Resolver.ast', 'src/test/jastadd/resolver/Resolver.jadd', 'src/test/jastadd/resolver/ResolverRefResolver.jadd', 'src/test/jastadd/resolver/ResolverResolverStubs.jrag'
-    }
-
-    classpath = sourceSets.main.runtimeClasspath
-    main = 'org.jastadd.relast.compiler.Compiler'
-    //noinspection GroovyAssignabilityCheck
-    args 'src/test/jastadd/resolver/Resolver.relast', '--useJastAddNames', '--file', '--grammarName=src/test/jastadd/resolver/Resolver', '--resolverHelper'
-}
-
-task compileResolverTest(type: JavaExec, group: 'verification') {
-
-    doFirst {
-        delete 'src/test/java-gen/resolver'
-    }
+test.dependsOn compileRelationTest
+compileRelationTest.dependsOn doublePreprocessRelationTest
+doublePreprocessRelationTest.dependsOn preprocessRelationTest
 
-    classpath = sourceSets.main.runtimeClasspath
-    main = 'org.jastadd.JastAdd'
-    //noinspection GroovyAssignabilityCheck
-    args '--o=src/test/java-gen/', '--package=resolver.ast',
-            'src/test/jastadd/resolver/Resolver.ast',
-            'src/test/jastadd/resolver/Resolver.jadd',
+task compileDefaultNamesTest(type: RelastTest) {
+    relastFiles 'src/test/jastadd/relations/Relations.relast'
+    grammarName = 'src/test/jastadd/relations/Relations3'
+    packageName = 'defaultnames.ast'
+    moreInputFiles 'src/test/jastadd/Utils.jadd'
+}
+
+task compileDefaultNamesResolverTest(type: RelastTest) {
+    relastFiles 'src/test/jastadd/resolver/Resolver.relast'
+    grammarName = 'src/test/jastadd/resolver/Resolver2'
+    resolverHelper = true
+    packageName = 'defaultnames.resolver.ast'
+    moreInputFiles 'src/test/jastadd/Utils.jadd',
+                   'src/test/jastadd/resolver/ResolverUtils.jadd',
+                   'src/test/jastadd/resolver/MyRefResolver.jadd'
+}
+
+task compileLowerBoundsTest(type: RelastTest) {
+    relastFiles 'src/test/jastadd/lowerbounds/LowerBounds.relast'
+    grammarName = 'src/test/jastadd/lowerbounds/LowerBounds'
+    useJastAddNames = true
+    packageName = 'lowerbounds.ast'
+    moreInputFiles 'src/test/jastadd/Utils.jadd'
+}
+
+task compileMultipleTest(type: RelastTest) {
+    relastFiles 'src/test/jastadd/multiple/Part1.relast',
+                'src/test/jastadd/multiple/Part2.relast',
+                'src/test/jastadd/multiple/Part3.relast'
+    grammarName = 'src/test/jastadd/multiple/Multiple'
+    useJastAddNames = true
+    packageName = 'multiple.ast'
+    moreInputFiles 'src/test/jastadd/Utils.jadd'
+}
+
+task compileResolverTest(type: RelastTest) {
+    relastFiles 'src/test/jastadd/resolver/Resolver.relast'
+    grammarName = 'src/test/jastadd/resolver/Resolver'
+    useJastAddNames = true
+    resolverHelper = true
+    packageName = 'resolver.ast'
+    moreInputFiles 'src/test/jastadd/Utils.jadd',
             'src/test/jastadd/resolver/ResolverUtils.jadd',
-            'src/test/jastadd/resolver/ResolverRefResolver.jadd',
-            'src/test/jastadd/resolver/ResolverResolverStubs.jrag',
-            'src/test/jastadd/resolver/MyRefResolver.jadd',
-            'src/test/jastadd/Utils.jadd'
+            'src/test/jastadd/resolver/MyRefResolver.jadd'
 }
 
-
-task preprocessResolver2Test(type: JavaExec, group: 'verification') {
-
-    doFirst {
-        delete 'src/test/jastadd/resolver2/Resolver.ast', 'src/test/jastadd/resolver2/Resolver.jadd', 'src/test/jastadd/resolver2/ResolverRefResolver.jadd'
-    }
-
-    classpath = sourceSets.main.runtimeClasspath
-    main = 'org.jastadd.relast.compiler.Compiler'
-    //noinspection GroovyAssignabilityCheck
-    args 'src/test/jastadd/resolver2/Resolver.relast', '--useJastAddNames', '--file', '--grammarName=src/test/jastadd/resolver2/Resolver', '--resolverHelper'
-}
-
-task compileResolver2Test(type: JavaExec, group: 'verification') {
-
-    doFirst {
-        delete 'src/test/java-gen/resolver2'
-    }
-
-    classpath = sourceSets.main.runtimeClasspath
-    main = 'org.jastadd.JastAdd'
-    //noinspection GroovyAssignabilityCheck
-    args '--o=src/test/java-gen/', '--package=resolver2.ast',
-            'src/test/jastadd/resolver2/Resolver.ast',
-            'src/test/jastadd/resolver2/Resolver.jadd',
+task compileResolver2Test(type: RelastTest) {
+    relastFiles 'src/test/jastadd/resolver2/Resolver.relast'
+    grammarName = 'src/test/jastadd/resolver2/Resolver'
+    useJastAddNames = true
+    resolverHelper = true
+    packageName = 'resolver2.ast'
+    moreInputFiles 'src/test/jastadd/Utils.jadd',
             'src/test/jastadd/resolver2/ResolverUtils.jadd',
-            'src/test/jastadd/resolver2/ResolverRefResolver.jadd',
-            'src/test/jastadd/resolver2/ResolverResolverStubs.jrag',
-            'src/test/jastadd/resolver2/MyRefResolver.jadd',
-            'src/test/jastadd/Utils.jadd'
+            'src/test/jastadd/resolver2/MyRefResolver.jadd'
 }
 
-task preprocessListNamesTest(type: JavaExec, group: 'verification') {
-
-    doFirst {
-        delete 'src/test/jastadd/listnames/ListNames.ast', 'src/test/jastadd/listnames/ListNames.jadd'
-    }
-
-    classpath = sourceSets.main.runtimeClasspath
-    main = 'org.jastadd.relast.compiler.Compiler'
-    //noinspection GroovyAssignabilityCheck
-    args 'src/test/jastadd/listnames/ListNames.relast', '--useJastAddNames', '--file', '--grammarName=src/test/jastadd/listnames/ListNames', '--jastAddList=ListyMcListface'
+task compileListNamesTest(type: RelastTest) {
+    relastFiles 'src/test/jastadd/listnames/ListNames.relast'
+    grammarName = 'src/test/jastadd/listnames/ListNames'
+    useJastAddNames = true
+    jastAddList = 'ListyMcListface'
+    packageName = 'listnames.ast'
+    moreInputFiles 'src/test/jastadd/Utils.jadd'
 }
 
-task compileListNamesTest(type: JavaExec, group: 'verification') {
-
-    doFirst {
-        delete 'src/test/java-gen/listnames'
-    }
-
-    classpath = sourceSets.main.runtimeClasspath
-    main = 'org.jastadd.JastAdd'
-    //noinspection GroovyAssignabilityCheck
-    args '--o=src/test/java-gen/', '--package=listnames.ast', '--List=ListyMcListface',
-            'src/test/jastadd/listnames/ListNames.ast',
-            'src/test/jastadd/listnames/ListNames.jadd',
-            'src/test/jastadd/Utils.jadd'
+task compileSerializerTest(type: RelastTest) {
+    relastFiles 'src/test/jastadd/serializer/Serializer.relast'
+    grammarName = 'src/test/jastadd/serializer/Serializer'
+    useJastAddNames = true
+    serializer = 'jackson'
+    packageName = 'serializer.ast'
+    moreInputFiles 'src/test/jastadd/Utils.jadd'
 }
 
-task preprocessSerializerTest(type: JavaExec, group: 'verification') {
-
-    doFirst {
-        delete 'src/test/jastadd/serializer/Serializer.ast',
-                'src/test/jastadd/serializer/Serializer.jadd',
-                'src/test/jastadd/serializer/SerializerRefResolver.jadd',
-                'src/test/jastadd/serializer/SerializerSerializer.jadd',
-                'src/test/jastadd/serializer/SerializerRefResolver.jadd',
-                'src/test/jastadd/serializer/SerializerResolverStubs.jrag'
-    }
-
-    classpath = sourceSets.main.runtimeClasspath
-    main = 'org.jastadd.relast.compiler.Compiler'
-    //noinspection GroovyAssignabilityCheck
-    args 'src/test/jastadd/serializer/Serializer.relast', '--useJastAddNames', '--file', '--grammarName=src/test/jastadd/serializer/Serializer', '--serializer=jackson'
-}
-
-task compileSerializerTest(type: JavaExec, group: 'verification') {
-
-    doFirst {
-        delete 'src/test/java-gen/serializer'
-    }
-
-    classpath = sourceSets.main.runtimeClasspath
-    main = 'org.jastadd.JastAdd'
-    //noinspection GroovyAssignabilityCheck
-    args '--o=src/test/java-gen/', '--package=serializer.ast',
-            'src/test/jastadd/serializer/Serializer.ast',
-            'src/test/jastadd/serializer/Serializer.jadd',
-            'src/test/jastadd/serializer/SerializerRefResolver.jadd',
-            'src/test/jastadd/serializer/SerializerSerializer.jadd',
-            'src/test/jastadd/serializer/SerializerResolverStubs.jrag',
-            'src/test/jastadd/Utils.jadd'
-}
-
-task preprocessSerializerOriginalNamesTest(type: JavaExec, group: 'verification') {
-
-    doFirst {
-        delete 'src/test/jastadd/serializer-names/Serializer.ast',
-                'src/test/jastadd/serializer-names/Serializer.jadd',
-                'src/test/jastadd/serializer-names/SerializerRefResolver.jadd',
-                'src/test/jastadd/serializer-names/SerializerSerializer.jadd',
-                'src/test/jastadd/serializer-names/SerializerRefResolver.jadd',
-                'src/test/jastadd/serializer-names/SerializerResolverStubs.jrag'
-    }
-
-    classpath = sourceSets.main.runtimeClasspath
-    main = 'org.jastadd.relast.compiler.Compiler'
-    //noinspection GroovyAssignabilityCheck
-    args 'src/test/jastadd/serializer-names/Serializer.relast', '--file', '--grammarName=src/test/jastadd/serializer-names/Serializer', '--serializer=jackson'
-}
-
-task compileSerializerOriginalNamesTest(type: JavaExec, group: 'verification') {
-
-    doFirst {
-        delete 'src/test/java-gen/serializer'
-    }
-
-    classpath = sourceSets.main.runtimeClasspath
-    main = 'org.jastadd.JastAdd'
-    //noinspection GroovyAssignabilityCheck
-    args '--o=src/test/java-gen/', '--package=defaultnames.serializer.ast',
-            'src/test/jastadd/serializer-names/Serializer.ast',
-            'src/test/jastadd/serializer-names/Serializer.jadd',
-            'src/test/jastadd/serializer-names/SerializerRefResolver.jadd',
-            'src/test/jastadd/serializer-names/SerializerSerializer.jadd',
-            'src/test/jastadd/serializer-names/SerializerResolverStubs.jrag',
-            'src/test/jastadd/Utils.jadd'
+task compileSerializerDefaultNamesTest(type: RelastTest) {
+    relastFiles 'src/test/jastadd/serializer-names/Serializer.relast'
+    grammarName = 'src/test/jastadd/serializer-names/Serializer'
+    serializer = 'jackson'
+    packageName = 'defaultnames.serializer.ast'
+    moreInputFiles 'src/test/jastadd/Utils.jadd'
 }
 
 test {
     outputs.upToDateWhen { false }
     useJUnitPlatform()
 }
-
-
-test.dependsOn compileRelationTest
-compileRelationTest.dependsOn doublePreprocessRelationTest
-doublePreprocessRelationTest.dependsOn preprocessRelationTest
-
-test.dependsOn compileDefaultNamesTest
-compileDefaultNamesTest.dependsOn preprocessDefaultNamesTest
-test.dependsOn compileDefaultNamesResolverTest
-compileDefaultNamesResolverTest.dependsOn preprocessDefaultNamesResolverTest
-
-test.dependsOn compileLowerBoundsTest
-compileLowerBoundsTest.dependsOn preprocessLowerBoundsTest
-
-test.dependsOn compileMultipleTest
-compileMultipleTest.dependsOn preprocessMultipleTest
-
-test.dependsOn compileResolverTest
-compileResolverTest.dependsOn preprocessResolverTest
-
-test.dependsOn compileResolver2Test
-compileResolver2Test.dependsOn preprocessResolver2Test
-
-test.dependsOn compileListNamesTest
-compileListNamesTest.dependsOn preprocessListNamesTest
-
-test.dependsOn compileSerializerTest
-compileSerializerTest.dependsOn preprocessSerializerTest
-
-
-test.dependsOn compileSerializerOriginalNamesTest
-compileSerializerOriginalNamesTest.dependsOn preprocessSerializerOriginalNamesTest
diff --git a/buildSrc/src/main/java/org/jastadd/relast/plugin/RelastPlugin.java b/buildSrc/src/main/java/org/jastadd/relast/plugin/RelastPlugin.java
new file mode 100644
index 0000000000000000000000000000000000000000..392c2e03c57c3d5235770b4dadc402504ef9cb5f
--- /dev/null
+++ b/buildSrc/src/main/java/org/jastadd/relast/plugin/RelastPlugin.java
@@ -0,0 +1,33 @@
+package org.jastadd.relast.plugin;
+
+import org.gradle.api.Plugin;
+import org.gradle.api.Project;
+import org.gradle.api.Task;
+import org.gradle.api.tasks.TaskCollection;
+
+import java.util.Set;
+
+/**
+ * Plugin for RelAst-Test.
+ *
+ * @author rschoene - Initial contribution
+ */
+public class RelastPlugin implements Plugin<Project> {
+
+  private Task testTask;
+
+  @Override
+  public void apply(Project project) {
+    Set<Task> tasks = project.getTasksByName("test", false);
+    // there should be only one task "test"
+    testTask = tasks.iterator().next();
+    TaskCollection<RelastTest> relastTests = project.getTasks().withType(RelastTest.class);
+    relastTests.forEach(this::setupRelastTest);
+    relastTests.whenTaskAdded(this::setupRelastTest);
+  }
+
+  private void setupRelastTest(RelastTest relastTest) {
+    testTask.dependsOn(relastTest);
+    relastTest.setGroup("verification");
+  }
+}
diff --git a/buildSrc/src/main/java/org/jastadd/relast/plugin/RelastTest.java b/buildSrc/src/main/java/org/jastadd/relast/plugin/RelastTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..dba3838d2771c688415026a6f798ab1d086db780
--- /dev/null
+++ b/buildSrc/src/main/java/org/jastadd/relast/plugin/RelastTest.java
@@ -0,0 +1,251 @@
+package org.jastadd.relast.plugin;
+
+import org.gradle.api.DefaultTask;
+import org.gradle.api.Project;
+import org.gradle.api.file.FileCollection;
+import org.gradle.api.plugins.JavaPlugin;
+import org.gradle.api.tasks.SourceSet;
+import org.gradle.api.tasks.SourceSetContainer;
+import org.gradle.api.tasks.TaskAction;
+
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * RelAst Test Task
+ *
+ * @author rschoene - Initial contribution
+ */
+@SuppressWarnings({"unused", "WeakerAccess"})
+public class RelastTest extends DefaultTask {
+  // general options
+  private boolean verbose = false;
+  // pre-process options
+  private List<String> relastFiles = new ArrayList<>();
+  private boolean useJastAddNames;
+  private boolean resolverHelper;
+  private boolean writeToFile = true;
+  private String grammarName;
+  private String listClass;
+  private String jastAddList;
+  private String serializer;
+
+  // compile options
+  private boolean runJastAdd = true;
+  private String outputDir = "src/test/java-gen/";
+  private String packageName;
+  private List<String> moreInputFiles = new ArrayList<>();
+
+  public boolean isVerbose() {
+    return verbose;
+  }
+
+  public void setVerbose(boolean verbose) {
+    this.verbose = verbose;
+  }
+
+  // pre-process options
+  public List<String> getRelastFiles() {
+    return relastFiles;
+  }
+
+  public void relastFiles(String relastFile) {
+    this.relastFiles.add(relastFile);
+  }
+
+  public void relastFiles(String[] relastFilesArray) {
+    this.relastFiles = Arrays.asList(relastFilesArray);
+  }
+
+  public boolean isUseJastAddNames() {
+    return useJastAddNames;
+  }
+
+  public void setUseJastAddNames(boolean useJastAddNames) {
+    this.useJastAddNames = useJastAddNames;
+  }
+
+  public boolean isResolverHelper() {
+    return resolverHelper;
+  }
+
+  public void setResolverHelper(boolean resolverHelper) {
+    this.resolverHelper = resolverHelper;
+  }
+
+  public boolean isWriteToFile() {
+    return writeToFile;
+  }
+
+  public void setWriteToFile(boolean writeToFile) {
+    this.writeToFile = writeToFile;
+  }
+
+  public String getGrammarName() {
+    return grammarName;
+  }
+
+  public void setGrammarName(String grammarName) {
+    this.grammarName = grammarName;
+  }
+
+  public String getListClass() {
+    return listClass;
+  }
+
+  public void setListClass(String listClass) {
+    this.listClass = listClass;
+  }
+
+  public String getJastAddList() {
+    return jastAddList;
+  }
+
+  public void setJastAddList(String jastAddList) {
+    this.jastAddList = jastAddList;
+  }
+
+  public String getSerializer() {
+    return serializer;
+  }
+
+  public void setSerializer(String serializer) {
+    this.serializer = serializer;
+  }
+
+  // compile options
+  public boolean isRunJastAdd() {
+    return runJastAdd;
+  }
+
+  public void setRunJastAdd(boolean runJastAdd) {
+    this.runJastAdd = runJastAdd;
+  }
+
+  public String getOutputDir() {
+    return outputDir;
+  }
+
+  public void setOutputDir(String outputDir) {
+    this.outputDir = outputDir;
+  }
+
+  public String getPackageName() {
+    return packageName;
+  }
+
+  public void setPackageName(String packageName) {
+    this.packageName = packageName;
+  }
+
+  public List<String> getMoreInputFiles() {
+    return moreInputFiles;
+  }
+
+  public void moreInputFiles(String f) {
+    this.moreInputFiles.add(f);
+  }
+
+  public void moreInputFiles(String[] fileArray) {
+    this.moreInputFiles.addAll(Arrays.asList(fileArray));
+  }
+
+  private boolean isSet(String option) {
+    return option != null && !option.isEmpty();
+  }
+
+  private String[] genSuffixes = {".ast", ".jadd", "RefResolver.jadd", "ResolverStubs.jrag", "Serializer.jadd"};
+
+  @TaskAction
+  void runTest() {
+    setGroup("verification");
+    setDescription("Runs a relast test");
+    Project project = getProject();
+    if (isVerbose()) {
+      System.out.println("Running relast test");
+      System.out.println("relast files: " + getRelastFiles());
+      System.out.println("Deleting files");
+    }
+    // first, delete generated files
+    List<String> genFiles = new ArrayList<>();
+    for (String suffix : genSuffixes) {
+      genFiles.add(getGrammarName() + suffix);
+    }
+    if (isVerbose()) {
+      System.out.println("gen files: " + genFiles);
+    }
+    project.delete(deleteSpec -> {
+      deleteSpec.delete(genFiles);
+      if (isSet(getPackageName())) {
+        deleteSpec.delete(Paths.get(getOutputDir(), getPackageName()));
+      }
+    });
+    if (isVerbose()) {
+      System.out.println("Pre processing, running relast");
+    }
+    // then, run relast pre processing
+    project.getPlugins().withType(JavaPlugin.class, javaPlugin -> {
+      SourceSetContainer sourceSets = (SourceSetContainer) project.getProperties().get("sourceSets");
+      FileCollection runtimeClasspath = sourceSets.getByName(SourceSet.MAIN_SOURCE_SET_NAME).getRuntimeClasspath();
+      project.javaexec(javaExecSpec -> {
+        javaExecSpec.setClasspath(runtimeClasspath);
+        javaExecSpec.setMain("org.jastadd.relast.compiler.Compiler");
+        List<Object> args = new ArrayList<>(getRelastFiles());
+        if (isWriteToFile()) {
+          args.add("--file");
+        }
+        if (isUseJastAddNames()) {
+          args.add("--useJastAddNames");
+        }
+        if (isResolverHelper()) {
+          args.add("--resolverHelper");
+        }
+        if (isSet(getJastAddList())) {
+          args.add("--jastAddList=" + getJastAddList());
+        }
+        if (isSet(getListClass())) {
+          args.add("--listClass=" + getListClass());
+        }
+        if (isSet(getSerializer())) {
+          args.add("--serializer=" + getSerializer());
+        }
+        args.add("--grammarName=" + getGrammarName());
+        if (isVerbose()) {
+          System.out.println("Start relast with args: " + args);
+        }
+        javaExecSpec.args(args);
+      });
+    });
+    if (isRunJastAdd()) {
+      if (isVerbose()) {
+        System.out.println("Compile with JastAdd");
+      }
+      // check which files were actually generated
+      genFiles.removeIf(s -> !Paths.get(s).toFile().exists());
+      // finally, compile generated files
+      project.getPlugins().withType(JavaPlugin.class, javaPlugin -> {
+        SourceSetContainer sourceSets = (SourceSetContainer) project.getProperties().get("sourceSets");
+        FileCollection runtimeClasspath = sourceSets.getByName(SourceSet.MAIN_SOURCE_SET_NAME).getRuntimeClasspath();
+        project.javaexec(javaExecSpec -> {
+          javaExecSpec.setClasspath(runtimeClasspath);
+          javaExecSpec.setMain("org.jastadd.JastAdd");
+          List<Object> args = new ArrayList<>();
+          args.add("--o=" + getOutputDir());
+          args.add("--package=" + getPackageName());
+          if (isSet(getJastAddList())) {
+            args.add("--List=" + getJastAddList());
+          }
+          args.addAll(genFiles);
+          args.addAll(getMoreInputFiles());
+          if (isVerbose()) {
+            System.out.println("Start JastAdd with args: " + args);
+          }
+          javaExecSpec.args(args);
+        });
+      });
+    }
+  }
+
+}
diff --git a/buildSrc/src/main/resources/META-INF/gradle-plugins/org.jastadd.relast.plugin.properties b/buildSrc/src/main/resources/META-INF/gradle-plugins/org.jastadd.relast.plugin.properties
new file mode 100644
index 0000000000000000000000000000000000000000..20222b8953522469ec2c0340ea3aeb5ed6294d13
--- /dev/null
+++ b/buildSrc/src/main/resources/META-INF/gradle-plugins/org.jastadd.relast.plugin.properties
@@ -0,0 +1 @@
+implementation-class=org.jastadd.relast.plugin.RelastPlugin