diff --git a/Hanoi-all.jar b/Hanoi-all.jar
new file mode 100644
index 0000000000000000000000000000000000000000..2def939ad0ca004c7e3854c063d3f2382bf3586e
Binary files /dev/null and b/Hanoi-all.jar differ
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000000000000000000000000000000000000..29f81d812f3e768fa89638d1f72920dbfd1413a8
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,201 @@
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
diff --git a/build.gradle b/build.gradle
new file mode 100644
index 0000000000000000000000000000000000000000..cb6c82bfa51ab87e3d6bd85799c70823bdc7e23d
--- /dev/null
+++ b/build.gradle
@@ -0,0 +1,185 @@
+apply plugin: 'java-library'
+apply plugin: 'jastadd'
+apply plugin: 'application'
+apply plugin: 'com.google.protobuf'
+
+
+mainClassName = 'de.tudresden.inf.st.ag.starter.StarterMain'
+
+allprojects {
+    group 'de.tudresden.inf.st'
+}
+
+sourceCompatibility = 1.11
+targetCompatibility = 1.11
+
+configurations {
+  baseRuntimeClasspath
+  //ragconnectClasspath
+  grammar2umlClasspath
+}
+
+repositories {
+    mavenCentral()
+    jcenter()
+      maven {
+        name "gitlab-maven"
+        url "https://git-st.inf.tu-dresden.de/api/v4/groups/jastadd/-/packages/maven"
+      }
+}
+
+buildscript {
+    repositories.jcenter()
+    dependencies {
+        classpath 'org.jastadd:jastaddgradle:1.13.3'
+        classpath 'com.google.protobuf:protobuf-gradle-plugin:0.8.16'
+    }
+}
+
+dependencies {
+    //ragconnectClasspath group: 'de.tudresden.inf.st', name: 'ragconnect', version: '0.3.1'
+    implementation group: 'com.fasterxml.jackson.core', name: 'jackson-databind', version: "${jackson_version}"
+    implementation group: 'com.fasterxml.jackson.dataformat', name: 'jackson-dataformat-yaml', version: "${jackson_version}"
+    api group: 'com.google.protobuf', name: 'protobuf-java', version: '3.0.0'
+    implementation group: 'org.apache.logging.log4j', name: 'log4j-api', version: '2.11.2'
+    implementation group: 'org.apache.logging.log4j', name: 'log4j-core', version: '2.11.2'
+    implementation group: 'org.apache.logging.log4j', name: 'log4j-jul', version: '2.11.2'
+    implementation group: 'org.fusesource.mqtt-client', name: 'mqtt-client', version: '1.15'
+    jastadd2 group: 'org.jastadd', name: 'jastadd', version: '2.3.5'
+    grammar2umlClasspath group: 'de.tudresden.inf.st', name: 'grammar2uml', version: '0.1.1'
+}   
+
+File protoSrc = file("src/main/common/proto")
+File genSrc = file("src/gen/java")
+sourceSets.main.java.srcDir genSrc
+sourceSets.main.proto.srcDir protoSrc
+// idea.module.generatedSourceDirs += genSrc
+
+//File robotModel = file('./src/main/jastadd/robot/RobotModel.relast')
+//File componentModel = file('./src/main/jastadd/component/ComponentModel.relast')
+File Constraint = file('./src/main/jastadd/hanoi/Constraint.relast')
+File Hanoi = file('./src/main/jastadd/hanoi/Hanoi.relast')
+//File actionModel = file('./src/main/jastadd/action/ActionModel.relast')
+//File containerModel = file('./src/main/jastadd/container/ContainerModel.relast')
+
+protobuf {
+    protoc {
+        artifact = 'com.google.protobuf:protoc:3.0.0'
+    }
+    generateProtoTasks {
+        all().each { task ->
+            
+        }
+        ofSourceSet('main')
+
+}
+}
+
+
+def relastFiles = ['src/main/jastadd/hanoi/Constraint.relast', "src/main/jastadd/hanoi/Hanoi.relast"]
+
+test {
+  include 'src/main/java/de/tudresden/inf/st/ag/starter/**'
+  testLogging {
+    events 'passed', 'failed'
+    showExceptions = true
+    showStackTraces = true
+    exceptionFormat = 'full'
+  }
+}
+task jarAll(type: Jar) {
+  destinationDir = projectDir
+  manifest.attributes 'Main-Class': 'de.tudresden.inf.st.ag.starter.StarterMain'
+  baseName = "${project.name}-all"
+  from { configurations.compile.collect { it.isDirectory() ? it : zipTree(it) } }
+  with jar
+}
+
+clean.dependsOn 'cleanJarAll'
+
+task cleanJarAll(type: Delete) {
+  delete jarAll.outputs.files
+}
+
+task relast(type: JavaExec) {
+    group = 'Build'
+    main = "-jar"
+
+    args(["./libs/relast.jar",
+            "--grammarName=./src/gen/jastadd/ag",
+            "--useJastAddNames",
+            "--listClass=java.util.ArrayList",
+            "--jastAddList=JastAddList",
+            "--resolverHelper",
+            "--file"]
+    +
+            relastFiles)
+
+    inputs.files relastFiles
+    outputs.files("./src/gen/jastadd/ag.ast",
+            "./src/gen/jastadd/ag.jadd")
+}
+task grammar2uml(type: JavaExec) {
+    group = 'Build'
+    main = 'de.tudresden.inf.st.jastadd.grammar2uml.compiler.Compiler'
+    classpath = configurations.grammar2umlClasspath
+    args([
+            '--verbose',
+            //constraintModel,
+            Hanoi
+    ])
+}
+jastadd {
+    configureModuleBuild()
+    modules {
+        module("ag") {
+            java {
+                basedir "."
+                include "ag/src/main/**/*.java"
+                include "ag/src/gen/**/*.java"
+            }
+
+            jastadd {
+                basedir "./"
+                include "src/main/jastadd/**/*.ast"
+                include "src/main/jastadd/**/*.jadd"
+                include "src/main/jastadd/**/*.jrag"
+                include "src/gen/jastadd/*.ast"
+                include "src/gen/jastadd/*.jadd"
+                include "src/gen/jastadd/*.jrag"
+            }
+        }
+        
+    }
+
+    cleanGen.doFirst {
+        delete "src/gen/java/org"
+        delete "src/gen-res/BuildInfo.properties"
+    }
+
+    preprocessParser.doFirst {
+
+        args += ["--no-beaver-symbol"]
+
+    }
+
+    module = "ag"
+    //astPackage = "AST"
+    astPackage = 'org.jastadd.ag.ast'
+
+    genDir = 'src/gen/java'
+
+    buildInfoDir = 'src/gen-res'
+
+    extraJastAddOptions = [
+            '--lineColumnNumbers',
+            '--List=JastAddList',
+            '--cache=all',
+            "--flush=api",
+            "--incremental=param",
+            "--tracing=cache,flush",
+    ]
+
+}
+
+generateAst.dependsOn relast
\ No newline at end of file
diff --git a/gradle.properties b/gradle.properties
new file mode 100644
index 0000000000000000000000000000000000000000..4a4f87a541ad93095b373d452fab786947f0436b
--- /dev/null
+++ b/gradle.properties
@@ -0,0 +1,2 @@
+jackson_version = 2.9.8
+apache_httpcomponents_version = 4.5.8
\ No newline at end of file
diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 0000000000000000000000000000000000000000..62d4c053550b91381bbd28b1afc82d634bf73a8a
Binary files /dev/null and b/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 0000000000000000000000000000000000000000..e6b7a42279df54936a1180635f971748bb3d9a35
--- /dev/null
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,5 @@
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-6.3-bin.zip
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
diff --git a/gradlew b/gradlew
new file mode 100644
index 0000000000000000000000000000000000000000..ae56c954ade9dcfed1e24ee1a5b87137fca04974
--- /dev/null
+++ b/gradlew
@@ -0,0 +1,185 @@
+#!/usr/bin/env sh
+
+#
+# Copyright 2015 the original author or authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+##############################################################################
+##
+##  Gradle start up script for UN*X
+##
+##############################################################################
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+    ls=`ls -ld "$PRG"`
+    link=`expr "$ls" : '.*-> \(.*\)$'`
+    if expr "$link" : '/.*' > /dev/null; then
+        PRG="$link"
+    else
+        PRG=`dirname "$PRG"`"/$link"
+    fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >/dev/null
+APP_HOME="`pwd -P`"
+cd "$SAVED" >/dev/null
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn () {
+    echo "$*"
+}
+
+die () {
+    echo
+    echo "$*"
+    echo
+    exit 1
+}
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+nonstop=false
+case "`uname`" in
+  CYGWIN* )
+    cygwin=true
+    ;;
+  Darwin* )
+    darwin=true
+    ;;
+  MINGW* )
+    msys=true
+    ;;
+  NONSTOP* )
+    nonstop=true
+    ;;
+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
+        # IBM's JDK on AIX uses strange locations for the executables
+        JAVACMD="$JAVA_HOME/jre/sh/java"
+    else
+        JAVACMD="$JAVA_HOME/bin/java"
+    fi
+    if [ ! -x "$JAVACMD" ] ; then
+        die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+    fi
+else
+    JAVACMD="java"
+    which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
+    MAX_FD_LIMIT=`ulimit -H -n`
+    if [ $? -eq 0 ] ; then
+        if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+            MAX_FD="$MAX_FD_LIMIT"
+        fi
+        ulimit -n $MAX_FD
+        if [ $? -ne 0 ] ; then
+            warn "Could not set maximum file descriptor limit: $MAX_FD"
+        fi
+    else
+        warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+    fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+if $darwin; then
+    GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
+fi
+
+# For Cygwin or MSYS, switch paths to Windows format before running java
+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
+    ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+    SEP=""
+    for dir in $ROOTDIRSRAW ; do
+        ROOTDIRS="$ROOTDIRS$SEP$dir"
+        SEP="|"
+    done
+    OURCYGPATTERN="(^($ROOTDIRS))"
+    # Add a user-defined pattern to the cygpath arguments
+    if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+        OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+    fi
+    # Now convert the arguments - kludge to limit ourselves to /bin/sh
+    i=0
+    for arg in "$@" ; do
+        CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+        CHECK2=`echo "$arg"|egrep -c "^-"`                                 ### Determine if an option
+
+        if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then                    ### Added a condition
+            eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+        else
+            eval `echo args$i`="\"$arg\""
+        fi
+        i=`expr $i + 1`
+    done
+    case $i in
+        0) set -- ;;
+        1) set -- "$args0" ;;
+        2) set -- "$args0" "$args1" ;;
+        3) set -- "$args0" "$args1" "$args2" ;;
+        4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+        5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+        6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+        7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+        8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+        9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+    esac
+fi
+
+# Escape application args
+save () {
+    for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
+    echo " "
+}
+APP_ARGS=`save "$@"`
+
+# Collect all arguments for the java command, following the shell quoting and substitution rules
+eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
+
+exec "$JAVACMD" "$@"
diff --git a/gradlew.bat b/gradlew.bat
new file mode 100644
index 0000000000000000000000000000000000000000..a9f778a7a964b6f01c904ee667903f005d6df556
--- /dev/null
+++ b/gradlew.bat
@@ -0,0 +1,104 @@
+@rem
+@rem Copyright 2015 the original author or authors.
+@rem
+@rem Licensed under the Apache License, Version 2.0 (the "License");
+@rem you may not use this file except in compliance with the License.
+@rem You may obtain a copy of the License at
+@rem
+@rem      https://www.apache.org/licenses/LICENSE-2.0
+@rem
+@rem Unless required by applicable law or agreed to in writing, software
+@rem distributed under the License is distributed on an "AS IS" BASIS,
+@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+@rem See the License for the specific language governing permissions and
+@rem limitations under the License.
+@rem
+
+@if "%DEBUG%" == "" @echo off
+@rem ##########################################################################
+@rem
+@rem  Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+set DIRNAME=%~dp0
+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"
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if "%ERRORLEVEL%" == "0" goto init
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto init
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+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%
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="0" goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+if  not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/libs/relast.jar b/libs/relast.jar
new file mode 100644
index 0000000000000000000000000000000000000000..b1a7542048dd1611db7f479307b0285efd8bb1f6
Binary files /dev/null and b/libs/relast.jar differ
diff --git a/settings.gradle b/settings.gradle
new file mode 100644
index 0000000000000000000000000000000000000000..585d4502ced8fa5a3a28d9d4e8ec4cf934fcb468
--- /dev/null
+++ b/settings.gradle
@@ -0,0 +1 @@
+rootProject.name = 'Hanoi'
\ No newline at end of file
diff --git a/src/gen-res/BuildInfo.properties b/src/gen-res/BuildInfo.properties
new file mode 100644
index 0000000000000000000000000000000000000000..05a6feb8ab29e1ecc05a0371f5cee34ad5adf584
--- /dev/null
+++ b/src/gen-res/BuildInfo.properties
@@ -0,0 +1,7 @@
+#Wed, 01 Dec 2021 07:40:25 +0100
+
+moduleId=ag
+moduleName=null
+moduleVariant=null
+timestamp=2021-12-01T07\:40Z
+build.date=2021-12-01
diff --git a/src/gen/jastadd/ag.ast b/src/gen/jastadd/ag.ast
new file mode 100644
index 0000000000000000000000000000000000000000..a0bae6f5f8f9617fa4af64ee800e9f7f68042167
--- /dev/null
+++ b/src/gen/jastadd/ag.ast
@@ -0,0 +1,17 @@
+Root ::= BinaryConstraint* UnaryConstraint* Atom*;
+abstract Constraint;
+abstract Atom : Constraint ::= <_impl_Rel:java.util.List<Pillar>>;
+abstract UnaryConstraint : Constraint ::= Constraint;
+abstract BinaryConstraint : Constraint ::= Left:Constraint Right:Constraint;
+Conjunction : BinaryConstraint;
+Disjunction : BinaryConstraint;
+Implication : BinaryConstraint;
+Negation : UnaryConstraint;
+CheckSize : Atom;
+CheckSeq : Atom;
+OnoDisk : Atom;
+TnoDisk : Atom;
+CheckD0 : Atom;
+Hanoi ::= Pillar* <AmountD:int>;
+Disk ::= <Size:int>;
+Pillar ::= Disk*;
diff --git a/src/gen/jastadd/ag.jadd b/src/gen/jastadd/ag.jadd
new file mode 100644
index 0000000000000000000000000000000000000000..1ffd0b1ea7d4da57b3b3b790edc91a064b698634
--- /dev/null
+++ b/src/gen/jastadd/ag.jadd
@@ -0,0 +1,90 @@
+aspect RelAstAPI {
+  // api for rel Atom.Rel* -> Pillar
+  // left direction for rel Atom.Rel* -> Pillar
+  public java.util.List<Pillar> Atom.getRels() {
+    return getRelList();
+  }
+  public java.util.List<Pillar> Atom.getRelList() {
+    java.util.List<Pillar> l = get_impl_Rel();
+    if (l != null) {
+      boolean changed = false;
+      for (int i = 0; i < l.size(); i++) {
+        Pillar element = l.get(i);
+        if (element.is$Unresolved()) {
+          changed = true;
+          Pillar resolvedElement = resolveRelByToken(element.as$Unresolved().getUnresolved$Token(), i);
+          l.set(i, resolvedElement);
+        }
+      }
+      if (changed) {
+        set_impl_Rel(l);
+      }
+    }
+    return l != null ? java.util.Collections.unmodifiableList(l) : java.util.Collections.emptyList();
+  }
+  public void Atom.addRel(Pillar o) {
+    assertNotNull(o);
+    java.util.List<Pillar> list = tokenjava_util_List_Pillar___impl_Rel;
+    if (list == null) {
+      list = new java.util.ArrayList<>();
+    }
+    list.add(o);
+    set_impl_Rel(list);
+  }
+  public void Atom.addRel(int index, Pillar o) {
+    assertNotNull(o);
+    java.util.List<Pillar> list = tokenjava_util_List_Pillar___impl_Rel;
+    if (list == null) {
+      list = new java.util.ArrayList<>();
+    }
+    list.add(index, o);
+    set_impl_Rel(list);
+  }
+  public void Atom.removeRel(Pillar o) {
+    assertNotNull(o);
+    java.util.List<Pillar> list = tokenjava_util_List_Pillar___impl_Rel;
+    if (list != null && list.remove(o)) {
+      set_impl_Rel(list);
+    }
+  }
+
+  public boolean ASTNode.violatesLowerBounds() {
+    return !getLowerBoundsViolations().isEmpty();
+  }
+  public java.util.List<Pair<ASTNode, String>> ASTNode.getLowerBoundsViolations() {
+    java.util.List<Pair<ASTNode, String>> list = new java.util.ArrayList<>();
+    computeLowerBoundsViolations(list);
+    return list;
+  }
+  public void ASTNode.computeLowerBoundsViolations(java.util.List<Pair<ASTNode, String>> list) {
+    for (int i = 0; i < getNumChildNoTransform(); i++) {
+      getChildNoTransform(i).computeLowerBoundsViolations(list);
+    }
+  }
+  public class Pair<T1, T2> {
+    public final T1 _1;
+    public final T2 _2;
+    public Pair(T1 _1, T2 _2) {
+      ASTNode.assertNotNull(_1);
+      ASTNode.assertNotNull(_2);
+      this._1 = _1;
+      this._2 = _2;
+    }
+    public boolean equals(Object other) {
+      if (other instanceof Pair) {
+        Pair<?,?> p = (Pair<?,?>) other;
+        return _1.equals(p._1) && _2.equals(p._2);
+      } else {
+        return false;
+      }
+    }
+    public int hashCode() {
+      return 31*_1.hashCode() + _2.hashCode();
+    }
+  }
+  public static void ASTNode.assertNotNull(Object obj) {
+    if (obj == null) {
+      throw new NullPointerException();
+    }
+  }
+}
diff --git a/src/gen/jastadd/agRefResolver.jadd b/src/gen/jastadd/agRefResolver.jadd
new file mode 100644
index 0000000000000000000000000000000000000000..f3af68edc849a0e6f72012e1d6ccdf4386579e36
--- /dev/null
+++ b/src/gen/jastadd/agRefResolver.jadd
@@ -0,0 +1,782 @@
+aspect ReferenceCreation {
+
+  public static Root Root.createRef(String ref) {
+    Unresolved$Root unresolvedNode = new Unresolved$Root();
+    unresolvedNode.setUnresolved$Token(ref);
+    unresolvedNode.setUnresolved$ResolveOpposite(true);
+    return unresolvedNode;
+  }
+  public static Root Root.createRefDirection(String ref) {
+    Unresolved$Root unresolvedNode = new Unresolved$Root();
+    unresolvedNode.setUnresolved$Token(ref);
+    unresolvedNode.setUnresolved$ResolveOpposite(false);
+    return unresolvedNode;
+  }
+  public static Constraint Constraint.createRef(String ref) {
+    Unresolved$CheckSize unresolvedNode = new Unresolved$CheckSize();
+    unresolvedNode.setUnresolved$Token(ref);
+    unresolvedNode.setUnresolved$ResolveOpposite(true);
+    return unresolvedNode;
+  }
+  public static Constraint Constraint.createRefDirection(String ref) {
+    Unresolved$CheckSize unresolvedNode = new Unresolved$CheckSize();
+    unresolvedNode.setUnresolved$Token(ref);
+    unresolvedNode.setUnresolved$ResolveOpposite(false);
+    return unresolvedNode;
+  }
+  public static Atom Atom.createRef(String ref) {
+    Unresolved$CheckSize unresolvedNode = new Unresolved$CheckSize();
+    unresolvedNode.setUnresolved$Token(ref);
+    unresolvedNode.setUnresolved$ResolveOpposite(true);
+    return unresolvedNode;
+  }
+  public static Atom Atom.createRefDirection(String ref) {
+    Unresolved$CheckSize unresolvedNode = new Unresolved$CheckSize();
+    unresolvedNode.setUnresolved$Token(ref);
+    unresolvedNode.setUnresolved$ResolveOpposite(false);
+    return unresolvedNode;
+  }
+  public static UnaryConstraint UnaryConstraint.createRef(String ref) {
+    Unresolved$Negation unresolvedNode = new Unresolved$Negation();
+    unresolvedNode.setUnresolved$Token(ref);
+    unresolvedNode.setUnresolved$ResolveOpposite(true);
+    return unresolvedNode;
+  }
+  public static UnaryConstraint UnaryConstraint.createRefDirection(String ref) {
+    Unresolved$Negation unresolvedNode = new Unresolved$Negation();
+    unresolvedNode.setUnresolved$Token(ref);
+    unresolvedNode.setUnresolved$ResolveOpposite(false);
+    return unresolvedNode;
+  }
+  public static BinaryConstraint BinaryConstraint.createRef(String ref) {
+    Unresolved$Conjunction unresolvedNode = new Unresolved$Conjunction();
+    unresolvedNode.setUnresolved$Token(ref);
+    unresolvedNode.setUnresolved$ResolveOpposite(true);
+    return unresolvedNode;
+  }
+  public static BinaryConstraint BinaryConstraint.createRefDirection(String ref) {
+    Unresolved$Conjunction unresolvedNode = new Unresolved$Conjunction();
+    unresolvedNode.setUnresolved$Token(ref);
+    unresolvedNode.setUnresolved$ResolveOpposite(false);
+    return unresolvedNode;
+  }
+  public static Conjunction Conjunction.createRef(String ref) {
+    Unresolved$Conjunction unresolvedNode = new Unresolved$Conjunction();
+    unresolvedNode.setUnresolved$Token(ref);
+    unresolvedNode.setUnresolved$ResolveOpposite(true);
+    return unresolvedNode;
+  }
+  public static Conjunction Conjunction.createRefDirection(String ref) {
+    Unresolved$Conjunction unresolvedNode = new Unresolved$Conjunction();
+    unresolvedNode.setUnresolved$Token(ref);
+    unresolvedNode.setUnresolved$ResolveOpposite(false);
+    return unresolvedNode;
+  }
+  public static Disjunction Disjunction.createRef(String ref) {
+    Unresolved$Disjunction unresolvedNode = new Unresolved$Disjunction();
+    unresolvedNode.setUnresolved$Token(ref);
+    unresolvedNode.setUnresolved$ResolveOpposite(true);
+    return unresolvedNode;
+  }
+  public static Disjunction Disjunction.createRefDirection(String ref) {
+    Unresolved$Disjunction unresolvedNode = new Unresolved$Disjunction();
+    unresolvedNode.setUnresolved$Token(ref);
+    unresolvedNode.setUnresolved$ResolveOpposite(false);
+    return unresolvedNode;
+  }
+  public static Implication Implication.createRef(String ref) {
+    Unresolved$Implication unresolvedNode = new Unresolved$Implication();
+    unresolvedNode.setUnresolved$Token(ref);
+    unresolvedNode.setUnresolved$ResolveOpposite(true);
+    return unresolvedNode;
+  }
+  public static Implication Implication.createRefDirection(String ref) {
+    Unresolved$Implication unresolvedNode = new Unresolved$Implication();
+    unresolvedNode.setUnresolved$Token(ref);
+    unresolvedNode.setUnresolved$ResolveOpposite(false);
+    return unresolvedNode;
+  }
+  public static Negation Negation.createRef(String ref) {
+    Unresolved$Negation unresolvedNode = new Unresolved$Negation();
+    unresolvedNode.setUnresolved$Token(ref);
+    unresolvedNode.setUnresolved$ResolveOpposite(true);
+    return unresolvedNode;
+  }
+  public static Negation Negation.createRefDirection(String ref) {
+    Unresolved$Negation unresolvedNode = new Unresolved$Negation();
+    unresolvedNode.setUnresolved$Token(ref);
+    unresolvedNode.setUnresolved$ResolveOpposite(false);
+    return unresolvedNode;
+  }
+  public static CheckSize CheckSize.createRef(String ref) {
+    Unresolved$CheckSize unresolvedNode = new Unresolved$CheckSize();
+    unresolvedNode.setUnresolved$Token(ref);
+    unresolvedNode.setUnresolved$ResolveOpposite(true);
+    return unresolvedNode;
+  }
+  public static CheckSize CheckSize.createRefDirection(String ref) {
+    Unresolved$CheckSize unresolvedNode = new Unresolved$CheckSize();
+    unresolvedNode.setUnresolved$Token(ref);
+    unresolvedNode.setUnresolved$ResolveOpposite(false);
+    return unresolvedNode;
+  }
+  public static CheckSeq CheckSeq.createRef(String ref) {
+    Unresolved$CheckSeq unresolvedNode = new Unresolved$CheckSeq();
+    unresolvedNode.setUnresolved$Token(ref);
+    unresolvedNode.setUnresolved$ResolveOpposite(true);
+    return unresolvedNode;
+  }
+  public static CheckSeq CheckSeq.createRefDirection(String ref) {
+    Unresolved$CheckSeq unresolvedNode = new Unresolved$CheckSeq();
+    unresolvedNode.setUnresolved$Token(ref);
+    unresolvedNode.setUnresolved$ResolveOpposite(false);
+    return unresolvedNode;
+  }
+  public static OnoDisk OnoDisk.createRef(String ref) {
+    Unresolved$OnoDisk unresolvedNode = new Unresolved$OnoDisk();
+    unresolvedNode.setUnresolved$Token(ref);
+    unresolvedNode.setUnresolved$ResolveOpposite(true);
+    return unresolvedNode;
+  }
+  public static OnoDisk OnoDisk.createRefDirection(String ref) {
+    Unresolved$OnoDisk unresolvedNode = new Unresolved$OnoDisk();
+    unresolvedNode.setUnresolved$Token(ref);
+    unresolvedNode.setUnresolved$ResolveOpposite(false);
+    return unresolvedNode;
+  }
+  public static TnoDisk TnoDisk.createRef(String ref) {
+    Unresolved$TnoDisk unresolvedNode = new Unresolved$TnoDisk();
+    unresolvedNode.setUnresolved$Token(ref);
+    unresolvedNode.setUnresolved$ResolveOpposite(true);
+    return unresolvedNode;
+  }
+  public static TnoDisk TnoDisk.createRefDirection(String ref) {
+    Unresolved$TnoDisk unresolvedNode = new Unresolved$TnoDisk();
+    unresolvedNode.setUnresolved$Token(ref);
+    unresolvedNode.setUnresolved$ResolveOpposite(false);
+    return unresolvedNode;
+  }
+  public static CheckD0 CheckD0.createRef(String ref) {
+    Unresolved$CheckD0 unresolvedNode = new Unresolved$CheckD0();
+    unresolvedNode.setUnresolved$Token(ref);
+    unresolvedNode.setUnresolved$ResolveOpposite(true);
+    return unresolvedNode;
+  }
+  public static CheckD0 CheckD0.createRefDirection(String ref) {
+    Unresolved$CheckD0 unresolvedNode = new Unresolved$CheckD0();
+    unresolvedNode.setUnresolved$Token(ref);
+    unresolvedNode.setUnresolved$ResolveOpposite(false);
+    return unresolvedNode;
+  }
+  public static Hanoi Hanoi.createRef(String ref) {
+    Unresolved$Hanoi unresolvedNode = new Unresolved$Hanoi();
+    unresolvedNode.setUnresolved$Token(ref);
+    unresolvedNode.setUnresolved$ResolveOpposite(true);
+    return unresolvedNode;
+  }
+  public static Hanoi Hanoi.createRefDirection(String ref) {
+    Unresolved$Hanoi unresolvedNode = new Unresolved$Hanoi();
+    unresolvedNode.setUnresolved$Token(ref);
+    unresolvedNode.setUnresolved$ResolveOpposite(false);
+    return unresolvedNode;
+  }
+  public static Disk Disk.createRef(String ref) {
+    Unresolved$Disk unresolvedNode = new Unresolved$Disk();
+    unresolvedNode.setUnresolved$Token(ref);
+    unresolvedNode.setUnresolved$ResolveOpposite(true);
+    return unresolvedNode;
+  }
+  public static Disk Disk.createRefDirection(String ref) {
+    Unresolved$Disk unresolvedNode = new Unresolved$Disk();
+    unresolvedNode.setUnresolved$Token(ref);
+    unresolvedNode.setUnresolved$ResolveOpposite(false);
+    return unresolvedNode;
+  }
+  public static Pillar Pillar.createRef(String ref) {
+    Unresolved$Pillar unresolvedNode = new Unresolved$Pillar();
+    unresolvedNode.setUnresolved$Token(ref);
+    unresolvedNode.setUnresolved$ResolveOpposite(true);
+    return unresolvedNode;
+  }
+  public static Pillar Pillar.createRefDirection(String ref) {
+    Unresolved$Pillar unresolvedNode = new Unresolved$Pillar();
+    unresolvedNode.setUnresolved$Token(ref);
+    unresolvedNode.setUnresolved$ResolveOpposite(false);
+    return unresolvedNode;
+  }
+}
+
+aspect ResolverTrigger {
+
+  // enforce resolving of all non-containment relations of the current non-terminal
+  public void ASTNode.resolveAll() {
+  }
+
+  // enforce resolving in the entire subtree
+  public void ASTNode.treeResolveAll() {
+    if (children != null) {
+      for (int i = 0; i < numChildren; ++i) {
+        ASTNode child = children[i];
+        if (child != null) {
+          child.treeResolveAll();
+        }
+      }
+    }
+    resolveAll();
+  }
+  // enforce resolving of all non-containment relations of the current non-terminal
+  public void Root.resolveAll() {
+    super.resolveAll();
+  }
+  // enforce resolving of all non-containment relations of the current non-terminal
+  public void Constraint.resolveAll() {
+    super.resolveAll();
+  }
+  // enforce resolving of all non-containment relations of the current non-terminal
+  public void Atom.resolveAll() {
+    getRelList();
+    super.resolveAll();
+  }
+  // enforce resolving of all non-containment relations of the current non-terminal
+  public void UnaryConstraint.resolveAll() {
+    super.resolveAll();
+  }
+  // enforce resolving of all non-containment relations of the current non-terminal
+  public void BinaryConstraint.resolveAll() {
+    super.resolveAll();
+  }
+  // enforce resolving of all non-containment relations of the current non-terminal
+  public void Conjunction.resolveAll() {
+    super.resolveAll();
+  }
+  // enforce resolving of all non-containment relations of the current non-terminal
+  public void Disjunction.resolveAll() {
+    super.resolveAll();
+  }
+  // enforce resolving of all non-containment relations of the current non-terminal
+  public void Implication.resolveAll() {
+    super.resolveAll();
+  }
+  // enforce resolving of all non-containment relations of the current non-terminal
+  public void Negation.resolveAll() {
+    super.resolveAll();
+  }
+  // enforce resolving of all non-containment relations of the current non-terminal
+  public void CheckSize.resolveAll() {
+    super.resolveAll();
+  }
+  // enforce resolving of all non-containment relations of the current non-terminal
+  public void CheckSeq.resolveAll() {
+    super.resolveAll();
+  }
+  // enforce resolving of all non-containment relations of the current non-terminal
+  public void OnoDisk.resolveAll() {
+    super.resolveAll();
+  }
+  // enforce resolving of all non-containment relations of the current non-terminal
+  public void TnoDisk.resolveAll() {
+    super.resolveAll();
+  }
+  // enforce resolving of all non-containment relations of the current non-terminal
+  public void CheckD0.resolveAll() {
+    super.resolveAll();
+  }
+  // enforce resolving of all non-containment relations of the current non-terminal
+  public void Hanoi.resolveAll() {
+    super.resolveAll();
+  }
+  // enforce resolving of all non-containment relations of the current non-terminal
+  public void Disk.resolveAll() {
+    super.resolveAll();
+  }
+  // enforce resolving of all non-containment relations of the current non-terminal
+  public void Pillar.resolveAll() {
+    super.resolveAll();
+  }
+}
+
+aspect RefResolverHelpers {
+
+  interface Unresolved$Node$Interface {
+    String getUnresolved$Token();
+    boolean getUnresolved$ResolveOpposite();
+  }
+
+  class Unresolved$Root extends Root  implements Unresolved$Node$Interface {
+    private String unresolved$Token;
+    public String getUnresolved$Token() {
+      return unresolved$Token;
+    }
+    void setUnresolved$Token(String token) {
+      this.unresolved$Token = token;
+    }
+    private boolean unresolved$ResolveOpposite;
+    public boolean getUnresolved$ResolveOpposite() {
+      return unresolved$ResolveOpposite;
+    }
+    void setUnresolved$ResolveOpposite(boolean resolveOpposite) {
+      this.unresolved$ResolveOpposite = resolveOpposite;
+    }
+  }
+  Unresolved$Node$Interface Root.as$Unresolved() {
+    return null;
+  }
+  Unresolved$Node$Interface Unresolved$Root.as$Unresolved() {
+    return this;
+  }
+  boolean Root.is$Unresolved() {
+    return false;
+  }
+  boolean Unresolved$Root.is$Unresolved() {
+    return true;
+  }
+  abstract class Unresolved$Constraint extends Constraint  implements Unresolved$Node$Interface {
+    private String unresolved$Token;
+    public String getUnresolved$Token() {
+      return unresolved$Token;
+    }
+    void setUnresolved$Token(String token) {
+      this.unresolved$Token = token;
+    }
+    private boolean unresolved$ResolveOpposite;
+    public boolean getUnresolved$ResolveOpposite() {
+      return unresolved$ResolveOpposite;
+    }
+    void setUnresolved$ResolveOpposite(boolean resolveOpposite) {
+      this.unresolved$ResolveOpposite = resolveOpposite;
+    }
+  }
+  Unresolved$Node$Interface Constraint.as$Unresolved() {
+    return null;
+  }
+  Unresolved$Node$Interface Unresolved$Constraint.as$Unresolved() {
+    return this;
+  }
+  boolean Constraint.is$Unresolved() {
+    return false;
+  }
+  boolean Unresolved$Constraint.is$Unresolved() {
+    return true;
+  }
+  abstract class Unresolved$Atom extends Atom  implements Unresolved$Node$Interface {
+    private String unresolved$Token;
+    public String getUnresolved$Token() {
+      return unresolved$Token;
+    }
+    void setUnresolved$Token(String token) {
+      this.unresolved$Token = token;
+    }
+    private boolean unresolved$ResolveOpposite;
+    public boolean getUnresolved$ResolveOpposite() {
+      return unresolved$ResolveOpposite;
+    }
+    void setUnresolved$ResolveOpposite(boolean resolveOpposite) {
+      this.unresolved$ResolveOpposite = resolveOpposite;
+    }
+  }
+  Unresolved$Node$Interface Atom.as$Unresolved() {
+    return null;
+  }
+  Unresolved$Node$Interface Unresolved$Atom.as$Unresolved() {
+    return this;
+  }
+  boolean Atom.is$Unresolved() {
+    return false;
+  }
+  boolean Unresolved$Atom.is$Unresolved() {
+    return true;
+  }
+  abstract class Unresolved$UnaryConstraint extends UnaryConstraint  implements Unresolved$Node$Interface {
+    private String unresolved$Token;
+    public String getUnresolved$Token() {
+      return unresolved$Token;
+    }
+    void setUnresolved$Token(String token) {
+      this.unresolved$Token = token;
+    }
+    private boolean unresolved$ResolveOpposite;
+    public boolean getUnresolved$ResolveOpposite() {
+      return unresolved$ResolveOpposite;
+    }
+    void setUnresolved$ResolveOpposite(boolean resolveOpposite) {
+      this.unresolved$ResolveOpposite = resolveOpposite;
+    }
+  }
+  Unresolved$Node$Interface UnaryConstraint.as$Unresolved() {
+    return null;
+  }
+  Unresolved$Node$Interface Unresolved$UnaryConstraint.as$Unresolved() {
+    return this;
+  }
+  boolean UnaryConstraint.is$Unresolved() {
+    return false;
+  }
+  boolean Unresolved$UnaryConstraint.is$Unresolved() {
+    return true;
+  }
+  abstract class Unresolved$BinaryConstraint extends BinaryConstraint  implements Unresolved$Node$Interface {
+    private String unresolved$Token;
+    public String getUnresolved$Token() {
+      return unresolved$Token;
+    }
+    void setUnresolved$Token(String token) {
+      this.unresolved$Token = token;
+    }
+    private boolean unresolved$ResolveOpposite;
+    public boolean getUnresolved$ResolveOpposite() {
+      return unresolved$ResolveOpposite;
+    }
+    void setUnresolved$ResolveOpposite(boolean resolveOpposite) {
+      this.unresolved$ResolveOpposite = resolveOpposite;
+    }
+  }
+  Unresolved$Node$Interface BinaryConstraint.as$Unresolved() {
+    return null;
+  }
+  Unresolved$Node$Interface Unresolved$BinaryConstraint.as$Unresolved() {
+    return this;
+  }
+  boolean BinaryConstraint.is$Unresolved() {
+    return false;
+  }
+  boolean Unresolved$BinaryConstraint.is$Unresolved() {
+    return true;
+  }
+  class Unresolved$Conjunction extends Conjunction  implements Unresolved$Node$Interface {
+    private String unresolved$Token;
+    public String getUnresolved$Token() {
+      return unresolved$Token;
+    }
+    void setUnresolved$Token(String token) {
+      this.unresolved$Token = token;
+    }
+    private boolean unresolved$ResolveOpposite;
+    public boolean getUnresolved$ResolveOpposite() {
+      return unresolved$ResolveOpposite;
+    }
+    void setUnresolved$ResolveOpposite(boolean resolveOpposite) {
+      this.unresolved$ResolveOpposite = resolveOpposite;
+    }
+  }
+  Unresolved$Node$Interface Conjunction.as$Unresolved() {
+    return null;
+  }
+  Unresolved$Node$Interface Unresolved$Conjunction.as$Unresolved() {
+    return this;
+  }
+  boolean Conjunction.is$Unresolved() {
+    return false;
+  }
+  boolean Unresolved$Conjunction.is$Unresolved() {
+    return true;
+  }
+  class Unresolved$Disjunction extends Disjunction  implements Unresolved$Node$Interface {
+    private String unresolved$Token;
+    public String getUnresolved$Token() {
+      return unresolved$Token;
+    }
+    void setUnresolved$Token(String token) {
+      this.unresolved$Token = token;
+    }
+    private boolean unresolved$ResolveOpposite;
+    public boolean getUnresolved$ResolveOpposite() {
+      return unresolved$ResolveOpposite;
+    }
+    void setUnresolved$ResolveOpposite(boolean resolveOpposite) {
+      this.unresolved$ResolveOpposite = resolveOpposite;
+    }
+  }
+  Unresolved$Node$Interface Disjunction.as$Unresolved() {
+    return null;
+  }
+  Unresolved$Node$Interface Unresolved$Disjunction.as$Unresolved() {
+    return this;
+  }
+  boolean Disjunction.is$Unresolved() {
+    return false;
+  }
+  boolean Unresolved$Disjunction.is$Unresolved() {
+    return true;
+  }
+  class Unresolved$Implication extends Implication  implements Unresolved$Node$Interface {
+    private String unresolved$Token;
+    public String getUnresolved$Token() {
+      return unresolved$Token;
+    }
+    void setUnresolved$Token(String token) {
+      this.unresolved$Token = token;
+    }
+    private boolean unresolved$ResolveOpposite;
+    public boolean getUnresolved$ResolveOpposite() {
+      return unresolved$ResolveOpposite;
+    }
+    void setUnresolved$ResolveOpposite(boolean resolveOpposite) {
+      this.unresolved$ResolveOpposite = resolveOpposite;
+    }
+  }
+  Unresolved$Node$Interface Implication.as$Unresolved() {
+    return null;
+  }
+  Unresolved$Node$Interface Unresolved$Implication.as$Unresolved() {
+    return this;
+  }
+  boolean Implication.is$Unresolved() {
+    return false;
+  }
+  boolean Unresolved$Implication.is$Unresolved() {
+    return true;
+  }
+  class Unresolved$Negation extends Negation  implements Unresolved$Node$Interface {
+    private String unresolved$Token;
+    public String getUnresolved$Token() {
+      return unresolved$Token;
+    }
+    void setUnresolved$Token(String token) {
+      this.unresolved$Token = token;
+    }
+    private boolean unresolved$ResolveOpposite;
+    public boolean getUnresolved$ResolveOpposite() {
+      return unresolved$ResolveOpposite;
+    }
+    void setUnresolved$ResolveOpposite(boolean resolveOpposite) {
+      this.unresolved$ResolveOpposite = resolveOpposite;
+    }
+  }
+  Unresolved$Node$Interface Negation.as$Unresolved() {
+    return null;
+  }
+  Unresolved$Node$Interface Unresolved$Negation.as$Unresolved() {
+    return this;
+  }
+  boolean Negation.is$Unresolved() {
+    return false;
+  }
+  boolean Unresolved$Negation.is$Unresolved() {
+    return true;
+  }
+  class Unresolved$CheckSize extends CheckSize  implements Unresolved$Node$Interface {
+    private String unresolved$Token;
+    public String getUnresolved$Token() {
+      return unresolved$Token;
+    }
+    void setUnresolved$Token(String token) {
+      this.unresolved$Token = token;
+    }
+    private boolean unresolved$ResolveOpposite;
+    public boolean getUnresolved$ResolveOpposite() {
+      return unresolved$ResolveOpposite;
+    }
+    void setUnresolved$ResolveOpposite(boolean resolveOpposite) {
+      this.unresolved$ResolveOpposite = resolveOpposite;
+    }
+  }
+  Unresolved$Node$Interface CheckSize.as$Unresolved() {
+    return null;
+  }
+  Unresolved$Node$Interface Unresolved$CheckSize.as$Unresolved() {
+    return this;
+  }
+  boolean CheckSize.is$Unresolved() {
+    return false;
+  }
+  boolean Unresolved$CheckSize.is$Unresolved() {
+    return true;
+  }
+  class Unresolved$CheckSeq extends CheckSeq  implements Unresolved$Node$Interface {
+    private String unresolved$Token;
+    public String getUnresolved$Token() {
+      return unresolved$Token;
+    }
+    void setUnresolved$Token(String token) {
+      this.unresolved$Token = token;
+    }
+    private boolean unresolved$ResolveOpposite;
+    public boolean getUnresolved$ResolveOpposite() {
+      return unresolved$ResolveOpposite;
+    }
+    void setUnresolved$ResolveOpposite(boolean resolveOpposite) {
+      this.unresolved$ResolveOpposite = resolveOpposite;
+    }
+  }
+  Unresolved$Node$Interface CheckSeq.as$Unresolved() {
+    return null;
+  }
+  Unresolved$Node$Interface Unresolved$CheckSeq.as$Unresolved() {
+    return this;
+  }
+  boolean CheckSeq.is$Unresolved() {
+    return false;
+  }
+  boolean Unresolved$CheckSeq.is$Unresolved() {
+    return true;
+  }
+  class Unresolved$OnoDisk extends OnoDisk  implements Unresolved$Node$Interface {
+    private String unresolved$Token;
+    public String getUnresolved$Token() {
+      return unresolved$Token;
+    }
+    void setUnresolved$Token(String token) {
+      this.unresolved$Token = token;
+    }
+    private boolean unresolved$ResolveOpposite;
+    public boolean getUnresolved$ResolveOpposite() {
+      return unresolved$ResolveOpposite;
+    }
+    void setUnresolved$ResolveOpposite(boolean resolveOpposite) {
+      this.unresolved$ResolveOpposite = resolveOpposite;
+    }
+  }
+  Unresolved$Node$Interface OnoDisk.as$Unresolved() {
+    return null;
+  }
+  Unresolved$Node$Interface Unresolved$OnoDisk.as$Unresolved() {
+    return this;
+  }
+  boolean OnoDisk.is$Unresolved() {
+    return false;
+  }
+  boolean Unresolved$OnoDisk.is$Unresolved() {
+    return true;
+  }
+  class Unresolved$TnoDisk extends TnoDisk  implements Unresolved$Node$Interface {
+    private String unresolved$Token;
+    public String getUnresolved$Token() {
+      return unresolved$Token;
+    }
+    void setUnresolved$Token(String token) {
+      this.unresolved$Token = token;
+    }
+    private boolean unresolved$ResolveOpposite;
+    public boolean getUnresolved$ResolveOpposite() {
+      return unresolved$ResolveOpposite;
+    }
+    void setUnresolved$ResolveOpposite(boolean resolveOpposite) {
+      this.unresolved$ResolveOpposite = resolveOpposite;
+    }
+  }
+  Unresolved$Node$Interface TnoDisk.as$Unresolved() {
+    return null;
+  }
+  Unresolved$Node$Interface Unresolved$TnoDisk.as$Unresolved() {
+    return this;
+  }
+  boolean TnoDisk.is$Unresolved() {
+    return false;
+  }
+  boolean Unresolved$TnoDisk.is$Unresolved() {
+    return true;
+  }
+  class Unresolved$CheckD0 extends CheckD0  implements Unresolved$Node$Interface {
+    private String unresolved$Token;
+    public String getUnresolved$Token() {
+      return unresolved$Token;
+    }
+    void setUnresolved$Token(String token) {
+      this.unresolved$Token = token;
+    }
+    private boolean unresolved$ResolveOpposite;
+    public boolean getUnresolved$ResolveOpposite() {
+      return unresolved$ResolveOpposite;
+    }
+    void setUnresolved$ResolveOpposite(boolean resolveOpposite) {
+      this.unresolved$ResolveOpposite = resolveOpposite;
+    }
+  }
+  Unresolved$Node$Interface CheckD0.as$Unresolved() {
+    return null;
+  }
+  Unresolved$Node$Interface Unresolved$CheckD0.as$Unresolved() {
+    return this;
+  }
+  boolean CheckD0.is$Unresolved() {
+    return false;
+  }
+  boolean Unresolved$CheckD0.is$Unresolved() {
+    return true;
+  }
+  class Unresolved$Hanoi extends Hanoi  implements Unresolved$Node$Interface {
+    private String unresolved$Token;
+    public String getUnresolved$Token() {
+      return unresolved$Token;
+    }
+    void setUnresolved$Token(String token) {
+      this.unresolved$Token = token;
+    }
+    private boolean unresolved$ResolveOpposite;
+    public boolean getUnresolved$ResolveOpposite() {
+      return unresolved$ResolveOpposite;
+    }
+    void setUnresolved$ResolveOpposite(boolean resolveOpposite) {
+      this.unresolved$ResolveOpposite = resolveOpposite;
+    }
+  }
+  Unresolved$Node$Interface Hanoi.as$Unresolved() {
+    return null;
+  }
+  Unresolved$Node$Interface Unresolved$Hanoi.as$Unresolved() {
+    return this;
+  }
+  boolean Hanoi.is$Unresolved() {
+    return false;
+  }
+  boolean Unresolved$Hanoi.is$Unresolved() {
+    return true;
+  }
+  class Unresolved$Disk extends Disk  implements Unresolved$Node$Interface {
+    private String unresolved$Token;
+    public String getUnresolved$Token() {
+      return unresolved$Token;
+    }
+    void setUnresolved$Token(String token) {
+      this.unresolved$Token = token;
+    }
+    private boolean unresolved$ResolveOpposite;
+    public boolean getUnresolved$ResolveOpposite() {
+      return unresolved$ResolveOpposite;
+    }
+    void setUnresolved$ResolveOpposite(boolean resolveOpposite) {
+      this.unresolved$ResolveOpposite = resolveOpposite;
+    }
+  }
+  Unresolved$Node$Interface Disk.as$Unresolved() {
+    return null;
+  }
+  Unresolved$Node$Interface Unresolved$Disk.as$Unresolved() {
+    return this;
+  }
+  boolean Disk.is$Unresolved() {
+    return false;
+  }
+  boolean Unresolved$Disk.is$Unresolved() {
+    return true;
+  }
+  class Unresolved$Pillar extends Pillar  implements Unresolved$Node$Interface {
+    private String unresolved$Token;
+    public String getUnresolved$Token() {
+      return unresolved$Token;
+    }
+    void setUnresolved$Token(String token) {
+      this.unresolved$Token = token;
+    }
+    private boolean unresolved$ResolveOpposite;
+    public boolean getUnresolved$ResolveOpposite() {
+      return unresolved$ResolveOpposite;
+    }
+    void setUnresolved$ResolveOpposite(boolean resolveOpposite) {
+      this.unresolved$ResolveOpposite = resolveOpposite;
+    }
+  }
+  Unresolved$Node$Interface Pillar.as$Unresolved() {
+    return null;
+  }
+  Unresolved$Node$Interface Unresolved$Pillar.as$Unresolved() {
+    return this;
+  }
+  boolean Pillar.is$Unresolved() {
+    return false;
+  }
+  boolean Unresolved$Pillar.is$Unresolved() {
+    return true;
+  }
+
+}
diff --git a/src/gen/jastadd/agResolverStubs.jrag b/src/gen/jastadd/agResolverStubs.jrag
new file mode 100644
index 0000000000000000000000000000000000000000..468d93a92f654f3061f6711ac7483fdbc9ce4f13
--- /dev/null
+++ b/src/gen/jastadd/agResolverStubs.jrag
@@ -0,0 +1,131 @@
+aspect RefResolverStubs {
+
+  // rel Atom.Rel* -> Pillar
+  // context-dependent name resolution
+  uncache Atom.resolveRelByToken(String id, int position);
+  syn Pillar Atom.resolveRelByToken(String id, int position) {
+    // default to context-independent name resolution
+    return globallyResolvePillarByToken(id);
+  }
+
+  // context-independent name resolution
+  uncache ASTNode.globallyResolveRootByToken(String id);
+  syn Root ASTNode.globallyResolveRootByToken(String id) {
+    // perform context independent name resolution here using the id
+    throw new RuntimeException("Context-independent name resolution for Root not implemented.");
+  }
+
+  // context-independent name resolution
+  uncache ASTNode.globallyResolveConstraintByToken(String id);
+  syn Constraint ASTNode.globallyResolveConstraintByToken(String id) {
+    // perform context independent name resolution here using the id
+    throw new RuntimeException("Context-independent name resolution for Constraint not implemented.");
+  }
+
+  // context-independent name resolution
+  uncache ASTNode.globallyResolveAtomByToken(String id);
+  syn Atom ASTNode.globallyResolveAtomByToken(String id) {
+    // perform context independent name resolution here using the id
+    throw new RuntimeException("Context-independent name resolution for Atom not implemented.");
+  }
+
+  // context-independent name resolution
+  uncache ASTNode.globallyResolveUnaryConstraintByToken(String id);
+  syn UnaryConstraint ASTNode.globallyResolveUnaryConstraintByToken(String id) {
+    // perform context independent name resolution here using the id
+    throw new RuntimeException("Context-independent name resolution for UnaryConstraint not implemented.");
+  }
+
+  // context-independent name resolution
+  uncache ASTNode.globallyResolveBinaryConstraintByToken(String id);
+  syn BinaryConstraint ASTNode.globallyResolveBinaryConstraintByToken(String id) {
+    // perform context independent name resolution here using the id
+    throw new RuntimeException("Context-independent name resolution for BinaryConstraint not implemented.");
+  }
+
+  // context-independent name resolution
+  uncache ASTNode.globallyResolveConjunctionByToken(String id);
+  syn Conjunction ASTNode.globallyResolveConjunctionByToken(String id) {
+    // perform context independent name resolution here using the id
+    throw new RuntimeException("Context-independent name resolution for Conjunction not implemented.");
+  }
+
+  // context-independent name resolution
+  uncache ASTNode.globallyResolveDisjunctionByToken(String id);
+  syn Disjunction ASTNode.globallyResolveDisjunctionByToken(String id) {
+    // perform context independent name resolution here using the id
+    throw new RuntimeException("Context-independent name resolution for Disjunction not implemented.");
+  }
+
+  // context-independent name resolution
+  uncache ASTNode.globallyResolveImplicationByToken(String id);
+  syn Implication ASTNode.globallyResolveImplicationByToken(String id) {
+    // perform context independent name resolution here using the id
+    throw new RuntimeException("Context-independent name resolution for Implication not implemented.");
+  }
+
+  // context-independent name resolution
+  uncache ASTNode.globallyResolveNegationByToken(String id);
+  syn Negation ASTNode.globallyResolveNegationByToken(String id) {
+    // perform context independent name resolution here using the id
+    throw new RuntimeException("Context-independent name resolution for Negation not implemented.");
+  }
+
+  // context-independent name resolution
+  uncache ASTNode.globallyResolveCheckSizeByToken(String id);
+  syn CheckSize ASTNode.globallyResolveCheckSizeByToken(String id) {
+    // perform context independent name resolution here using the id
+    throw new RuntimeException("Context-independent name resolution for CheckSize not implemented.");
+  }
+
+  // context-independent name resolution
+  uncache ASTNode.globallyResolveCheckSeqByToken(String id);
+  syn CheckSeq ASTNode.globallyResolveCheckSeqByToken(String id) {
+    // perform context independent name resolution here using the id
+    throw new RuntimeException("Context-independent name resolution for CheckSeq not implemented.");
+  }
+
+  // context-independent name resolution
+  uncache ASTNode.globallyResolveOnoDiskByToken(String id);
+  syn OnoDisk ASTNode.globallyResolveOnoDiskByToken(String id) {
+    // perform context independent name resolution here using the id
+    throw new RuntimeException("Context-independent name resolution for OnoDisk not implemented.");
+  }
+
+  // context-independent name resolution
+  uncache ASTNode.globallyResolveTnoDiskByToken(String id);
+  syn TnoDisk ASTNode.globallyResolveTnoDiskByToken(String id) {
+    // perform context independent name resolution here using the id
+    throw new RuntimeException("Context-independent name resolution for TnoDisk not implemented.");
+  }
+
+  // context-independent name resolution
+  uncache ASTNode.globallyResolveCheckD0ByToken(String id);
+  syn CheckD0 ASTNode.globallyResolveCheckD0ByToken(String id) {
+    // perform context independent name resolution here using the id
+    throw new RuntimeException("Context-independent name resolution for CheckD0 not implemented.");
+  }
+
+  // context-independent name resolution
+  uncache ASTNode.globallyResolveHanoiByToken(String id);
+  syn Hanoi ASTNode.globallyResolveHanoiByToken(String id) {
+    // perform context independent name resolution here using the id
+    throw new RuntimeException("Context-independent name resolution for Hanoi not implemented.");
+  }
+
+  // context-independent name resolution
+  uncache ASTNode.globallyResolveDiskByToken(String id);
+  syn Disk ASTNode.globallyResolveDiskByToken(String id) {
+    // perform context independent name resolution here using the id
+    throw new RuntimeException("Context-independent name resolution for Disk not implemented.");
+  }
+
+  // context-independent name resolution
+  uncache ASTNode.globallyResolvePillarByToken(String id);
+  syn Pillar ASTNode.globallyResolvePillarByToken(String id) {
+    // perform context independent name resolution here using the id
+    throw new RuntimeException("Context-independent name resolution for Pillar not implemented.");
+  }
+
+}
+
diff --git a/src/gen/java/org/jastadd/ag/ast/ASTNode$DepGraphNode.java b/src/gen/java/org/jastadd/ag/ast/ASTNode$DepGraphNode.java
new file mode 100644
index 0000000000000000000000000000000000000000..d8a73b8820211999a7524ef3b2fd44a9c416d886
--- /dev/null
+++ b/src/gen/java/org/jastadd/ag/ast/ASTNode$DepGraphNode.java
@@ -0,0 +1,317 @@
+package org.jastadd.ag.ast;
+
+import java.util.*;
+/** @apilevel internal 
+ * @ast class
+ * @declaredat ASTNode:2
+ */
+public class ASTNode$DepGraphNode extends java.lang.Object {
+  /**
+   * @declaredat ASTNode:6
+   */
+  
+
+  // Level: param
+
+  public ASTNode fNode;
+  /**
+   * @declaredat ASTNode:7
+   */
+  
+  public String fAttrID;
+  /**
+   * @declaredat ASTNode:8
+   */
+  
+  protected Object fParams;
+  /**
+   * @declaredat ASTNode:10
+   */
+  
+
+  public static ASTNode$DepGraphNode createAttrHandler(ASTNode node, String attrID, Object params) {
+    return new ASTNode$DepGraphNode(node, attrID, params, ASTNode.inc_EMPTY);
+  }
+  /**
+   * @declaredat ASTNode:14
+   */
+  
+
+  public static ASTNode$DepGraphNode createAttrHandler(ASTNode$DepGraphNode handler, ASTNode node) {
+    return new ASTNode$DepGraphNode(handler, node, ASTNode.inc_EMPTY);
+  }
+  /**
+   * @declaredat ASTNode:18
+   */
+  
+
+  public static ASTNode$DepGraphNode createAstHandler(ASTNode node, String attrID, Object params) {
+    return new ASTNode$DepGraphNode(node, attrID, params, ASTNode.inc_AST);
+  }
+  /**
+   * @declaredat ASTNode:22
+   */
+  
+
+  public static ASTNode$DepGraphNode createAstHandler(ASTNode$DepGraphNode handler, ASTNode node) {
+    return new ASTNode$DepGraphNode(handler, node, ASTNode.inc_AST);
+  }
+  /**
+   * @declaredat ASTNode:27
+   */
+  
+
+
+  ASTNode$DepGraphNode(ASTNode node, String attrID, Object params, int state) {
+    fNode = node;
+    fAttrID = attrID;
+    fParams = params;
+    fState = state;
+  }
+  /**
+   * @declaredat ASTNode:34
+   */
+  
+
+  ASTNode$DepGraphNode(ASTNode$DepGraphNode handler, ASTNode node, int state) {
+    fNode = node;
+    fAttrID = handler.fAttrID;
+    fParams = handler.fParams;
+    fState = state;
+  }
+  /**
+   * @declaredat ASTNode:41
+   */
+  
+
+  public void setParams(Object params) {
+    fParams = params;
+  }
+  /**
+   * @declaredat ASTNode:52
+   */
+  
+
+
+
+
+
+
+  // Dependency management
+
+  public java.util.HashSet<ASTNode$DepGraphNode> fListenerSet = new java.util.HashSet<ASTNode$DepGraphNode>(4);
+  /**
+   * @declaredat ASTNode:54
+   */
+  
+
+  public boolean hasListeners() {
+    return !fListenerSet.isEmpty();
+  }
+  /**
+   * @declaredat ASTNode:58
+   */
+  
+
+  public void addListener(ASTNode$DepGraphNode node) {
+    fListenerSet.add(node);
+  }
+  /**
+   * @declaredat ASTNode:62
+   */
+  
+
+  public void removeListener(ASTNode$DepGraphNode node) {
+    fListenerSet.remove(node);
+  }
+  /**
+   * @declaredat ASTNode:66
+   */
+  
+
+  public void cleanupListeners() {
+    java.util.Iterator<ASTNode$DepGraphNode> itr = fListenerSet.iterator();
+    while (itr.hasNext()) {
+      ASTNode$DepGraphNode node = itr.next();
+      if (node.isEmpty() || node.isGarbage()) {
+        itr.remove();
+      }
+    }
+  }
+  /**
+   * @declaredat ASTNode:76
+   */
+  
+
+  public void clearListeners() {
+    fListenerSet.clear();
+  }
+  /**
+   * @declaredat ASTNode:82
+   */
+  
+
+  // Notification
+
+  private boolean visited = false;
+  /**
+   * @declaredat ASTNode:84
+   */
+  
+
+  public void notifyDependencies() {
+    // Notify and remove listeners
+    if (!visited) {
+      visited = true;
+      java.util.HashSet<ASTNode$DepGraphNode> k = fListenerSet;
+      fListenerSet = new java.util.HashSet<ASTNode$DepGraphNode>(4);
+      for (ASTNode$DepGraphNode node : k) {
+        if (!node.isGarbage()) {
+          node.dependencyChanged();
+        }
+      }
+      visited = false;
+    }
+  }
+  /**
+   * @declaredat ASTNode:101
+   */
+  
+
+  // React to change
+
+  public void dependencyChanged() {
+    if (isComputed() || isCreated()) {
+      setEmpty();
+      reactToDependencyChange();
+    }
+  }
+  /**
+   * @declaredat ASTNode:108
+   */
+  
+
+  public void reactToDependencyChange() {
+    fNode.reactToDependencyChange(fAttrID, fParams);
+  }
+  /**
+   * @declaredat ASTNode:114
+   */
+  
+
+  // State
+
+  protected int fState = ASTNode.inc_EMPTY;
+  /**
+   * @declaredat ASTNode:116
+   */
+  
+
+  public void throwAway() {
+    fState = ASTNode.inc_GARBAGE;
+  }
+  /**
+   * @declaredat ASTNode:120
+   */
+  
+
+  public void keepAlive() {
+    fState = ASTNode.inc_LIVE;
+  }
+  /**
+   * @declaredat ASTNode:124
+   */
+  
+
+  public void setComputed() {
+    fState = ASTNode.inc_COMPUTED;
+  }
+  /**
+   * @declaredat ASTNode:128
+   */
+  
+
+  public void setEmpty() {
+    fState = ASTNode.inc_EMPTY;
+  }
+  /**
+   * @declaredat ASTNode:132
+   */
+  
+
+  public boolean isGarbage() {
+    return fState == ASTNode.inc_GARBAGE;
+  }
+  /**
+   * @declaredat ASTNode:136
+   */
+  
+
+  public boolean isCreated() {
+    return fState == ASTNode.inc_CREATED;
+  }
+  /**
+   * @declaredat ASTNode:140
+   */
+  
+
+  public boolean isCloned() {
+    return fState == ASTNode.inc_CLONED;
+  }
+  /**
+   * @declaredat ASTNode:144
+   */
+  
+
+  public boolean isLive() {
+    return fState == ASTNode.inc_LIVE;
+  }
+  /**
+   * @declaredat ASTNode:148
+   */
+  
+
+  public boolean isComputed() {
+    return fState == ASTNode.inc_COMPUTED;
+  }
+  /**
+   * @declaredat ASTNode:152
+   */
+  
+
+  public boolean isEmpty() {
+    return fState == ASTNode.inc_EMPTY;
+  }
+  /**
+   * @declaredat ASTNode:159
+   */
+  
+
+
+  // Clean up
+
+  public boolean visitedDuringCleanup = false;
+  /**
+   * @declaredat ASTNode:160
+   */
+  
+  public static int nbr_cleanup = 0;
+  /**
+   * @declaredat ASTNode:162
+   */
+  
+
+  public void cleanUpGarbage() {
+    visitedDuringCleanup = true;
+    nbr_cleanup++;
+    // Clean up garbage
+    java.util.Iterator<ASTNode$DepGraphNode> itr = fListenerSet.iterator();
+    while (itr.hasNext()) {
+      ASTNode$DepGraphNode cur = itr.next();
+      if (cur.isGarbage()) {
+        itr.remove();
+      }
+    }
+  }
+
+}
diff --git a/src/gen/java/org/jastadd/ag/ast/ASTNode.java b/src/gen/java/org/jastadd/ag/ast/ASTNode.java
new file mode 100644
index 0000000000000000000000000000000000000000..cf7417f4be4a11bca6476ad24d6e9d3344fd5cc2
--- /dev/null
+++ b/src/gen/java/org/jastadd/ag/ast/ASTNode.java
@@ -0,0 +1,1073 @@
+/* This file was generated with JastAdd2 (http://jastadd.org) version 2.3.5 */
+package org.jastadd.ag.ast;
+import java.util.*;
+/**
+ * @ast node
+ * @astdecl ASTNode;
+ * @production ASTNode;
+
+ */
+public class ASTNode<T extends ASTNode> implements Cloneable {
+  /**
+   * @aspect RelAstAPI
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\ag.jadd:51
+   */
+  public boolean violatesLowerBounds() {
+    return !getLowerBoundsViolations().isEmpty();
+  }
+  /**
+   * @aspect RelAstAPI
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\ag.jadd:54
+   */
+  public java.util.List<Pair<ASTNode, String>> getLowerBoundsViolations() {
+    java.util.List<Pair<ASTNode, String>> list = new java.util.ArrayList<>();
+    computeLowerBoundsViolations(list);
+    return list;
+  }
+  /**
+   * @aspect RelAstAPI
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\ag.jadd:59
+   */
+  public void computeLowerBoundsViolations(java.util.List<Pair<ASTNode, String>> list) {
+    for (int i = 0; i < getNumChildNoTransform(); i++) {
+      getChildNoTransform(i).computeLowerBoundsViolations(list);
+    }
+  }
+  /**
+   * @aspect RelAstAPI
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\ag.jadd:85
+   */
+  public static void assertNotNull(Object obj) {
+    if (obj == null) {
+      throw new NullPointerException();
+    }
+  }
+  /**
+   * @aspect ResolverTrigger
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:212
+   */
+  public void resolveAll() {
+  }
+  /**
+   * @aspect ResolverTrigger
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:216
+   */
+  public void treeResolveAll() {
+    if (children != null) {
+      for (int i = 0; i < numChildren; ++i) {
+        ASTNode child = children[i];
+        if (child != null) {
+          child.treeResolveAll();
+        }
+      }
+    }
+    resolveAll();
+  }
+  /**
+   * @declaredat ASTNode:1
+   */
+  public ASTNode() {
+    super();
+    init$Children();
+  }
+  /**
+   * Initializes the child array to the correct size.
+   * Initializes List and Opt nta children.
+   * @apilevel internal
+   * @ast method
+   * @declaredat ASTNode:11
+   */
+  public void init$Children() {
+    state().enterConstruction();
+    state().exitConstruction();
+  }
+  /**
+   * Cached child index. Child indices are assumed to never change (AST should
+   * not change after construction).
+   * @apilevel internal
+   * @declaredat ASTNode:20
+   */
+  private int childIndex = -1;
+  /** @apilevel low-level 
+   * @declaredat ASTNode:23
+   */
+  public int getIndexOfChild(ASTNode node) {
+    if (node == null) {
+      return -1;
+    }
+    if (node.childIndex >= 0) {
+      return node.childIndex;
+    }
+    for (int i = 0; children != null && i < children.length; i++) {
+      if (getChild(i) == node) {
+        node.childIndex = i;
+        return i;
+      }
+    }
+    return -1;
+  }
+  /** @apilevel internal 
+   * @declaredat ASTNode:40
+   */
+  public static final boolean generatedWithCacheCycle = false;
+  /** @apilevel low-level 
+   * @declaredat ASTNode:43
+   */
+  protected ASTNode parent;
+  /** @apilevel low-level 
+   * @declaredat ASTNode:46
+   */
+  protected ASTNode[] children;
+  /**
+   * @declaredat ASTNode:48
+   */
+  public final ASTState.Trace trace() {
+    return state().trace();
+  }
+  /** @apilevel internal 
+   * @declaredat ASTNode:53
+   */
+  private static ASTState state = new ASTState();
+  /** @apilevel internal 
+   * @declaredat ASTNode:56
+   */
+  public final ASTState state() {
+    return state;
+  }
+  /** @apilevel internal 
+   * @declaredat ASTNode:61
+   */
+  public final static ASTState resetState() {
+    return state = new ASTState();
+  }
+  /**
+   * @return an iterator that can be used to iterate over the children of this node.
+   * The iterator does not allow removing children.
+   * @declaredat ASTNode:70
+   */
+  public java.util.Iterator<T> astChildIterator() {
+    return new java.util.Iterator<T>() {
+      private int index = 0;
+
+      @Override
+      public boolean hasNext() {
+        return index < getNumChild();
+      }
+
+      @Override
+      public T next() {
+        return hasNext() ? (T) getChild(index++) : null;
+      }
+
+      @Override
+      public void remove() {
+        throw new UnsupportedOperationException();
+      }
+    };
+  }
+  /** @return an object that can be used to iterate over the children of this node 
+   * @declaredat ASTNode:92
+   */
+  public Iterable<T> astChildren() {
+    return new Iterable<T>() {
+      @Override
+      public java.util.Iterator<T> iterator() {
+        return astChildIterator();
+      }
+    };
+  }
+  /**
+   * @declaredat ASTNode:101
+   */
+  public static String nodeToString(Object node) {
+    return (node != null ? node.getClass().getSimpleName() : "null");
+  }
+  /** @apilevel low-level 
+   * @declaredat ASTNode:105
+   */
+  public T getChild(int i) {
+    ASTNode node = this.getChildNoTransform(i);
+    
+    if (getChild_handler[i] == null) {
+      getChild_handler[i] = ASTNode$DepGraphNode.createAttrHandler(this, "getChild", Integer.valueOf(i));
+    }
+    state().addHandlerDepTo(getChild_handler[i]);
+    if (node != null && node.mayHaveRewrite()) {
+      
+      state().enterAttrStoreEval(getChild_handler[i]);
+      ASTNode rewritten = node.rewrittenNode();
+      if (rewritten != node) {
+        state().enterConstruction();
+        rewritten.setParent(this);
+        state().exitConstruction();
+        node = rewritten;
+      }
+      
+      state().exitAttrStoreEval(getChild_handler[i]);
+    }
+    return (T) node;
+  }
+  /** @apilevel low-level 
+   * @declaredat ASTNode:128
+   */
+  public ASTNode addChild(T node) {
+    setChild(node, getNumChildNoTransform());
+    int i = getNumChildNoTransform() - 1;
+    if (getChild_handler[i] == null) {
+      getChild_handler[i] = ASTNode$DepGraphNode.createAttrHandler(this, "getChild", Integer.valueOf(i));
+    }
+    state().addHandlerDepTo(getChild_handler[i]);
+    return this;
+  }
+  /**
+   * Gets a child without triggering rewrites.
+   * @apilevel low-level
+   * @declaredat ASTNode:141
+   */
+  public T getChildNoTransform(int i) {
+    if (children == null) {
+      return null;
+    }
+    T child = (T) children[i];
+    return child;
+  }
+  /** @apilevel low-level 
+   * @declaredat ASTNode:149
+   */
+  protected int numChildren;
+  /** @apilevel low-level 
+   * @declaredat ASTNode:152
+   */
+  protected int numChildren() {
+    
+    state().addHandlerDepTo(numChildren_handler);
+    return numChildren;
+  }
+  /** @apilevel low-level 
+   * @declaredat ASTNode:159
+   */
+  public int getNumChild() {
+    return numChildren();
+  }
+  /**
+   * Behaves like getNumChild, but does not invoke AST transformations (rewrites).
+   * @apilevel low-level
+   * @declaredat ASTNode:167
+   */
+  public final int getNumChildNoTransform() {
+    return numChildren();
+  }
+  /** @apilevel low-level 
+   * @declaredat ASTNode:171
+   */
+  public ASTNode setChild(ASTNode node, int i) {
+    
+    if (state().disableDeps == 0 && !state().IN_ATTR_STORE_EVAL) {
+      if (children != null && i < children.length && children[i] != null) {
+        children[i].inc_notifyForRemove();
+      }
+      if (children == null) {
+        numChildren_handler.notifyDependencies();
+      } else if (i >= numChildren) {
+        numChildren_handler.notifyDependencies();
+        if (i > 0 && getChild_handler[i-1] != null) {
+          getChild_handler[i-1].notifyDependencies();
+        }
+      } else {
+        if (getChild_handler[i] != null) {
+          getChild_handler[i].notifyDependencies();
+        } else {
+          getChild_handler[i] = ASTNode$DepGraphNode.createAttrHandler(this, "getChild", Integer.valueOf(i));
+        }
+      }
+    
+    
+    
+    
+    }
+    if (children == null) {
+      children = new ASTNode[(i + 1 > 4 || !(this instanceof JastAddList)) ? i + 1 : 4];
+      
+      getChild_handler = new ASTNode$DepGraphNode[(i + 1 > 4 || !(this instanceof JastAddList)) ? i + 1 : 4];
+    } else if (i >= children.length) {
+      ASTNode c[] = new ASTNode[i << 1];
+      System.arraycopy(children, 0, c, 0, children.length);
+      children = c;
+      
+      if (getChild_handler != null) {
+        ASTNode$DepGraphNode h[] = new ASTNode$DepGraphNode[i << 1];
+        System.arraycopy(getChild_handler, 0, h, 0, getChild_handler.length);
+        getChild_handler = h;
+      }
+    }
+    
+    if (children[i] != null) {
+      children[i].inc_throwAway();
+      children[i].parent = null;
+    }
+    children[i] = node;
+    if (i >= numChildren) {
+      numChildren = i+1;
+    }
+    if (node != null) {
+      node.setParent(this);
+      node.childIndex = i;
+    }
+    return this;
+  }
+  /** @apilevel low-level 
+   * @declaredat ASTNode:227
+   */
+  public ASTNode insertChild(ASTNode node, int i) {
+    
+    if (state().disableDeps == 0 && !state().IN_ATTR_STORE_EVAL) {
+      numChildren_handler.notifyDependencies();
+      if (children != null && i <= numChildren) {
+        for (int k = i; k < children.length; k++) {
+          if (getChild_handler[k] != null) {
+            getChild_handler[k].notifyDependencies();
+          }
+        }
+      }
+    
+    
+    
+    
+    }
+    if (children == null) {
+      children = new ASTNode[(i + 1 > 4 || !(this instanceof JastAddList)) ? i + 1 : 4];
+      children[i] = node;
+      
+      getChild_handler = new ASTNode$DepGraphNode[(i + 1 > 4 || !(this instanceof JastAddList)) ? i + 1 : 4];
+      getChild_handler[i] = ASTNode$DepGraphNode.createAttrHandler(this, "getChild", Integer.valueOf(i));
+    } else {
+      ASTNode c[] = new ASTNode[children.length + 1];
+      System.arraycopy(children, 0, c, 0, i);
+      c[i] = node;
+      if (i < children.length) {
+        System.arraycopy(children, i, c, i+1, children.length-i);
+        for(int j = i+1; j < c.length; ++j) {
+          if (c[j] != null) {
+            c[j].childIndex = j;
+          }
+        }
+      }
+      children = c;
+      
+      if (getChild_handler != null) {
+        ASTNode$DepGraphNode h[] = new ASTNode$DepGraphNode[getChild_handler.length + 1];
+        System.arraycopy(getChild_handler, 0, h, 0, getChild_handler.length);
+        getChild_handler = h;
+      }
+    }
+    numChildren++;
+    if (node != null) {
+      node.setParent(this);
+      node.childIndex = i;
+    }
+    return this;
+  }
+  /** @apilevel low-level 
+   * @declaredat ASTNode:277
+   */
+  public void removeChild(int i) {
+    if (children != null) {
+      
+      if (state().disableDeps == 0 && !state().IN_ATTR_STORE_EVAL) {
+        if (children[i] != null) {
+          children[i].inc_notifyForRemove();
+        }
+        numChildren_handler.notifyDependencies();
+        for (int k = i; k < children.length; k++) {
+          if (getChild_handler[k] != null) {
+            getChild_handler[k].notifyDependencies();
+          }
+        }
+      
+      
+      
+      
+      }
+      ASTNode child = (ASTNode) children[i];
+      if (child != null) {
+        
+        // Prevent recursive call during state handling where setParent calls removeChild.
+        child.inc_throwAway();
+        child.parent = null;
+        child.childIndex = -1;
+      }
+      // Adding a check of this instance to make sure its a List, a move of children doesn't make
+      // any sense for a node unless its a list. Also, there is a problem if a child of a non-List node is removed
+      // and siblings are moved one step to the right, with null at the end.
+      if (this instanceof JastAddList || this instanceof Opt) {
+        System.arraycopy(children, i+1, children, i, children.length-i-1);
+        children[children.length-1] = null;
+        numChildren--;
+        // fix child indices
+        for(int j = i; j < numChildren; ++j) {
+          if (children[j] != null) {
+            child = (ASTNode) children[j];
+            child.childIndex = j;
+          }
+        }
+      } else {
+        children[i] = null;
+      }
+      
+      if (getChild_handler != null && this instanceof JastAddList) {
+        getChild_handler[numChildren] = null;
+      }
+    }
+  }
+  /** @apilevel low-level 
+   * @declaredat ASTNode:327
+   */
+  public ASTNode getParent() {
+    
+    state().addHandlerDepTo(getParent_handler);
+    return (ASTNode) parent;
+  }
+  /** @apilevel low-level 
+   * @declaredat ASTNode:333
+   */
+  public void setParent(ASTNode node) {
+    if (state().disableDeps == 0 && !state().IN_ATTR_STORE_EVAL) {
+      getParent_handler.notifyDependencies();
+    }
+    /*
+    if (node != null) {
+      inc_changeState(node.inc_state);
+    } else {
+      inc_changeState(inc_GARBAGE);
+    }
+    */
+    parent = node;
+  }
+  /**
+   * Line and column information.
+   * @declaredat ASTNode:405
+   */
+  protected int startLine;
+  /**
+   * @declaredat ASTNode:406
+   */
+  protected short startColumn;
+  /**
+   * @declaredat ASTNode:407
+   */
+  protected int endLine;
+  /**
+   * @declaredat ASTNode:408
+   */
+  protected short endColumn;
+  /**
+   * @declaredat ASTNode:410
+   */
+  public int getStartLine() {
+    return startLine;
+  }
+  /**
+   * @declaredat ASTNode:413
+   */
+  public short getStartColumn() {
+    return startColumn;
+  }
+  /**
+   * @declaredat ASTNode:416
+   */
+  public int getEndLine() {
+    return endLine;
+  }
+  /**
+   * @declaredat ASTNode:419
+   */
+  public short getEndColumn() {
+    return endColumn;
+  }
+  /**
+   * @declaredat ASTNode:423
+   */
+  public void setStart(int startLine, short startColumn) {
+    this.startLine = startLine;
+    this.startColumn = startColumn;
+  }
+  /**
+   * @declaredat ASTNode:427
+   */
+  public void setEnd(int endLine, short endColumn) {
+    this.endLine = endLine;
+    this.endColumn = endColumn;
+  }
+  /**
+   * @apilevel internal
+   * @declaredat ASTNode:439
+   */
+  public boolean mayHaveRewrite() {
+    return false;
+  }
+  /** @apilevel low-level 
+   * @declaredat ASTNode:443
+   */
+  public void flushTreeCache() {
+  }
+  /** @apilevel low-level 
+   * @declaredat ASTNode:446
+   */
+  public void flushCache() {
+  }
+  /** @apilevel internal 
+   * @declaredat ASTNode:449
+   */
+  public void flushAttrAndCollectionCache() {
+  }
+  /** @apilevel internal 
+   * @declaredat ASTNode:452
+   */
+  public void flushAttrCache() {
+  }
+  /** @apilevel internal 
+   * @declaredat ASTNode:455
+   */
+  public void flushCollectionCache() {
+  }
+  /** @apilevel internal 
+   * @declaredat ASTNode:458
+   */
+  public ASTNode<T> clone() throws CloneNotSupportedException {
+    ASTNode node = (ASTNode) super.clone();
+    node.flushAttrAndCollectionCache();
+    return node;
+  }
+  /** @apilevel internal 
+   * @declaredat ASTNode:464
+   */
+  public ASTNode<T> copy() {
+    try {
+      ASTNode node = (ASTNode) clone();
+      node.parent = null;
+      if (children != null) {
+        node.children = (ASTNode[]) children.clone();
+      }
+      node.inc_state = inc_CLONED;
+      for (int i = 0; node.children != null && i < node.children.length; i++) {
+        node.children[i] = null;
+      }
+      inc_copyHandlers(node);
+      return node;
+    } catch (CloneNotSupportedException e) {
+      throw new Error("Error: clone not supported for " + getClass().getName());
+    }
+  }
+  /**
+   * Create a deep copy of the AST subtree at this node.
+   * The copy is dangling, i.e. has no parent.
+   * @return dangling copy of the subtree at this node
+   * @apilevel low-level
+   * @deprecated Please use treeCopy or treeCopyNoTransform instead
+   * @declaredat ASTNode:488
+   */
+  @Deprecated
+  public ASTNode<T> fullCopy() {
+    return treeCopyNoTransform();
+  }
+  /**
+   * Create a deep copy of the AST subtree at this node.
+   * The copy is dangling, i.e. has no parent.
+   * @return dangling copy of the subtree at this node
+   * @apilevel low-level
+   * @declaredat ASTNode:498
+   */
+  public ASTNode<T> treeCopyNoTransform() {
+    ASTNode tree = (ASTNode) copy();
+    if (children != null) {
+      for (int i = 0; i < children.length; ++i) {
+        ASTNode child = (ASTNode) children[i];
+        if (child != null) {
+          child = child.treeCopyNoTransform();
+          tree.children[i] = child;
+          child.parent = tree;
+        }
+      }
+    }
+    return tree;
+  }
+  /**
+   * Create a deep copy of the AST subtree at this node.
+   * The subtree of this node is traversed to trigger rewrites before copy.
+   * The copy is dangling, i.e. has no parent.
+   * @return dangling copy of the subtree at this node
+   * @apilevel low-level
+   * @declaredat ASTNode:519
+   */
+  public ASTNode<T> treeCopy() {
+    ASTNode tree = (ASTNode) copy();
+    if (children != null) {
+      for (int i = 0; i < children.length; ++i) {
+        ASTNode child = (ASTNode) getChild(i);
+        if (child != null) {
+          child = child.treeCopy();
+          tree.children[i] = child;
+          child.parent = tree;
+        }
+      }
+    }
+    return tree;
+  }
+  /**
+   * Performs a full traversal of the tree using getChild to trigger rewrites
+   * @apilevel low-level
+   * @declaredat ASTNode:537
+   */
+  public void doFullTraversal() {
+    for (int i = 0; i < getNumChild(); i++) {
+      getChild(i).doFullTraversal();
+    }
+  }
+  /**
+   * @declaredat ASTNode:542
+   */
+  public String relativeNodeID() {
+  StringBuffer res = new StringBuffer();
+  ASTNode parent = this.parent;
+  int index = -1;
+  if (parent != null) {
+    res.append(parent.relativeNodeID() + "/");
+    for (int i = 0; parent.children != null && i < parent.children.length; i++) {
+      if (parent.children[i] != null && parent.children[i] == this && !parent.childIsNTA(i)) {
+        index = i;
+        break;
+      }
+    }
+  }
+  res.append(getClass().getSimpleName());
+  if (index > -1) {
+    res.append("[" + index + (mayHaveRewrite() ? ",r" : "") + "]");
+  }
+  return res.toString();
+}
+  /** @apilevel internal 
+   * @declaredat ASTNode:562
+   */
+  protected boolean childIsNTA(int index) {
+    return false;
+  }
+  /**
+   * @declaredat ASTNode:565
+   */
+  protected ASTNode$DepGraphNode getParent_handler = ASTNode$DepGraphNode.createAstHandler(this, "getParent", null);
+  /**
+   * @declaredat ASTNode:566
+   */
+  protected ASTNode$DepGraphNode numChildren_handler = ASTNode$DepGraphNode.createAstHandler(this, "numChildren", null);
+  /**
+   * @declaredat ASTNode:567
+   */
+  protected ASTNode$DepGraphNode[] getChild_handler;
+  /**
+   * @declaredat ASTNode:568
+   */
+  protected void inc_copyHandlers(ASTNode copy) {
+    // ast handlers
+    if (getChild_handler != null) {
+      copy.getChild_handler = (ASTNode$DepGraphNode[])getChild_handler.clone();
+    }
+    copy.numChildren_handler = ASTNode$DepGraphNode.createAstHandler(numChildren_handler, copy);
+    copy.getParent_handler = ASTNode$DepGraphNode.createAstHandler(getParent_handler, copy);
+    for (int i = 0; getChild_handler != null && i < getChild_handler.length; i++) {
+      if (getChild_handler[i] != null) {
+        copy.getChild_handler[i] = ASTNode$DepGraphNode.createAttrHandler(getChild_handler[i], copy);
+      }
+    }
+
+  }
+  /** @apilevel internal 
+   * @declaredat ASTNode:584
+   */
+  public void reactToDependencyChange(String attrID, Object _parameters) {
+    
+    // flush children
+    if (attrID.equals("getChild")) {
+      int i = (Integer)_parameters;
+      getChild_handler[i].notifyDependencies();
+    }
+  }
+  /** @apilevel internal 
+   * @declaredat ASTNode:601
+   */
+  public void inc_notifyForRemove() {
+    getParent_handler.notifyDependencies();
+  }
+  /**
+   * @declaredat ASTNode:604
+   */
+  public static final int inc_CREATED = 0;
+  /**
+   * @declaredat ASTNode:605
+   */
+  public static final int inc_CLONED = 1;
+  /**
+   * @declaredat ASTNode:606
+   */
+  public static final int inc_LIVE = 2;
+  /**
+   * @declaredat ASTNode:607
+   */
+  public static final int inc_GARBAGE = 3;
+  /**
+   * @declaredat ASTNode:608
+   */
+  public static final int inc_EMPTY = 4;
+  /**
+   * @declaredat ASTNode:609
+   */
+  public static final int inc_COMPUTED = 5;
+  /**
+   * @declaredat ASTNode:610
+   */
+  public static final int inc_AST = 6;
+  /**
+   * @declaredat ASTNode:611
+   */
+  public int inc_state = inc_CREATED;
+  /**
+   * @declaredat ASTNode:612
+   */
+  private boolean inc_throwAway_visited = false;
+  /** @apilevel internal 
+   * @declaredat ASTNode:614
+   */
+  public void inc_throwAway() {
+  if (inc_throwAway_visited) {
+    return;
+  }
+  inc_throwAway_visited = true;
+  inc_state = inc_GARBAGE;
+  getParent_handler.throwAway();
+  numChildren_handler.throwAway();
+  for (int i = 0; children != null && i < children.length; i++) {
+    ASTNode child = children[i];
+    if (getChild_handler[i] != null) {
+      getChild_handler[i].throwAway();
+    }
+    if (child != null) {
+      child.inc_throwAway();
+    }
+  }
+
+  inc_throwAway_visited = false;
+}
+  /**
+   * @declaredat ASTNode:634
+   */
+  private boolean inc_cleanupListeners_visited = false;
+  /**
+   * @declaredat ASTNode:635
+   */
+  public void cleanupListeners() {
+  if (inc_cleanupListeners_visited) {
+    return;
+  }
+  inc_cleanupListeners_visited = true;
+  getParent_handler.cleanupListeners();
+  numChildren_handler.cleanupListeners();
+  for (int k = 0; getChild_handler != null && k < getChild_handler.length; k++) {
+    if (getChild_handler[k] != null) {
+      getChild_handler[k].cleanupListeners();
+    }
+  }
+  inc_cleanupListeners_visited = false;
+}
+  /**
+   * @declaredat ASTNode:649
+   */
+  private boolean inc_cleanupListenersInTree_visited = false;
+  /**
+   * @declaredat ASTNode:650
+   */
+  public void cleanupListenersInTree() {
+  if (inc_cleanupListenersInTree_visited) {
+    return;
+  }
+  inc_cleanupListenersInTree_visited = true;
+  cleanupListeners();
+  for (int i = 0; children != null && i < children.length; i++) {
+    ASTNode child = children[i];
+    if (child == null) {
+      continue;
+    }
+    child.cleanupListenersInTree();
+  }
+  inc_cleanupListenersInTree_visited = false;
+}
+  /**
+   * @attribute syn
+   * @aspect RefResolverStubs
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agResolverStubs.jrag:13
+   */
+  @ASTNodeAnnotation.Attribute(kind=ASTNodeAnnotation.Kind.SYN)
+  @ASTNodeAnnotation.Source(aspect="RefResolverStubs", declaredAt="E:\\project\\20211201\\src\\gen\\jastadd\\agResolverStubs.jrag:13")
+  public Root globallyResolveRootByToken(String id) {
+    {
+        // perform context independent name resolution here using the id
+        throw new RuntimeException("Context-independent name resolution for Root not implemented.");
+      }
+  }
+  /**
+   * @attribute syn
+   * @aspect RefResolverStubs
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agResolverStubs.jrag:20
+   */
+  @ASTNodeAnnotation.Attribute(kind=ASTNodeAnnotation.Kind.SYN)
+  @ASTNodeAnnotation.Source(aspect="RefResolverStubs", declaredAt="E:\\project\\20211201\\src\\gen\\jastadd\\agResolverStubs.jrag:20")
+  public Constraint globallyResolveConstraintByToken(String id) {
+    {
+        // perform context independent name resolution here using the id
+        throw new RuntimeException("Context-independent name resolution for Constraint not implemented.");
+      }
+  }
+  /**
+   * @attribute syn
+   * @aspect RefResolverStubs
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agResolverStubs.jrag:27
+   */
+  @ASTNodeAnnotation.Attribute(kind=ASTNodeAnnotation.Kind.SYN)
+  @ASTNodeAnnotation.Source(aspect="RefResolverStubs", declaredAt="E:\\project\\20211201\\src\\gen\\jastadd\\agResolverStubs.jrag:27")
+  public Atom globallyResolveAtomByToken(String id) {
+    {
+        // perform context independent name resolution here using the id
+        throw new RuntimeException("Context-independent name resolution for Atom not implemented.");
+      }
+  }
+  /**
+   * @attribute syn
+   * @aspect RefResolverStubs
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agResolverStubs.jrag:34
+   */
+  @ASTNodeAnnotation.Attribute(kind=ASTNodeAnnotation.Kind.SYN)
+  @ASTNodeAnnotation.Source(aspect="RefResolverStubs", declaredAt="E:\\project\\20211201\\src\\gen\\jastadd\\agResolverStubs.jrag:34")
+  public UnaryConstraint globallyResolveUnaryConstraintByToken(String id) {
+    {
+        // perform context independent name resolution here using the id
+        throw new RuntimeException("Context-independent name resolution for UnaryConstraint not implemented.");
+      }
+  }
+  /**
+   * @attribute syn
+   * @aspect RefResolverStubs
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agResolverStubs.jrag:41
+   */
+  @ASTNodeAnnotation.Attribute(kind=ASTNodeAnnotation.Kind.SYN)
+  @ASTNodeAnnotation.Source(aspect="RefResolverStubs", declaredAt="E:\\project\\20211201\\src\\gen\\jastadd\\agResolverStubs.jrag:41")
+  public BinaryConstraint globallyResolveBinaryConstraintByToken(String id) {
+    {
+        // perform context independent name resolution here using the id
+        throw new RuntimeException("Context-independent name resolution for BinaryConstraint not implemented.");
+      }
+  }
+  /**
+   * @attribute syn
+   * @aspect RefResolverStubs
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agResolverStubs.jrag:48
+   */
+  @ASTNodeAnnotation.Attribute(kind=ASTNodeAnnotation.Kind.SYN)
+  @ASTNodeAnnotation.Source(aspect="RefResolverStubs", declaredAt="E:\\project\\20211201\\src\\gen\\jastadd\\agResolverStubs.jrag:48")
+  public Conjunction globallyResolveConjunctionByToken(String id) {
+    {
+        // perform context independent name resolution here using the id
+        throw new RuntimeException("Context-independent name resolution for Conjunction not implemented.");
+      }
+  }
+  /**
+   * @attribute syn
+   * @aspect RefResolverStubs
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agResolverStubs.jrag:55
+   */
+  @ASTNodeAnnotation.Attribute(kind=ASTNodeAnnotation.Kind.SYN)
+  @ASTNodeAnnotation.Source(aspect="RefResolverStubs", declaredAt="E:\\project\\20211201\\src\\gen\\jastadd\\agResolverStubs.jrag:55")
+  public Disjunction globallyResolveDisjunctionByToken(String id) {
+    {
+        // perform context independent name resolution here using the id
+        throw new RuntimeException("Context-independent name resolution for Disjunction not implemented.");
+      }
+  }
+  /**
+   * @attribute syn
+   * @aspect RefResolverStubs
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agResolverStubs.jrag:62
+   */
+  @ASTNodeAnnotation.Attribute(kind=ASTNodeAnnotation.Kind.SYN)
+  @ASTNodeAnnotation.Source(aspect="RefResolverStubs", declaredAt="E:\\project\\20211201\\src\\gen\\jastadd\\agResolverStubs.jrag:62")
+  public Implication globallyResolveImplicationByToken(String id) {
+    {
+        // perform context independent name resolution here using the id
+        throw new RuntimeException("Context-independent name resolution for Implication not implemented.");
+      }
+  }
+  /**
+   * @attribute syn
+   * @aspect RefResolverStubs
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agResolverStubs.jrag:69
+   */
+  @ASTNodeAnnotation.Attribute(kind=ASTNodeAnnotation.Kind.SYN)
+  @ASTNodeAnnotation.Source(aspect="RefResolverStubs", declaredAt="E:\\project\\20211201\\src\\gen\\jastadd\\agResolverStubs.jrag:69")
+  public Negation globallyResolveNegationByToken(String id) {
+    {
+        // perform context independent name resolution here using the id
+        throw new RuntimeException("Context-independent name resolution for Negation not implemented.");
+      }
+  }
+  /**
+   * @attribute syn
+   * @aspect RefResolverStubs
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agResolverStubs.jrag:76
+   */
+  @ASTNodeAnnotation.Attribute(kind=ASTNodeAnnotation.Kind.SYN)
+  @ASTNodeAnnotation.Source(aspect="RefResolverStubs", declaredAt="E:\\project\\20211201\\src\\gen\\jastadd\\agResolverStubs.jrag:76")
+  public CheckSize globallyResolveCheckSizeByToken(String id) {
+    {
+        // perform context independent name resolution here using the id
+        throw new RuntimeException("Context-independent name resolution for CheckSize not implemented.");
+      }
+  }
+  /**
+   * @attribute syn
+   * @aspect RefResolverStubs
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agResolverStubs.jrag:83
+   */
+  @ASTNodeAnnotation.Attribute(kind=ASTNodeAnnotation.Kind.SYN)
+  @ASTNodeAnnotation.Source(aspect="RefResolverStubs", declaredAt="E:\\project\\20211201\\src\\gen\\jastadd\\agResolverStubs.jrag:83")
+  public CheckSeq globallyResolveCheckSeqByToken(String id) {
+    {
+        // perform context independent name resolution here using the id
+        throw new RuntimeException("Context-independent name resolution for CheckSeq not implemented.");
+      }
+  }
+  /**
+   * @attribute syn
+   * @aspect RefResolverStubs
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agResolverStubs.jrag:90
+   */
+  @ASTNodeAnnotation.Attribute(kind=ASTNodeAnnotation.Kind.SYN)
+  @ASTNodeAnnotation.Source(aspect="RefResolverStubs", declaredAt="E:\\project\\20211201\\src\\gen\\jastadd\\agResolverStubs.jrag:90")
+  public OnoDisk globallyResolveOnoDiskByToken(String id) {
+    {
+        // perform context independent name resolution here using the id
+        throw new RuntimeException("Context-independent name resolution for OnoDisk not implemented.");
+      }
+  }
+  /**
+   * @attribute syn
+   * @aspect RefResolverStubs
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agResolverStubs.jrag:97
+   */
+  @ASTNodeAnnotation.Attribute(kind=ASTNodeAnnotation.Kind.SYN)
+  @ASTNodeAnnotation.Source(aspect="RefResolverStubs", declaredAt="E:\\project\\20211201\\src\\gen\\jastadd\\agResolverStubs.jrag:97")
+  public TnoDisk globallyResolveTnoDiskByToken(String id) {
+    {
+        // perform context independent name resolution here using the id
+        throw new RuntimeException("Context-independent name resolution for TnoDisk not implemented.");
+      }
+  }
+  /**
+   * @attribute syn
+   * @aspect RefResolverStubs
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agResolverStubs.jrag:104
+   */
+  @ASTNodeAnnotation.Attribute(kind=ASTNodeAnnotation.Kind.SYN)
+  @ASTNodeAnnotation.Source(aspect="RefResolverStubs", declaredAt="E:\\project\\20211201\\src\\gen\\jastadd\\agResolverStubs.jrag:104")
+  public CheckD0 globallyResolveCheckD0ByToken(String id) {
+    {
+        // perform context independent name resolution here using the id
+        throw new RuntimeException("Context-independent name resolution for CheckD0 not implemented.");
+      }
+  }
+  /**
+   * @attribute syn
+   * @aspect RefResolverStubs
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agResolverStubs.jrag:111
+   */
+  @ASTNodeAnnotation.Attribute(kind=ASTNodeAnnotation.Kind.SYN)
+  @ASTNodeAnnotation.Source(aspect="RefResolverStubs", declaredAt="E:\\project\\20211201\\src\\gen\\jastadd\\agResolverStubs.jrag:111")
+  public Hanoi globallyResolveHanoiByToken(String id) {
+    {
+        // perform context independent name resolution here using the id
+        throw new RuntimeException("Context-independent name resolution for Hanoi not implemented.");
+      }
+  }
+  /**
+   * @attribute syn
+   * @aspect RefResolverStubs
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agResolverStubs.jrag:118
+   */
+  @ASTNodeAnnotation.Attribute(kind=ASTNodeAnnotation.Kind.SYN)
+  @ASTNodeAnnotation.Source(aspect="RefResolverStubs", declaredAt="E:\\project\\20211201\\src\\gen\\jastadd\\agResolverStubs.jrag:118")
+  public Disk globallyResolveDiskByToken(String id) {
+    {
+        // perform context independent name resolution here using the id
+        throw new RuntimeException("Context-independent name resolution for Disk not implemented.");
+      }
+  }
+  /**
+   * @attribute syn
+   * @aspect RefResolverStubs
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agResolverStubs.jrag:125
+   */
+  @ASTNodeAnnotation.Attribute(kind=ASTNodeAnnotation.Kind.SYN)
+  @ASTNodeAnnotation.Source(aspect="RefResolverStubs", declaredAt="E:\\project\\20211201\\src\\gen\\jastadd\\agResolverStubs.jrag:125")
+  public Pillar globallyResolvePillarByToken(String id) {
+    {
+        // perform context independent name resolution here using the id
+        throw new RuntimeException("Context-independent name resolution for Pillar not implemented.");
+      }
+  }
+  /** @apilevel internal */
+  public ASTNode rewriteTo() {
+    return this;
+  }
+  /** @apilevel internal */
+  public boolean canRewrite() {
+    return false;
+  }
+  /** @apilevel internal */
+  public int Define_moveSeq(ASTNode _callerNode, ASTNode _childNode) {
+    ASTNode self = this;
+    ASTNode parent = getParent();
+    while (parent != null && !parent.canDefine_moveSeq(self, _callerNode)) {
+      _callerNode = self;
+      self = parent;
+      parent = self.getParent();
+    }
+    return parent.Define_moveSeq(self, _callerNode);
+  }
+
+  /**
+   * @declaredat E:\\project\\20211201\\src\\main\\jastadd\\hanoi\\CanMove.jrag:13
+   * @apilevel internal
+   * @return {@code true} if this node has an equation for the inherited attribute moveSeq
+   */
+  protected boolean canDefine_moveSeq(ASTNode _callerNode, ASTNode _childNode) {
+    return false;
+  }
+  /** @apilevel internal */
+  public int Define_ID(ASTNode _callerNode, ASTNode _childNode) {
+    ASTNode self = this;
+    ASTNode parent = getParent();
+    while (parent != null && !parent.canDefine_ID(self, _callerNode)) {
+      _callerNode = self;
+      self = parent;
+      parent = self.getParent();
+    }
+    return parent.Define_ID(self, _callerNode);
+  }
+
+  /**
+   * @declaredat E:\\project\\20211201\\src\\main\\jastadd\\hanoi\\CanMove.jrag:21
+   * @apilevel internal
+   * @return {@code true} if this node has an equation for the inherited attribute ID
+   */
+  protected boolean canDefine_ID(ASTNode _callerNode, ASTNode _childNode) {
+    return false;
+  }
+public ASTNode rewrittenNode() { throw new Error("rewrittenNode is undefined for ASTNode"); }
+
+}
diff --git a/src/gen/java/org/jastadd/ag/ast/ASTNodeAnnotation.java b/src/gen/java/org/jastadd/ag/ast/ASTNodeAnnotation.java
new file mode 100644
index 0000000000000000000000000000000000000000..8c5765121bb5494e8f86101fdd12fe990ff33bbd
--- /dev/null
+++ b/src/gen/java/org/jastadd/ag/ast/ASTNodeAnnotation.java
@@ -0,0 +1,96 @@
+package org.jastadd.ag.ast;
+
+import java.util.*;
+/**
+ * @ast class
+ * @declaredat ASTNode:346
+ */
+public class ASTNodeAnnotation extends java.lang.Object {
+  /**
+   * @declaredat ASTNode:347
+   */
+  
+  @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.RUNTIME)
+  @java.lang.annotation.Target(java.lang.annotation.ElementType.METHOD)
+  @java.lang.annotation.Documented
+  public @interface Child {
+    String name();
+  }
+  /**
+   * @declaredat ASTNode:354
+   */
+  
+  
+  @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.RUNTIME)
+  @java.lang.annotation.Target(java.lang.annotation.ElementType.METHOD)
+  @java.lang.annotation.Documented
+  public @interface ListChild {
+    String name();
+  }
+  /**
+   * @declaredat ASTNode:361
+   */
+  
+  
+  @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.RUNTIME)
+  @java.lang.annotation.Target(java.lang.annotation.ElementType.METHOD)
+  @java.lang.annotation.Documented
+  public @interface OptChild {
+    String name();
+  }
+  /**
+   * @declaredat ASTNode:368
+   */
+  
+  
+  @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.RUNTIME)
+  @java.lang.annotation.Target(java.lang.annotation.ElementType.METHOD)
+  @java.lang.annotation.Documented
+  public @interface Token {
+    String name();
+  }
+  /**
+   * @declaredat ASTNode:375
+   */
+  
+  
+  @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.RUNTIME)
+  @java.lang.annotation.Target(java.lang.annotation.ElementType.METHOD)
+  @java.lang.annotation.Documented
+  public @interface Attribute {
+    Kind kind();
+    boolean isCircular() default false;
+    boolean isNTA() default false;
+  }
+  /**
+   * @declaredat ASTNode:383
+   */
+  
+  public enum Kind { SYN, INH, COLL }
+  /**
+   * @declaredat ASTNode:385
+   */
+  
+
+  @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.RUNTIME)
+  @java.lang.annotation.Target(java.lang.annotation.ElementType.METHOD)
+  @java.lang.annotation.Documented
+  public @interface Source {
+    String aspect() default "";
+    String declaredAt() default "";
+  }
+  /**
+   * @declaredat ASTNode:393
+   */
+  
+
+  @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.RUNTIME)
+  @java.lang.annotation.Target(java.lang.annotation.ElementType.CONSTRUCTOR)
+  @java.lang.annotation.Documented
+  public @interface Constructor{
+    String[] name(); 
+    String[] type(); 
+    String[] kind(); 
+  }
+
+}
diff --git a/src/gen/java/org/jastadd/ag/ast/ASTState.java b/src/gen/java/org/jastadd/ag/ast/ASTState.java
new file mode 100644
index 0000000000000000000000000000000000000000..f752a3c1af9ca78d753951243d76e657815f9468
--- /dev/null
+++ b/src/gen/java/org/jastadd/ag/ast/ASTState.java
@@ -0,0 +1,798 @@
+package org.jastadd.ag.ast;
+
+import java.util.*;
+/** @apilevel internal 
+ * @ast class
+ * @declaredat ASTState:34
+ */
+public class ASTState extends java.lang.Object {
+  /**
+   * This class stores an attribute value tagged with an iteration ID for
+   * a circular evaluation.
+   * 
+   * @apilevel internal
+   * @declaredat ASTState:41
+   */
+  
+  /**
+   * This class stores an attribute value tagged with an iteration ID for
+   * a circular evaluation.
+   *
+   * @apilevel internal
+   */
+  protected static class CircularValue {
+    Object value;
+    Cycle cycle;
+  }
+  /**
+   * Instances of this class are used to uniquely identify circular evaluation iterations.
+   * These iteration ID objects are created for each new fixed-point iteration in
+   * a circular evaluation.
+   * 
+   * @apilevel internal
+   * @declaredat ASTState:53
+   */
+  
+
+  /**
+   * Instances of this class are used to uniquely identify circular evaluation iterations.
+   * These iteration ID objects are created for each new fixed-point iteration in
+   * a circular evaluation.
+   *
+   * @apilevel internal
+   */
+  protected static class Cycle {
+  }
+  /**
+   * The iteration ID used outside of circular evaluation.
+   * 
+   * <p>This is the iteration ID when no circular evaluation is ongoing.
+   * @declaredat ASTState:61
+   */
+  
+
+  /**
+   * The iteration ID used outside of circular evaluation.
+   *
+   * <p>This is the iteration ID when no circular evaluation is ongoing.
+   */
+  public static final Cycle NON_CYCLE = new Cycle();
+  /**
+   * Tracks the state of the current circular evaluation. This class defines a
+   * stack structure where the next element on the stack is pointed to by the
+   * {@code next} field.
+   * 
+   * @apilevel internal
+   * @declaredat ASTState:70
+   */
+  
+
+  /**
+   * Tracks the state of the current circular evaluation. This class defines a
+   * stack structure where the next element on the stack is pointed to by the
+   * {@code next} field.
+   *
+   * @apilevel internal
+   */
+  protected static class CircleState {
+    final CircleState next;
+    boolean change = false;
+
+    /** Evaluation depth of lazy attributes. */
+    int lazyAttribute = 0;
+
+    /** Cycle ID of the latest cycle in this circular evaluation. */
+    Cycle cycle = NON_CYCLE;
+
+
+    protected CircleState(CircleState next) {
+      this.next = next;
+    }
+  }
+  /** Sentinel circle state representing non-circular evaluation. 
+   * @declaredat ASTState:88
+   */
+  
+
+
+  /** Sentinel circle state representing non-circular evaluation. */
+  private static final CircleState CIRCLE_BOTTOM = new CircleState(null);
+  /**
+   * Current circular state.
+   * @apilevel internal
+   * @declaredat ASTState:94
+   */
+  
+
+  /**
+   * Current circular state.
+   * @apilevel internal
+   */
+  private CircleState circle = CIRCLE_BOTTOM;
+  /** @apilevel internal 
+   * @declaredat ASTState:97
+   */
+  
+
+  /** @apilevel internal */
+  protected boolean inCircle() {
+    return circle != CIRCLE_BOTTOM;
+  }
+  /** @apilevel internal 
+   * @declaredat ASTState:102
+   */
+  
+
+  /** @apilevel internal */
+  protected boolean calledByLazyAttribute() {
+    return circle.lazyAttribute > 0;
+  }
+  /** @apilevel internal 
+   * @declaredat ASTState:107
+   */
+  
+
+  /** @apilevel internal */
+  protected void enterLazyAttribute() {
+    circle.lazyAttribute += 1;
+  }
+  /** @apilevel internal 
+   * @declaredat ASTState:112
+   */
+  
+
+  /** @apilevel internal */
+  protected void leaveLazyAttribute() {
+    circle.lazyAttribute -= 1;
+  }
+  /** @apilevel internal 
+   * @declaredat ASTState:117
+   */
+  
+
+  /** @apilevel internal */
+  protected void enterCircle() {
+    CircleState next = new CircleState(circle);
+    circle = next;
+  }
+  /**
+   * Maps circular attribute to last evaluated cycle index.
+   * @apilevel internal
+   * @declaredat ASTState:127
+   */
+  
+
+
+  /**
+   * Maps circular attribute to last evaluated cycle index.
+   * @apilevel internal
+   */
+  private java.util.Map<Object, Integer> visited = new java.util.IdentityHashMap<Object, Integer>();
+  /**
+   * Check if attribute was already visited during the current cycle.
+   * @apilevel internal
+   * @return {@code true} if the attribute was already visited.
+   * @declaredat ASTState:134
+   */
+  
+
+  /**
+   * Check if attribute was already visited during the current cycle.
+   * @apilevel internal
+   * @return {@code true} if the attribute was already visited.
+   */
+  protected boolean checkAndSetVisited(Object attribute, int cycle) {
+    boolean result = visited.containsKey(attribute) && visited.get(attribute) == cycle;
+    visited.put(attribute, cycle);
+    return result;
+  }
+  /**
+   * Reset visited cycle tracking for this thread.
+   * @apilevel internal
+   * @declaredat ASTState:144
+   */
+  
+
+  /**
+   * Reset visited cycle tracking for this thread.
+   * @apilevel internal
+   */
+  protected void clearVisited() {
+    visited.clear();
+  }
+  /**
+   * Reset visit tracker for a single attribute.
+   * @apilevel internal
+   * @declaredat ASTState:153
+   */
+  
+
+  // TODO(joqvist): may not be necessary.
+  /**
+   * Reset visit tracker for a single attribute.
+   * @apilevel internal
+   */
+  protected void resetVisited(Object attribute) {
+    visited.remove(attribute);
+  }
+  /** @apilevel internal 
+   * @declaredat ASTState:158
+   */
+  
+
+  /** @apilevel internal */
+  protected void leaveCircle() {
+    circle = circle.next;
+  }
+  /** @apilevel internal 
+   * @declaredat ASTState:163
+   */
+  
+
+  /** @apilevel internal */
+  protected Cycle nextCycle() {
+    Cycle cycle = new Cycle();
+    circle.cycle = cycle;
+    return cycle;
+  }
+  /** @apilevel internal 
+   * @declaredat ASTState:170
+   */
+  
+
+  /** @apilevel internal */
+  protected Cycle cycle() {
+    return circle.cycle;
+  }
+  /** @apilevel internal 
+   * @declaredat ASTState:175
+   */
+  
+
+  /** @apilevel internal */
+  protected CircleState currentCircle() {
+    return circle;
+  }
+  /** @apilevel internal 
+   * @declaredat ASTState:181
+   */
+  
+
+
+  /** @apilevel internal */
+  protected void setChangeInCycle() {
+    circle.change = true;
+  }
+  /** @apilevel internal 
+   * @declaredat ASTState:186
+   */
+  
+
+  /** @apilevel internal */
+  protected boolean testAndClearChangeInCycle() {
+    boolean change = circle.change;
+    circle.change = false;
+    return change;
+  }
+  /** @apilevel internal 
+   * @declaredat ASTState:193
+   */
+  
+
+  /** @apilevel internal */
+  protected boolean changeInCycle() {
+    return circle.change;
+  }
+  /**
+   * @declaredat ASTState:198
+   */
+  
+
+
+  protected ASTState() {
+  }
+  /**
+   * @declaredat ASTState:202
+   */
+  
+  
+  
+    protected java.util.Stack handlerAttrStack = new java.util.Stack();
+  /**
+   * @declaredat ASTState:204
+   */
+  
+  
+    public void addHandlerDepTo(ASTNode$DepGraphNode handler) {
+      if (!IN_ATTR_STORE_EVAL || handler == null) {
+        return;
+      }
+      java.util.Stack handlerStack = handlerAttrStack;
+      if (!handlerStack.isEmpty()) {
+        ASTNode$DepGraphNode top = (ASTNode$DepGraphNode) handlerStack.peek();
+        handler.addListener(top);
+  
+      }
+    }
+  /**
+   * @declaredat ASTState:216
+   */
+  
+  
+    public boolean IN_ATTR_STORE_EVAL = false;
+  /**
+   * @declaredat ASTState:218
+   */
+  
+  
+    public void enterAttrStoreEval(ASTNode$DepGraphNode handler) {
+      IN_ATTR_STORE_EVAL = true;
+      pushHandler(handlerAttrStack, handler);
+      handler.setComputed();
+    }
+  /**
+   * @declaredat ASTState:224
+   */
+  
+  
+    public void exitAttrStoreEval(ASTNode$DepGraphNode handler) {
+      popHandler(handlerAttrStack, handler);
+      IN_ATTR_STORE_EVAL = !handlerAttrStack.isEmpty();
+    }
+  /**
+   * @declaredat ASTState:229
+   */
+  
+  
+    public void enterRewriteEval(ASTNode$DepGraphNode handler) {
+      enterAttrStoreEval(handler);
+    }
+  /**
+   * @declaredat ASTState:233
+   */
+  
+  
+    public void exitRewriteEval(ASTNode$DepGraphNode handler) {
+      exitAttrStoreEval(handler);
+    }
+  /**
+   * @declaredat ASTState:237
+   */
+  
+  
+    public int disableDeps = 0;
+  /**
+   * @declaredat ASTState:239
+   */
+  
+  
+    public void enterConstruction() {
+      disableDeps++;
+    }
+  /**
+   * @declaredat ASTState:243
+   */
+  
+  
+    public void exitConstruction() {
+      disableDeps--;
+    }
+  /**
+   * @declaredat ASTState:247
+   */
+  
+  
+    protected void pushHandler(java.util.Stack stack, ASTNode$DepGraphNode handler) {
+      stack.push(handler);
+    }
+  /**
+   * @declaredat ASTState:251
+   */
+  
+  
+    protected ASTNode$DepGraphNode popHandler(java.util.Stack stack, ASTNode$DepGraphNode handler) {
+      if (stack.isEmpty()) {
+        throw new Error("Handler stack is empty at exit!");
+      }
+      ASTNode$DepGraphNode h = (ASTNode$DepGraphNode)stack.pop();
+      if (h != handler) {
+        throw new Error("Top of handler stack does not match at pop!");
+      }
+      return h;
+    }
+  /**
+   * @declaredat ASTState:262
+   */
+  
+
+  public interface ReceiverFactory {
+    Trace.Receiver build();
+  }
+  /**
+   * @declaredat ASTState:266
+   */
+  
+
+  public static ReceiverFactory receiverFactory = new ReceiverFactory() {
+    public Trace.Receiver build() {
+      return new Trace.Receiver() {
+        public void accept(ASTState.Trace.Event event, ASTNode node, String attribute,
+            Object params, Object value) {
+        }
+      };
+    }
+  };
+  /**
+   * @declaredat ASTState:276
+   */
+  
+
+  private Trace trace = null;
+  /** @return the tracer instance used for tracing attribute evaluation in this AST. 
+   * @declaredat ASTState:279
+   */
+  
+
+  /** @return the tracer instance used for tracing attribute evaluation in this AST. */
+  public Trace trace() {
+    if (trace == null) {
+      trace = new Trace(receiverFactory.build());
+    }
+    return trace;
+  }
+  /**
+   * @declaredat ASTState:286
+   */
+  
+
+  public static class Trace {
+    /**
+     * Trace events corresponding to attribute evaluation events.
+     *
+     * <p>These events can be filtered statically using the flag --tracing to
+     * JastAdd2. For example, the flag {@code --tracing=compute,cache} will only trace
+     * compute events and cache events. The flag --tracing will enable all events.
+     *
+     * <p>To access the trace events you will need to register an event receiver.
+     * This can be done using the method setReceiver(ASTState.Trace.Receiver).
+     */
+    public enum Event {
+      // Flag: --tracing=compute
+      COMPUTE_BEGIN,
+      COMPUTE_END,
+  
+      // Flag: --tracing=cache
+      CACHE_WRITE,
+      CACHE_READ,
+      CACHE_ABORT,
+  
+      // Flag: --tracing=rewrite
+      REWRITE_CASE1_START,
+      REWRITE_CASE1_CHANGE,
+      REWRITE_CASE1_RETURN,
+      REWRITE_CASE2_RETURN,
+      REWRITE_CASE3_RETURN,
+  
+      // Flag: --tracing=circular
+      CIRCULAR_NTA_CASE1_START,
+      CIRCULAR_NTA_CASE1_CHANGE,
+      CIRCULAR_NTA_CASE1_RETURN,
+      CIRCULAR_NTA_CASE2_START,
+      CIRCULAR_NTA_CASE2_CHANGE,
+      CIRCULAR_NTA_CASE2_RETURN,
+      CIRCULAR_NTA_CASE3_RETURN,
+      CIRCULAR_CASE1_START,
+      CIRCULAR_CASE1_CHANGE,
+      CIRCULAR_CASE1_RETURN,
+      CIRCULAR_CASE2_START,
+      CIRCULAR_CASE2_CHANGE,
+      CIRCULAR_CASE2_RETURN,
+      CIRCULAR_CASE3_RETURN,
+  
+      // Flag: --tracing=copy
+      COPY_NODE,
+  
+      // Flag: --tracing=flush
+      FLUSH_ATTR,
+      FLUSH_REWRITE,
+      FLUSH_REWRITE_INIT,
+      INC_FLUSH_ATTR,
+  
+      // Flag: --tracing=coll
+      CONTRIBUTION_CHECK_BEGIN,
+      CONTRIBUTION_CHECK_MATCH,
+      CONTRIBUTION_CHECK_END,
+      
+      // Flag: --tracing=token
+      TOKEN_READ;
+    }
+  
+    /**
+     * Functional interface for a trace event receiver.
+     * This can be implemented by applications that want to trace attribute evaluation.
+     */
+    public interface Receiver {
+      void accept(ASTState.Trace.Event event, ASTNode node, String attribute,
+          Object params, Object value);
+    }
+  
+    public Trace(Receiver receiver) {
+      this.receiver = receiver;
+    }
+  
+    public Trace() {
+    }
+  
+    // The default event receiver does nothing.
+    private Receiver receiver = new Receiver() {
+      public void accept(ASTState.Trace.Event event, ASTNode node, String attribute,
+          Object params, Object value) {
+      }
+    };
+  
+    /**
+     * Registers an input filter to use during tracing.
+     * @param filter The input filter to register.
+     */
+    public void setReceiver(ASTState.Trace.Receiver receiver) {
+      this.receiver = receiver;
+    }
+  
+    public Receiver getReceiver() {
+      return receiver;
+    }
+  
+    /**
+     * Trace that an attribute instance started its computation.
+     * @param value The value of the attribute instance.
+     */
+    public void computeBegin(ASTNode node, String attr, Object params, Object value) {
+      receiver.accept(Event.COMPUTE_BEGIN, node, attr, params, value);
+    }
+  
+    /**
+     * Trace that an attribute instance ended its computation.
+     * @param value The value of the attribute instance.
+     */
+    public void computeEnd(ASTNode node, String attr, Object params, Object value) {
+      receiver.accept(ASTState.Trace.Event.COMPUTE_END, node, attr, params, value);
+    }
+  
+    /**
+     * Trace that the cache of an attribute instances was read.
+     * @param value The value of the attribute instance.
+     */
+    public void cacheRead(ASTNode node, String attr, Object params, Object value) {
+      receiver.accept(ASTState.Trace.Event.CACHE_READ, node, attr, params, value);
+    }
+  
+    /**
+     * Trace that an attribute instance was cached.
+     * @param value The value of the attribute instance.
+     */
+    public void cacheWrite(ASTNode node, String attr, Object params, Object value) {
+      receiver.accept(ASTState.Trace.Event.CACHE_WRITE, node, attr, params, value);
+    }
+  
+    /**
+     * Trace that the caching of an attribute instance was aborted.
+     * @param value The value of the attribute instance.
+     */
+    public void cacheAbort(ASTNode node, String attr, Object params, Object value) {
+      receiver.accept(ASTState.Trace.Event.CACHE_ABORT, node, attr, params, value);
+    }
+  
+    /**
+     * Trace that a rewrite evaluation entered case 1.
+     * @param value The value of the rewrite.
+     */
+    public void enterRewriteCase1(ASTNode node, String attr, Object params, Object value) {
+      receiver.accept(ASTState.Trace.Event.REWRITE_CASE1_START, node, attr, params, value);
+    }
+  
+    /**
+     * Trace that a rewrite in evaluation case 1 changed value.
+     * @param value The value of the rewrite before and after.
+     */
+    public void rewriteChange(ASTNode node, String attr, Object params, Object value) {
+      receiver.accept(ASTState.Trace.Event.REWRITE_CASE1_CHANGE, node, attr, params, value);
+    }
+  
+    /**
+     * Trace that a rewrite returned from evaluation case 1.
+     * @param value The value of the rewrite.
+     */
+    public void exitRewriteCase1(ASTNode node, String attr, Object params, Object value) {
+      receiver.accept(ASTState.Trace.Event.REWRITE_CASE1_RETURN, node, attr, params, value);
+    }
+  
+    /**
+     * Trace that a rewrite returned from evaluation case 2.
+     * @param value The value of the rewrite.
+     */
+    public void exitRewriteCase2(ASTNode node, String attr, Object params, Object value) {
+      receiver.accept(ASTState.Trace.Event.REWRITE_CASE2_RETURN, node, attr, params, value);
+    }
+  
+    /**
+     * Trace that a rewrite returned from evaluation case 3.
+     * @param value The value of the rewrite.
+     */
+    public void exitRewriteCase3(ASTNode node, String attr, Object params, Object value) {
+      receiver.accept(ASTState.Trace.Event.REWRITE_CASE3_RETURN, node, attr, params, value);
+    }
+  
+    /**
+     * Trace that a circular attribute instance entered evaluation case 1.
+     * @param value The value of the circular attribute instance.
+     */
+    public void enterCircularCase1(ASTNode node, String attr, Object params, Object value) {
+      receiver.accept(ASTState.Trace.Event.CIRCULAR_CASE1_START, node, attr, params, value);
+    }
+  
+    /**
+     * Trace that a circular attribute instance in evaluation case 1 changed value.
+     * @param value The value of the circular attribute instance, before and after.
+     */
+    public void circularCase1Change(ASTNode node, String attr, Object params, Object value) {
+      receiver.accept(ASTState.Trace.Event.CIRCULAR_CASE1_CHANGE, node, attr, params, value);
+    }
+  
+    /**
+     * Trace that a circular attribute instance returned from evaluation case 1.
+     * @param value The value of the circular attribute instance.
+     */
+    public void exitCircularCase1(ASTNode node, String attr, Object params, Object value) {
+      receiver.accept(ASTState.Trace.Event.CIRCULAR_CASE1_RETURN, node, attr, params, value);
+    }
+  
+    /**
+     * Trace that a circular attribute instance entered evaluation case 2.
+     * @param value The value of the circular attribute instance.
+     */
+    public void enterCircularCase2(ASTNode node, String attr, Object params, Object value) {
+      receiver.accept(ASTState.Trace.Event.CIRCULAR_CASE2_START, node, attr, params, value);
+    }
+  
+    /**
+     * Trace that a circular attribute instance in evaluation case 2 changed value.
+     * @param value The value of the circular attribute instance, before and after.
+     */
+    public void circularCase2Change(ASTNode node, String attr, Object params, Object value) {
+      receiver.accept(ASTState.Trace.Event.CIRCULAR_CASE2_CHANGE, node, attr, params, value);
+    }
+  
+    /**
+     * Trace that a circular attribute instance returned from evaluation case 2.
+     * @param value The value of the circular attribute instance.
+     */
+    public void exitCircularCase2(ASTNode node, String attr, Object params, Object value) {
+      receiver.accept(ASTState.Trace.Event.CIRCULAR_CASE2_RETURN, node, attr, params, value);
+    }
+  
+    /**
+     * Trace that a circular attribute instance returned from evaluation case 2.
+     * @param value The value of the circular attribute instance.
+     */
+    public void exitCircularCase3(ASTNode node, String attr, Object params, Object value) {
+      receiver.accept(ASTState.Trace.Event.CIRCULAR_CASE3_RETURN, node, attr, params, value);
+    }
+  
+    /**
+     * Trace that a circular NTA entered evaluation case 1.
+     * @param value The value of the circular NTA.
+     */
+    public void enterCircularNTACase1(ASTNode node, String attr, Object params, Object value) {
+      receiver.accept(ASTState.Trace.Event.CIRCULAR_NTA_CASE1_START, node, attr, params, value);
+    }
+  
+    /**
+     * Trace that a circular NTA in evaluation case 1 changed value.
+     * @param value The value of the circular NTA, before and after.
+     */
+    public void circularNTACase1Change(ASTNode node, String attr, Object params, Object value) {
+      receiver.accept(ASTState.Trace.Event.CIRCULAR_NTA_CASE1_CHANGE, node, attr, params, value);
+    }
+  
+    /**
+     * Trace that a circular NTA returned from evaluation case 1.
+     * @param value The value of the circular NTA.
+     */
+    public void exitCircularNTACase1(ASTNode node, String attr, Object params, Object value) {
+      receiver.accept(ASTState.Trace.Event.CIRCULAR_NTA_CASE1_RETURN, node, attr, params, value);
+    }
+  
+    /**
+     * Trace that a circular NTA entered evaluation case 2.
+     * @param value The value of the circular NTA.
+     */
+    public void enterCircularNTACase2(ASTNode node, String attr, Object params, Object value) {
+      receiver.accept(ASTState.Trace.Event.CIRCULAR_NTA_CASE2_START, node, attr, params, value);
+    }
+  
+    /**
+     * Trace that a circular NTA in evaluation case 2 changed value.
+     * @param value The value of the circular NTA, before and after.
+     */
+    public void circularNTACase2Change(ASTNode node, String attr, Object params, Object value) {
+      receiver.accept(ASTState.Trace.Event.CIRCULAR_NTA_CASE2_CHANGE, node, attr, params, value);
+    }
+  
+    /**
+     * Trace that a circular NTA returned from evaluation case 2.
+     * @param value The value of the circular NTA.
+     */
+    public void exitCircularNTACase2(ASTNode node, String attr, Object params, Object value) {
+      receiver.accept(ASTState.Trace.Event.CIRCULAR_NTA_CASE2_RETURN, node, attr, params, value);
+    }
+  
+    /**
+     * Trace that a circular NTA returned from evaluation case 2.
+     * @param value The value of the circular NTA.
+     */
+    public void exitCircularNTACase3(ASTNode node, String attr, Object params, Object value) {
+      receiver.accept(ASTState.Trace.Event.CIRCULAR_NTA_CASE3_RETURN, node, attr, params, value);
+    }
+  
+    /**
+     * Trace that an AST node was copied.
+     * @param node The copied node.
+     * @param value The value of the node.
+     */
+    public void copyNode(ASTNode node, Object value) {
+      receiver.accept(ASTState.Trace.Event.COPY_NODE, node, "ASTNode.copy", "", value);
+    }
+  
+    /**
+     * Trace that an attribute was flushed.
+     * @param value The value of the attribute.
+     */
+    public void flushAttr(ASTNode node, String attr, Object params, Object value) {
+      receiver.accept(ASTState.Trace.Event.FLUSH_ATTR, node, attr, params, value);
+    }
+  
+    /**
+     * Trace that an attribute was flushed by incremental evaluation.
+     */
+    public void flushIncAttr(ASTNode node, String attr, Object params, Object value) {
+      receiver.accept(ASTState.Trace.Event.INC_FLUSH_ATTR, node, attr, params, value);
+    }
+  
+    /**
+     * Trace that a contribution check to a collection attribute begun.
+     */
+    public void contributionCheckBegin(ASTNode node, String attr, String check) {
+      receiver.accept(ASTState.Trace.Event.CONTRIBUTION_CHECK_BEGIN, node, attr, check, "");
+    }
+  
+    /**
+     * Trace that a contribution check to a collection attribute ended.
+     */
+    public void contributionCheckEnd(ASTNode node, String attr, String check) {
+      receiver.accept(ASTState.Trace.Event.CONTRIBUTION_CHECK_END, node, attr, check, "");
+    }
+  
+    /**
+     * Trace that a contribution check to a collection attribute found a match.
+     */
+    public void contributionCheckMatch(ASTNode node, String attr, String check, Object value) {
+      receiver.accept(ASTState.Trace.Event.CONTRIBUTION_CHECK_MATCH, node, attr, check, value);
+    }
+  
+    /**
+     * Trace that a token was read.
+     */
+    public void tokenRead(ASTNode node, String token, Object value) {
+      receiver.accept(ASTState.Trace.Event.TOKEN_READ, node, token, "", value);
+    }
+  
+  }
+  /** @apilevel internal 
+   * @declaredat ASTNode:432
+   */
+  public void reset() {
+    // Reset circular evaluation state.
+    circle = CIRCLE_BOTTOM;
+  }
+
+}
diff --git a/src/gen/java/org/jastadd/ag/ast/Atom.java b/src/gen/java/org/jastadd/ag/ast/Atom.java
new file mode 100644
index 0000000000000000000000000000000000000000..c9d30be3c12eea5f1ca50a5b1a473d77aba5e04f
--- /dev/null
+++ b/src/gen/java/org/jastadd/ag/ast/Atom.java
@@ -0,0 +1,346 @@
+/* This file was generated with JastAdd2 (http://jastadd.org) version 2.3.5 */
+package org.jastadd.ag.ast;
+import java.util.*;
+/**
+ * @ast node
+ * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\ag.ast:3
+ * @astdecl Atom : Constraint ::= <_impl_Rel:java.util.List<Pillar>>;
+ * @production Atom : {@link Constraint} ::= <span class="component">&lt;_impl_Rel:{@link java.util.List<Pillar>}&gt;</span>;
+
+ */
+public abstract class Atom extends Constraint implements Cloneable {
+  /**
+   * @aspect RelAstAPI
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\ag.jadd:4
+   */
+  public java.util.List<Pillar> getRels() {
+    return getRelList();
+  }
+  /**
+   * @aspect RelAstAPI
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\ag.jadd:7
+   */
+  public java.util.List<Pillar> getRelList() {
+    java.util.List<Pillar> l = get_impl_Rel();
+    if (l != null) {
+      boolean changed = false;
+      for (int i = 0; i < l.size(); i++) {
+        Pillar element = l.get(i);
+        if (element.is$Unresolved()) {
+          changed = true;
+          Pillar resolvedElement = resolveRelByToken(element.as$Unresolved().getUnresolved$Token(), i);
+          l.set(i, resolvedElement);
+        }
+      }
+      if (changed) {
+        set_impl_Rel(l);
+      }
+    }
+    return l != null ? java.util.Collections.unmodifiableList(l) : java.util.Collections.emptyList();
+  }
+  /**
+   * @aspect RelAstAPI
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\ag.jadd:25
+   */
+  public void addRel(Pillar o) {
+    assertNotNull(o);
+    java.util.List<Pillar> list = tokenjava_util_List_Pillar___impl_Rel;
+    if (list == null) {
+      list = new java.util.ArrayList<>();
+    }
+    list.add(o);
+    set_impl_Rel(list);
+  }
+  /**
+   * @aspect RelAstAPI
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\ag.jadd:34
+   */
+  public void addRel(int index, Pillar o) {
+    assertNotNull(o);
+    java.util.List<Pillar> list = tokenjava_util_List_Pillar___impl_Rel;
+    if (list == null) {
+      list = new java.util.ArrayList<>();
+    }
+    list.add(index, o);
+    set_impl_Rel(list);
+  }
+  /**
+   * @aspect RelAstAPI
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\ag.jadd:43
+   */
+  public void removeRel(Pillar o) {
+    assertNotNull(o);
+    java.util.List<Pillar> list = tokenjava_util_List_Pillar___impl_Rel;
+    if (list != null && list.remove(o)) {
+      set_impl_Rel(list);
+    }
+  }
+  /**
+   * @aspect ReferenceCreation
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:27
+   */
+  public static Atom createRef(String ref) {
+    Unresolved$CheckSize unresolvedNode = new Unresolved$CheckSize();
+    unresolvedNode.setUnresolved$Token(ref);
+    unresolvedNode.setUnresolved$ResolveOpposite(true);
+    return unresolvedNode;
+  }
+  /**
+   * @aspect ReferenceCreation
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:33
+   */
+  public static Atom createRefDirection(String ref) {
+    Unresolved$CheckSize unresolvedNode = new Unresolved$CheckSize();
+    unresolvedNode.setUnresolved$Token(ref);
+    unresolvedNode.setUnresolved$ResolveOpposite(false);
+    return unresolvedNode;
+  }
+  /**
+   * @aspect ResolverTrigger
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:236
+   */
+  public void resolveAll() {
+    getRelList();
+    super.resolveAll();
+  }
+  /**
+   * @aspect RefResolverHelpers
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:377
+   */
+  Unresolved$Node$Interface as$Unresolved() {
+    return null;
+  }
+  /**
+   * @aspect RefResolverHelpers
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:383
+   */
+  boolean is$Unresolved() {
+    return false;
+  }
+  /**
+   * @declaredat ASTNode:1
+   */
+  public Atom() {
+    super();
+  }
+  /**
+   * Initializes the child array to the correct size.
+   * Initializes List and Opt nta children.
+   * @apilevel internal
+   * @ast method
+   * @declaredat ASTNode:10
+   */
+  public void init$Children() {
+    state().enterConstruction();
+    state().exitConstruction();
+  }
+  /**
+   * @declaredat ASTNode:14
+   */
+  @ASTNodeAnnotation.Constructor(
+    name = {"_impl_Rel"},
+    type = {"java.util.List<Pillar>"},
+    kind = {"Token"}
+  )
+  public Atom(java.util.List<Pillar> p0) {
+state().enterConstruction();
+    set_impl_Rel(p0);
+state().exitConstruction();
+  }
+  /** @apilevel low-level 
+   * @declaredat ASTNode:25
+   */
+  protected int numChildren() {
+    
+    state().addHandlerDepTo(numChildren_handler);
+    return 0;
+  }
+  /**
+   * @apilevel internal
+   * @declaredat ASTNode:33
+   */
+  public boolean mayHaveRewrite() {
+    return false;
+  }
+  /** @apilevel internal 
+   * @declaredat ASTNode:37
+   */
+  public void flushAttrCache() {
+  }
+  /** @apilevel internal 
+   * @declaredat ASTNode:40
+   */
+  public void flushCollectionCache() {
+  }
+  /** @apilevel internal 
+   * @declaredat ASTNode:43
+   */
+  public Atom clone() throws CloneNotSupportedException {
+    Atom node = (Atom) super.clone();
+    return node;
+  }
+  /**
+   * Create a deep copy of the AST subtree at this node.
+   * The copy is dangling, i.e. has no parent.
+   * @return dangling copy of the subtree at this node
+   * @apilevel low-level
+   * @deprecated Please use treeCopy or treeCopyNoTransform instead
+   * @declaredat ASTNode:54
+   */
+  @Deprecated
+  public abstract Atom fullCopy();
+  /**
+   * Create a deep copy of the AST subtree at this node.
+   * The copy is dangling, i.e. has no parent.
+   * @return dangling copy of the subtree at this node
+   * @apilevel low-level
+   * @declaredat ASTNode:62
+   */
+  public abstract Atom treeCopyNoTransform();
+  /**
+   * Create a deep copy of the AST subtree at this node.
+   * The subtree of this node is traversed to trigger rewrites before copy.
+   * The copy is dangling, i.e. has no parent.
+   * @return dangling copy of the subtree at this node
+   * @apilevel low-level
+   * @declaredat ASTNode:70
+   */
+  public abstract Atom treeCopy();
+  /** @apilevel internal 
+   * @declaredat ASTNode:72
+   */
+  protected boolean childIsNTA(int index) {
+    return super.childIsNTA(index);
+  }
+  /**
+   * @declaredat ASTNode:75
+   */
+  protected void inc_copyHandlers(Atom copy) {
+    super.inc_copyHandlers(copy);
+
+        if (get_impl_Rel_handler != null) {
+          copy.get_impl_Rel_handler = ASTNode$DepGraphNode.createAstHandler(get_impl_Rel_handler, copy);
+        }
+  }
+  /** @apilevel internal 
+   * @declaredat ASTNode:84
+   */
+  public void reactToDependencyChange(String attrID, Object _parameters) {
+    super.reactToDependencyChange(attrID, _parameters);
+  }
+  /**
+   * @declaredat ASTNode:91
+   */
+  private boolean inc_throwAway_visited = false;
+  /** @apilevel internal 
+   * @declaredat ASTNode:93
+   */
+  public void inc_throwAway() {
+  if (inc_throwAway_visited) {
+    return;
+  }
+  inc_throwAway_visited = true;
+  inc_state = inc_GARBAGE;
+  super.inc_throwAway();
+  if (get_impl_Rel_handler != null) {
+    get_impl_Rel_handler.throwAway();
+  }
+  inc_throwAway_visited = false;
+}
+  /**
+   * @declaredat ASTNode:105
+   */
+  private boolean inc_cleanupListeners_visited = false;
+  /**
+   * @declaredat ASTNode:106
+   */
+  public void cleanupListeners() {
+  if (inc_cleanupListeners_visited) {
+    return;
+  }
+  inc_cleanupListeners_visited = true;
+  if (get_impl_Rel_handler != null) {
+    get_impl_Rel_handler.cleanupListeners();
+  }
+  super.cleanupListeners();
+  inc_cleanupListeners_visited = false;
+}
+  /**
+   * @declaredat ASTNode:117
+   */
+  private boolean inc_cleanupListenersInTree_visited = false;
+  /**
+   * @declaredat ASTNode:118
+   */
+  public void cleanupListenersInTree() {
+  if (inc_cleanupListenersInTree_visited) {
+    return;
+  }
+  inc_cleanupListenersInTree_visited = true;
+  cleanupListeners();
+  for (int i = 0; children != null && i < children.length; i++) {
+    ASTNode child = children[i];
+    if (child == null) {
+      continue;
+    }
+    child.cleanupListenersInTree();
+  }
+  inc_cleanupListenersInTree_visited = false;
+}
+  /**
+   */
+  protected ASTNode$DepGraphNode get_impl_Rel_handler = ASTNode$DepGraphNode.createAstHandler(this, "get_impl_Rel", null);
+  /**
+   * Replaces the lexeme _impl_Rel.
+   * @param value The new value for the lexeme _impl_Rel.
+   * @apilevel high-level
+   */
+  public Atom set_impl_Rel(java.util.List<Pillar> value) {
+    tokenjava_util_List_Pillar___impl_Rel = value;
+    
+    if (state().disableDeps == 0 && !state().IN_ATTR_STORE_EVAL) {
+      get_impl_Rel_handler.notifyDependencies();
+    
+    
+    
+    
+    }
+    return this;
+  }
+  /** @apilevel internal 
+   */
+  protected java.util.List<Pillar> tokenjava_util_List_Pillar___impl_Rel;
+  /**
+   * Retrieves the value for the lexeme _impl_Rel.
+   * @return The value for the lexeme _impl_Rel.
+   * @apilevel high-level
+   */
+  @ASTNodeAnnotation.Token(name="_impl_Rel")
+  public java.util.List<Pillar> get_impl_Rel() {
+    
+    state().addHandlerDepTo(get_impl_Rel_handler);
+    return tokenjava_util_List_Pillar___impl_Rel;
+  }
+  /**
+   * @attribute syn
+   * @aspect RefResolverStubs
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agResolverStubs.jrag:6
+   */
+  @ASTNodeAnnotation.Attribute(kind=ASTNodeAnnotation.Kind.SYN)
+  @ASTNodeAnnotation.Source(aspect="RefResolverStubs", declaredAt="E:\\project\\20211201\\src\\gen\\jastadd\\agResolverStubs.jrag:6")
+  public Pillar resolveRelByToken(String id, int position) {
+    {
+        // default to context-independent name resolution
+        return globallyResolvePillarByToken(id);
+      }
+  }
+  /** @apilevel internal */
+  public ASTNode rewriteTo() {
+    return super.rewriteTo();
+  }
+  /** @apilevel internal */
+  public boolean canRewrite() {
+    return false;
+  }
+
+}
diff --git a/src/gen/java/org/jastadd/ag/ast/AttributeValue.java b/src/gen/java/org/jastadd/ag/ast/AttributeValue.java
new file mode 100644
index 0000000000000000000000000000000000000000..68857e3c853146e9899def55a2f5a3970230accc
--- /dev/null
+++ b/src/gen/java/org/jastadd/ag/ast/AttributeValue.java
@@ -0,0 +1,61 @@
+package org.jastadd.ag.ast;
+
+import java.util.*;
+/** Wrapper class for storing nullable attribute values. 
+ * @ast class
+ * @declaredat ASTState:2
+ */
+public class AttributeValue<T> extends java.lang.Object {
+  /**
+   * This singleton object is an illegal, unused, attribute value.
+   * It represents that an attribute has not been memoized, or that
+   * a circular attribute approximation has not been initialized.
+   * @declaredat ASTState:8
+   */
+  
+  /**
+   * This singleton object is an illegal, unused, attribute value.
+   * It represents that an attribute has not been memoized, or that
+   * a circular attribute approximation has not been initialized.
+   */
+  public static final Object NONE = new Object();
+  /**
+   * @declaredat ASTState:10
+   */
+  
+
+  public final T value;
+  /**
+   * @declaredat ASTState:12
+   */
+  
+
+  public AttributeValue(T value) {
+    this.value = value;
+  }
+  /**
+   * @declaredat ASTState:16
+   */
+  
+
+  public static <V> boolean equals(AttributeValue<V> v1, AttributeValue<V> v2) {
+    if (v1 == null || v2 == null) {
+      return v1 == v2;
+    } else {
+      return equals(v1.value, v2.value);
+    }
+  }
+  /**
+   * @declaredat ASTState:24
+   */
+  
+
+  public static <V> boolean equals(V v1, V v2) {
+    if (v1 == null || v2 == null) {
+      return v1 == v2;
+    } else {
+      return v1 == v2 || v1.equals(v2);
+    }
+  }
+
+}
diff --git a/src/gen/java/org/jastadd/ag/ast/BinaryConstraint.java b/src/gen/java/org/jastadd/ag/ast/BinaryConstraint.java
new file mode 100644
index 0000000000000000000000000000000000000000..8768a8c2b1940ef56691afc1baa20e9e803d1969
--- /dev/null
+++ b/src/gen/java/org/jastadd/ag/ast/BinaryConstraint.java
@@ -0,0 +1,279 @@
+/* This file was generated with JastAdd2 (http://jastadd.org) version 2.3.5 */
+package org.jastadd.ag.ast;
+import java.util.*;
+/**
+ * @ast node
+ * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\ag.ast:5
+ * @astdecl BinaryConstraint : Constraint ::= Left:Constraint Right:Constraint;
+ * @production BinaryConstraint : {@link Constraint} ::= <span class="component">Left:{@link Constraint}</span> <span class="component">Right:{@link Constraint}</span>;
+
+ */
+public abstract class BinaryConstraint extends Constraint implements Cloneable {
+  /**
+   * @aspect ReferenceCreation
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:51
+   */
+  public static BinaryConstraint createRef(String ref) {
+    Unresolved$Conjunction unresolvedNode = new Unresolved$Conjunction();
+    unresolvedNode.setUnresolved$Token(ref);
+    unresolvedNode.setUnresolved$ResolveOpposite(true);
+    return unresolvedNode;
+  }
+  /**
+   * @aspect ReferenceCreation
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:57
+   */
+  public static BinaryConstraint createRefDirection(String ref) {
+    Unresolved$Conjunction unresolvedNode = new Unresolved$Conjunction();
+    unresolvedNode.setUnresolved$Token(ref);
+    unresolvedNode.setUnresolved$ResolveOpposite(false);
+    return unresolvedNode;
+  }
+  /**
+   * @aspect ResolverTrigger
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:245
+   */
+  public void resolveAll() {
+    super.resolveAll();
+  }
+  /**
+   * @aspect RefResolverHelpers
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:433
+   */
+  Unresolved$Node$Interface as$Unresolved() {
+    return null;
+  }
+  /**
+   * @aspect RefResolverHelpers
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:439
+   */
+  boolean is$Unresolved() {
+    return false;
+  }
+  /**
+   * @declaredat ASTNode:1
+   */
+  public BinaryConstraint() {
+    super();
+  }
+  /**
+   * Initializes the child array to the correct size.
+   * Initializes List and Opt nta children.
+   * @apilevel internal
+   * @ast method
+   * @declaredat ASTNode:10
+   */
+  public void init$Children() {
+    children = new ASTNode[2];  getChild_handler = new ASTNode$DepGraphNode[children.length];
+    state().enterConstruction();
+    state().exitConstruction();
+  }
+  /**
+   * @declaredat ASTNode:15
+   */
+  @ASTNodeAnnotation.Constructor(
+    name = {"Left", "Right"},
+    type = {"Constraint", "Constraint"},
+    kind = {"Child", "Child"}
+  )
+  public BinaryConstraint(Constraint p0, Constraint p1) {
+state().enterConstruction();
+    setChild(p0, 0);
+    setChild(p1, 1);
+state().exitConstruction();
+  }
+  /** @apilevel low-level 
+   * @declaredat ASTNode:27
+   */
+  protected int numChildren() {
+    
+    state().addHandlerDepTo(numChildren_handler);
+    return 2;
+  }
+  /**
+   * @apilevel internal
+   * @declaredat ASTNode:35
+   */
+  public boolean mayHaveRewrite() {
+    return false;
+  }
+  /** @apilevel internal 
+   * @declaredat ASTNode:39
+   */
+  public void flushAttrCache() {
+  }
+  /** @apilevel internal 
+   * @declaredat ASTNode:42
+   */
+  public void flushCollectionCache() {
+  }
+  /** @apilevel internal 
+   * @declaredat ASTNode:45
+   */
+  public BinaryConstraint clone() throws CloneNotSupportedException {
+    BinaryConstraint node = (BinaryConstraint) super.clone();
+    return node;
+  }
+  /**
+   * Create a deep copy of the AST subtree at this node.
+   * The copy is dangling, i.e. has no parent.
+   * @return dangling copy of the subtree at this node
+   * @apilevel low-level
+   * @deprecated Please use treeCopy or treeCopyNoTransform instead
+   * @declaredat ASTNode:56
+   */
+  @Deprecated
+  public abstract BinaryConstraint fullCopy();
+  /**
+   * Create a deep copy of the AST subtree at this node.
+   * The copy is dangling, i.e. has no parent.
+   * @return dangling copy of the subtree at this node
+   * @apilevel low-level
+   * @declaredat ASTNode:64
+   */
+  public abstract BinaryConstraint treeCopyNoTransform();
+  /**
+   * Create a deep copy of the AST subtree at this node.
+   * The subtree of this node is traversed to trigger rewrites before copy.
+   * The copy is dangling, i.e. has no parent.
+   * @return dangling copy of the subtree at this node
+   * @apilevel low-level
+   * @declaredat ASTNode:72
+   */
+  public abstract BinaryConstraint treeCopy();
+  /** @apilevel internal 
+   * @declaredat ASTNode:74
+   */
+  protected boolean childIsNTA(int index) {
+    return super.childIsNTA(index);
+  }
+  /**
+   * @declaredat ASTNode:77
+   */
+  protected void inc_copyHandlers(BinaryConstraint copy) {
+    super.inc_copyHandlers(copy);
+
+  }
+  /** @apilevel internal 
+   * @declaredat ASTNode:83
+   */
+  public void reactToDependencyChange(String attrID, Object _parameters) {
+    super.reactToDependencyChange(attrID, _parameters);
+  }
+  /**
+   * @declaredat ASTNode:90
+   */
+  private boolean inc_throwAway_visited = false;
+  /** @apilevel internal 
+   * @declaredat ASTNode:92
+   */
+  public void inc_throwAway() {
+  if (inc_throwAway_visited) {
+    return;
+  }
+  inc_throwAway_visited = true;
+  inc_state = inc_GARBAGE;
+  super.inc_throwAway();
+  inc_throwAway_visited = false;
+}
+  /**
+   * @declaredat ASTNode:101
+   */
+  private boolean inc_cleanupListeners_visited = false;
+  /**
+   * @declaredat ASTNode:102
+   */
+  public void cleanupListeners() {
+  if (inc_cleanupListeners_visited) {
+    return;
+  }
+  inc_cleanupListeners_visited = true;
+  super.cleanupListeners();
+  inc_cleanupListeners_visited = false;
+}
+  /**
+   * @declaredat ASTNode:110
+   */
+  private boolean inc_cleanupListenersInTree_visited = false;
+  /**
+   * @declaredat ASTNode:111
+   */
+  public void cleanupListenersInTree() {
+  if (inc_cleanupListenersInTree_visited) {
+    return;
+  }
+  inc_cleanupListenersInTree_visited = true;
+  cleanupListeners();
+  for (int i = 0; children != null && i < children.length; i++) {
+    ASTNode child = children[i];
+    if (child == null) {
+      continue;
+    }
+    child.cleanupListenersInTree();
+  }
+  inc_cleanupListenersInTree_visited = false;
+}
+  /**
+   * Replaces the Left child.
+   * @param node The new node to replace the Left child.
+   * @apilevel high-level
+   */
+  public BinaryConstraint setLeft(Constraint node) {
+    setChild(node, 0);
+    return this;
+  }
+  /**
+   * Retrieves the Left child.
+   * @return The current node used as the Left child.
+   * @apilevel high-level
+   */
+  @ASTNodeAnnotation.Child(name="Left")
+  public Constraint getLeft() {
+    return (Constraint) getChild(0);
+  }
+  /**
+   * Retrieves the Left child.
+   * <p><em>This method does not invoke AST transformations.</em></p>
+   * @return The current node used as the Left child.
+   * @apilevel low-level
+   */
+  public Constraint getLeftNoTransform() {
+    return (Constraint) getChildNoTransform(0);
+  }
+  /**
+   * Replaces the Right child.
+   * @param node The new node to replace the Right child.
+   * @apilevel high-level
+   */
+  public BinaryConstraint setRight(Constraint node) {
+    setChild(node, 1);
+    return this;
+  }
+  /**
+   * Retrieves the Right child.
+   * @return The current node used as the Right child.
+   * @apilevel high-level
+   */
+  @ASTNodeAnnotation.Child(name="Right")
+  public Constraint getRight() {
+    return (Constraint) getChild(1);
+  }
+  /**
+   * Retrieves the Right child.
+   * <p><em>This method does not invoke AST transformations.</em></p>
+   * @return The current node used as the Right child.
+   * @apilevel low-level
+   */
+  public Constraint getRightNoTransform() {
+    return (Constraint) getChildNoTransform(1);
+  }
+  /** @apilevel internal */
+  public ASTNode rewriteTo() {
+    return super.rewriteTo();
+  }
+  /** @apilevel internal */
+  public boolean canRewrite() {
+    return false;
+  }
+
+}
diff --git a/src/gen/java/org/jastadd/ag/ast/CheckD0.java b/src/gen/java/org/jastadd/ag/ast/CheckD0.java
new file mode 100644
index 0000000000000000000000000000000000000000..37788827875c954d0088c2b847dccc40e6a2b25f
--- /dev/null
+++ b/src/gen/java/org/jastadd/ag/ast/CheckD0.java
@@ -0,0 +1,390 @@
+/* This file was generated with JastAdd2 (http://jastadd.org) version 2.3.5 */
+package org.jastadd.ag.ast;
+import java.util.*;
+/**
+ * @ast node
+ * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\ag.ast:14
+ * @astdecl CheckD0 : Atom ::= <_impl_Rel:java.util.List<Pillar>>;
+ * @production CheckD0 : {@link Atom};
+
+ */
+public class CheckD0 extends Atom implements Cloneable {
+  /**
+   * @aspect ReferenceCreation
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:159
+   */
+  public static CheckD0 createRef(String ref) {
+    Unresolved$CheckD0 unresolvedNode = new Unresolved$CheckD0();
+    unresolvedNode.setUnresolved$Token(ref);
+    unresolvedNode.setUnresolved$ResolveOpposite(true);
+    return unresolvedNode;
+  }
+  /**
+   * @aspect ReferenceCreation
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:165
+   */
+  public static CheckD0 createRefDirection(String ref) {
+    Unresolved$CheckD0 unresolvedNode = new Unresolved$CheckD0();
+    unresolvedNode.setUnresolved$Token(ref);
+    unresolvedNode.setUnresolved$ResolveOpposite(false);
+    return unresolvedNode;
+  }
+  /**
+   * @aspect ResolverTrigger
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:281
+   */
+  public void resolveAll() {
+    super.resolveAll();
+  }
+  /**
+   * @aspect RefResolverHelpers
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:685
+   */
+  Unresolved$Node$Interface as$Unresolved() {
+    return null;
+  }
+  /**
+   * @aspect RefResolverHelpers
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:691
+   */
+  boolean is$Unresolved() {
+    return false;
+  }
+  /**
+   * @declaredat ASTNode:1
+   */
+  public CheckD0() {
+    super();
+  }
+  /**
+   * Initializes the child array to the correct size.
+   * Initializes List and Opt nta children.
+   * @apilevel internal
+   * @ast method
+   * @declaredat ASTNode:10
+   */
+  public void init$Children() {
+    state().enterConstruction();
+    state().exitConstruction();
+  }
+  /**
+   * @declaredat ASTNode:14
+   */
+  @ASTNodeAnnotation.Constructor(
+    name = {"_impl_Rel"},
+    type = {"java.util.List<Pillar>"},
+    kind = {"Token"}
+  )
+  public CheckD0(java.util.List<Pillar> p0) {
+state().enterConstruction();
+    set_impl_Rel(p0);
+state().exitConstruction();
+  }
+  /** @apilevel low-level 
+   * @declaredat ASTNode:25
+   */
+  protected int numChildren() {
+    
+    state().addHandlerDepTo(numChildren_handler);
+    return 0;
+  }
+  /**
+   * @apilevel internal
+   * @declaredat ASTNode:33
+   */
+  public boolean mayHaveRewrite() {
+    return false;
+  }
+  /** @apilevel internal 
+   * @declaredat ASTNode:37
+   */
+  public void flushAttrCache() {
+  }
+  /** @apilevel internal 
+   * @declaredat ASTNode:40
+   */
+  public void flushCollectionCache() {
+  }
+  /** @apilevel internal 
+   * @declaredat ASTNode:43
+   */
+  public CheckD0 clone() throws CloneNotSupportedException {
+    CheckD0 node = (CheckD0) super.clone();
+    return node;
+  }
+  /** @apilevel internal 
+   * @declaredat ASTNode:48
+   */
+  public CheckD0 copy() {
+    try {
+      CheckD0 node = (CheckD0) clone();
+      node.parent = null;
+      if (children != null) {
+        node.children = (ASTNode[]) children.clone();
+      }
+      node.inc_state = inc_CLONED;
+      for (int i = 0; node.children != null && i < node.children.length; i++) {
+        node.children[i] = null;
+      }
+      inc_copyHandlers(node);
+      return node;
+    } catch (CloneNotSupportedException e) {
+      throw new Error("Error: clone not supported for " + getClass().getName());
+    }
+  }
+  /**
+   * Create a deep copy of the AST subtree at this node.
+   * The copy is dangling, i.e. has no parent.
+   * @return dangling copy of the subtree at this node
+   * @apilevel low-level
+   * @deprecated Please use treeCopy or treeCopyNoTransform instead
+   * @declaredat ASTNode:72
+   */
+  @Deprecated
+  public CheckD0 fullCopy() {
+    return treeCopyNoTransform();
+  }
+  /**
+   * Create a deep copy of the AST subtree at this node.
+   * The copy is dangling, i.e. has no parent.
+   * @return dangling copy of the subtree at this node
+   * @apilevel low-level
+   * @declaredat ASTNode:82
+   */
+  public CheckD0 treeCopyNoTransform() {
+    CheckD0 tree = (CheckD0) copy();
+    if (children != null) {
+      for (int i = 0; i < children.length; ++i) {
+        ASTNode child = (ASTNode) children[i];
+        if (child != null) {
+          child = child.treeCopyNoTransform();
+          tree.children[i] = child;
+          child.parent = tree;
+        }
+      }
+    }
+    return tree;
+  }
+  /**
+   * Create a deep copy of the AST subtree at this node.
+   * The subtree of this node is traversed to trigger rewrites before copy.
+   * The copy is dangling, i.e. has no parent.
+   * @return dangling copy of the subtree at this node
+   * @apilevel low-level
+   * @declaredat ASTNode:103
+   */
+  public CheckD0 treeCopy() {
+    CheckD0 tree = (CheckD0) copy();
+    if (children != null) {
+      for (int i = 0; i < children.length; ++i) {
+        ASTNode child = (ASTNode) getChild(i);
+        if (child != null) {
+          child = child.treeCopy();
+          tree.children[i] = child;
+          child.parent = tree;
+        }
+      }
+    }
+    return tree;
+  }
+  /** @apilevel internal 
+   * @declaredat ASTNode:118
+   */
+  protected boolean childIsNTA(int index) {
+    return super.childIsNTA(index);
+  }
+  /**
+   * @declaredat ASTNode:121
+   */
+  protected ASTNode$DepGraphNode eval_handler;
+  /**
+   * @declaredat ASTNode:122
+   */
+  protected void inc_copyHandlers(CheckD0 copy) {
+    super.inc_copyHandlers(copy);
+
+        if (eval_handler != null) {
+          copy.eval_handler = ASTNode$DepGraphNode.createAttrHandler(eval_handler, copy);
+        }
+  }
+  /** @apilevel internal 
+   * @declaredat ASTNode:131
+   */
+  public void reactToDependencyChange(String attrID, Object _parameters) {
+    super.reactToDependencyChange(attrID, _parameters);
+  }
+  /**
+   * @declaredat ASTNode:138
+   */
+  private boolean inc_throwAway_visited = false;
+  /** @apilevel internal 
+   * @declaredat ASTNode:140
+   */
+  public void inc_throwAway() {
+  if (inc_throwAway_visited) {
+    return;
+  }
+  inc_throwAway_visited = true;
+  inc_state = inc_GARBAGE;
+  super.inc_throwAway();
+  if (eval_handler != null) {
+    eval_handler.throwAway();
+  }
+  inc_throwAway_visited = false;
+}
+  /**
+   * @declaredat ASTNode:152
+   */
+  private boolean inc_cleanupListeners_visited = false;
+  /**
+   * @declaredat ASTNode:153
+   */
+  public void cleanupListeners() {
+  if (inc_cleanupListeners_visited) {
+    return;
+  }
+  inc_cleanupListeners_visited = true;
+  if (get_impl_Rel_handler != null) {
+    get_impl_Rel_handler.cleanupListeners();
+  }
+  if (eval_handler != null) {
+    eval_handler.cleanupListeners();
+  }
+  super.cleanupListeners();
+  inc_cleanupListeners_visited = false;
+}
+  /**
+   * @declaredat ASTNode:167
+   */
+  private boolean inc_cleanupListenersInTree_visited = false;
+  /**
+   * @declaredat ASTNode:168
+   */
+  public void cleanupListenersInTree() {
+  if (inc_cleanupListenersInTree_visited) {
+    return;
+  }
+  inc_cleanupListenersInTree_visited = true;
+  cleanupListeners();
+  for (int i = 0; children != null && i < children.length; i++) {
+    ASTNode child = children[i];
+    if (child == null) {
+      continue;
+    }
+    child.cleanupListenersInTree();
+  }
+  inc_cleanupListenersInTree_visited = false;
+}
+  /**
+   */
+  protected ASTNode$DepGraphNode get_impl_Rel_handler = ASTNode$DepGraphNode.createAstHandler(this, "get_impl_Rel", null);
+  /**
+   * Replaces the lexeme _impl_Rel.
+   * @param value The new value for the lexeme _impl_Rel.
+   * @apilevel high-level
+   */
+  public CheckD0 set_impl_Rel(java.util.List<Pillar> value) {
+    tokenjava_util_List_Pillar___impl_Rel = value;
+    
+    if (state().disableDeps == 0 && !state().IN_ATTR_STORE_EVAL) {
+      get_impl_Rel_handler.notifyDependencies();
+    
+    
+    
+    
+    }
+    return this;
+  }
+  /**
+   * Retrieves the value for the lexeme _impl_Rel.
+   * @return The value for the lexeme _impl_Rel.
+   * @apilevel high-level
+   */
+  @ASTNodeAnnotation.Token(name="_impl_Rel")
+  public java.util.List<Pillar> get_impl_Rel() {
+    
+    state().addHandlerDepTo(get_impl_Rel_handler);
+    return tokenjava_util_List_Pillar___impl_Rel;
+  }
+  /** @apilevel internal */
+  private void eval_reset() {
+    state().trace().flushAttr(this, "Constraint.eval()", "", eval_value);
+    eval_computed = null;
+  }
+  /** @apilevel internal */
+  protected ASTState.Cycle eval_computed = null;
+
+  /** @apilevel internal */
+  protected boolean eval_value;
+
+  /**
+   * @attribute syn
+   * @aspect Constraints
+   * @declaredat E:\\project\\20211201\\src\\main\\jastadd\\hanoi\\Constraints.jrag:36
+   */
+  @ASTNodeAnnotation.Attribute(kind=ASTNodeAnnotation.Kind.SYN)
+  @ASTNodeAnnotation.Source(aspect="Constraints", declaredAt="E:\\project\\20211201\\src\\main\\jastadd\\hanoi\\Constraints.jrag:3")
+  public boolean eval() {
+    ASTState state = state();
+    
+    if (eval_handler == null) {
+      eval_handler = new ASTNode$DepGraphNode(this, "eval", null, ASTNode.inc_EMPTY) {
+        @Override public void reactToDependencyChange() {
+          {
+            eval_computed = null;
+            eval_handler.notifyDependencies();
+            CheckD0.this.state().trace().flushIncAttr(CheckD0.this, "eval", "", "");
+          }
+        }
+      };
+    }
+    state().addHandlerDepTo(eval_handler);
+    
+    
+    
+    
+    
+    if (eval_computed == ASTState.NON_CYCLE || eval_computed == state().cycle()) {
+      state().trace().cacheRead(this, "Constraint.eval()", "", eval_value);
+      return eval_value;
+    }
+    
+    state().enterAttrStoreEval(eval_handler);
+    eval_value = eval_compute();
+    if (state().inCircle()) {
+      eval_computed = state().cycle();
+      state().trace().cacheWrite(this, "Constraint.eval()", "", eval_value);
+    } else {
+      eval_computed = ASTState.NON_CYCLE;
+      state().trace().cacheWrite(this, "Constraint.eval()", "", eval_value);
+    }
+    
+    state().exitAttrStoreEval(eval_handler);
+    
+    
+    
+    
+    
+    
+    return eval_value;
+  }
+  /** @apilevel internal */
+  private boolean eval_compute() {
+          //the pillar has the smallest disk D0 on the top?
+          if(this.getRels().get(0).getNumDisk()>0){
+          //if the pillar is not empty, check if the top disk has size 1.
+              return  this.getRels().get(0).getDisk(this.getRels().get(0).getNumDisk()-1).getSize()==1;
+          }else{
+              return false;
+          }
+      }
+  /** @apilevel internal */
+  public ASTNode rewriteTo() {
+    return super.rewriteTo();
+  }
+  /** @apilevel internal */
+  public boolean canRewrite() {
+    return false;
+  }
+
+}
diff --git a/src/gen/java/org/jastadd/ag/ast/CheckSeq.java b/src/gen/java/org/jastadd/ag/ast/CheckSeq.java
new file mode 100644
index 0000000000000000000000000000000000000000..8ab62bf34c2702ac762290a01b303db36b30ce0b
--- /dev/null
+++ b/src/gen/java/org/jastadd/ag/ast/CheckSeq.java
@@ -0,0 +1,386 @@
+/* This file was generated with JastAdd2 (http://jastadd.org) version 2.3.5 */
+package org.jastadd.ag.ast;
+import java.util.*;
+/**
+ * @ast node
+ * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\ag.ast:11
+ * @astdecl CheckSeq : Atom ::= <_impl_Rel:java.util.List<Pillar>>;
+ * @production CheckSeq : {@link Atom};
+
+ */
+public class CheckSeq extends Atom implements Cloneable {
+  /**
+   * @aspect ReferenceCreation
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:123
+   */
+  public static CheckSeq createRef(String ref) {
+    Unresolved$CheckSeq unresolvedNode = new Unresolved$CheckSeq();
+    unresolvedNode.setUnresolved$Token(ref);
+    unresolvedNode.setUnresolved$ResolveOpposite(true);
+    return unresolvedNode;
+  }
+  /**
+   * @aspect ReferenceCreation
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:129
+   */
+  public static CheckSeq createRefDirection(String ref) {
+    Unresolved$CheckSeq unresolvedNode = new Unresolved$CheckSeq();
+    unresolvedNode.setUnresolved$Token(ref);
+    unresolvedNode.setUnresolved$ResolveOpposite(false);
+    return unresolvedNode;
+  }
+  /**
+   * @aspect ResolverTrigger
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:269
+   */
+  public void resolveAll() {
+    super.resolveAll();
+  }
+  /**
+   * @aspect RefResolverHelpers
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:601
+   */
+  Unresolved$Node$Interface as$Unresolved() {
+    return null;
+  }
+  /**
+   * @aspect RefResolverHelpers
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:607
+   */
+  boolean is$Unresolved() {
+    return false;
+  }
+  /**
+   * @declaredat ASTNode:1
+   */
+  public CheckSeq() {
+    super();
+  }
+  /**
+   * Initializes the child array to the correct size.
+   * Initializes List and Opt nta children.
+   * @apilevel internal
+   * @ast method
+   * @declaredat ASTNode:10
+   */
+  public void init$Children() {
+    state().enterConstruction();
+    state().exitConstruction();
+  }
+  /**
+   * @declaredat ASTNode:14
+   */
+  @ASTNodeAnnotation.Constructor(
+    name = {"_impl_Rel"},
+    type = {"java.util.List<Pillar>"},
+    kind = {"Token"}
+  )
+  public CheckSeq(java.util.List<Pillar> p0) {
+state().enterConstruction();
+    set_impl_Rel(p0);
+state().exitConstruction();
+  }
+  /** @apilevel low-level 
+   * @declaredat ASTNode:25
+   */
+  protected int numChildren() {
+    
+    state().addHandlerDepTo(numChildren_handler);
+    return 0;
+  }
+  /**
+   * @apilevel internal
+   * @declaredat ASTNode:33
+   */
+  public boolean mayHaveRewrite() {
+    return false;
+  }
+  /** @apilevel internal 
+   * @declaredat ASTNode:37
+   */
+  public void flushAttrCache() {
+  }
+  /** @apilevel internal 
+   * @declaredat ASTNode:40
+   */
+  public void flushCollectionCache() {
+  }
+  /** @apilevel internal 
+   * @declaredat ASTNode:43
+   */
+  public CheckSeq clone() throws CloneNotSupportedException {
+    CheckSeq node = (CheckSeq) super.clone();
+    return node;
+  }
+  /** @apilevel internal 
+   * @declaredat ASTNode:48
+   */
+  public CheckSeq copy() {
+    try {
+      CheckSeq node = (CheckSeq) clone();
+      node.parent = null;
+      if (children != null) {
+        node.children = (ASTNode[]) children.clone();
+      }
+      node.inc_state = inc_CLONED;
+      for (int i = 0; node.children != null && i < node.children.length; i++) {
+        node.children[i] = null;
+      }
+      inc_copyHandlers(node);
+      return node;
+    } catch (CloneNotSupportedException e) {
+      throw new Error("Error: clone not supported for " + getClass().getName());
+    }
+  }
+  /**
+   * Create a deep copy of the AST subtree at this node.
+   * The copy is dangling, i.e. has no parent.
+   * @return dangling copy of the subtree at this node
+   * @apilevel low-level
+   * @deprecated Please use treeCopy or treeCopyNoTransform instead
+   * @declaredat ASTNode:72
+   */
+  @Deprecated
+  public CheckSeq fullCopy() {
+    return treeCopyNoTransform();
+  }
+  /**
+   * Create a deep copy of the AST subtree at this node.
+   * The copy is dangling, i.e. has no parent.
+   * @return dangling copy of the subtree at this node
+   * @apilevel low-level
+   * @declaredat ASTNode:82
+   */
+  public CheckSeq treeCopyNoTransform() {
+    CheckSeq tree = (CheckSeq) copy();
+    if (children != null) {
+      for (int i = 0; i < children.length; ++i) {
+        ASTNode child = (ASTNode) children[i];
+        if (child != null) {
+          child = child.treeCopyNoTransform();
+          tree.children[i] = child;
+          child.parent = tree;
+        }
+      }
+    }
+    return tree;
+  }
+  /**
+   * Create a deep copy of the AST subtree at this node.
+   * The subtree of this node is traversed to trigger rewrites before copy.
+   * The copy is dangling, i.e. has no parent.
+   * @return dangling copy of the subtree at this node
+   * @apilevel low-level
+   * @declaredat ASTNode:103
+   */
+  public CheckSeq treeCopy() {
+    CheckSeq tree = (CheckSeq) copy();
+    if (children != null) {
+      for (int i = 0; i < children.length; ++i) {
+        ASTNode child = (ASTNode) getChild(i);
+        if (child != null) {
+          child = child.treeCopy();
+          tree.children[i] = child;
+          child.parent = tree;
+        }
+      }
+    }
+    return tree;
+  }
+  /** @apilevel internal 
+   * @declaredat ASTNode:118
+   */
+  protected boolean childIsNTA(int index) {
+    return super.childIsNTA(index);
+  }
+  /**
+   * @declaredat ASTNode:121
+   */
+  protected ASTNode$DepGraphNode eval_handler;
+  /**
+   * @declaredat ASTNode:122
+   */
+  protected void inc_copyHandlers(CheckSeq copy) {
+    super.inc_copyHandlers(copy);
+
+        if (eval_handler != null) {
+          copy.eval_handler = ASTNode$DepGraphNode.createAttrHandler(eval_handler, copy);
+        }
+  }
+  /** @apilevel internal 
+   * @declaredat ASTNode:131
+   */
+  public void reactToDependencyChange(String attrID, Object _parameters) {
+    super.reactToDependencyChange(attrID, _parameters);
+  }
+  /**
+   * @declaredat ASTNode:138
+   */
+  private boolean inc_throwAway_visited = false;
+  /** @apilevel internal 
+   * @declaredat ASTNode:140
+   */
+  public void inc_throwAway() {
+  if (inc_throwAway_visited) {
+    return;
+  }
+  inc_throwAway_visited = true;
+  inc_state = inc_GARBAGE;
+  super.inc_throwAway();
+  if (eval_handler != null) {
+    eval_handler.throwAway();
+  }
+  inc_throwAway_visited = false;
+}
+  /**
+   * @declaredat ASTNode:152
+   */
+  private boolean inc_cleanupListeners_visited = false;
+  /**
+   * @declaredat ASTNode:153
+   */
+  public void cleanupListeners() {
+  if (inc_cleanupListeners_visited) {
+    return;
+  }
+  inc_cleanupListeners_visited = true;
+  if (get_impl_Rel_handler != null) {
+    get_impl_Rel_handler.cleanupListeners();
+  }
+  if (eval_handler != null) {
+    eval_handler.cleanupListeners();
+  }
+  super.cleanupListeners();
+  inc_cleanupListeners_visited = false;
+}
+  /**
+   * @declaredat ASTNode:167
+   */
+  private boolean inc_cleanupListenersInTree_visited = false;
+  /**
+   * @declaredat ASTNode:168
+   */
+  public void cleanupListenersInTree() {
+  if (inc_cleanupListenersInTree_visited) {
+    return;
+  }
+  inc_cleanupListenersInTree_visited = true;
+  cleanupListeners();
+  for (int i = 0; children != null && i < children.length; i++) {
+    ASTNode child = children[i];
+    if (child == null) {
+      continue;
+    }
+    child.cleanupListenersInTree();
+  }
+  inc_cleanupListenersInTree_visited = false;
+}
+  /**
+   */
+  protected ASTNode$DepGraphNode get_impl_Rel_handler = ASTNode$DepGraphNode.createAstHandler(this, "get_impl_Rel", null);
+  /**
+   * Replaces the lexeme _impl_Rel.
+   * @param value The new value for the lexeme _impl_Rel.
+   * @apilevel high-level
+   */
+  public CheckSeq set_impl_Rel(java.util.List<Pillar> value) {
+    tokenjava_util_List_Pillar___impl_Rel = value;
+    
+    if (state().disableDeps == 0 && !state().IN_ATTR_STORE_EVAL) {
+      get_impl_Rel_handler.notifyDependencies();
+    
+    
+    
+    
+    }
+    return this;
+  }
+  /**
+   * Retrieves the value for the lexeme _impl_Rel.
+   * @return The value for the lexeme _impl_Rel.
+   * @apilevel high-level
+   */
+  @ASTNodeAnnotation.Token(name="_impl_Rel")
+  public java.util.List<Pillar> get_impl_Rel() {
+    
+    state().addHandlerDepTo(get_impl_Rel_handler);
+    return tokenjava_util_List_Pillar___impl_Rel;
+  }
+  /** @apilevel internal */
+  private void eval_reset() {
+    state().trace().flushAttr(this, "Constraint.eval()", "", eval_value);
+    eval_computed = null;
+  }
+  /** @apilevel internal */
+  protected ASTState.Cycle eval_computed = null;
+
+  /** @apilevel internal */
+  protected boolean eval_value;
+
+  /**
+   * @attribute syn
+   * @aspect Constraints
+   * @declaredat E:\\project\\20211201\\src\\main\\jastadd\\hanoi\\Constraints.jrag:23
+   */
+  @ASTNodeAnnotation.Attribute(kind=ASTNodeAnnotation.Kind.SYN)
+  @ASTNodeAnnotation.Source(aspect="Constraints", declaredAt="E:\\project\\20211201\\src\\main\\jastadd\\hanoi\\Constraints.jrag:3")
+  public boolean eval() {
+    ASTState state = state();
+    
+    if (eval_handler == null) {
+      eval_handler = new ASTNode$DepGraphNode(this, "eval", null, ASTNode.inc_EMPTY) {
+        @Override public void reactToDependencyChange() {
+          {
+            eval_computed = null;
+            eval_handler.notifyDependencies();
+            CheckSeq.this.state().trace().flushIncAttr(CheckSeq.this, "eval", "", "");
+          }
+        }
+      };
+    }
+    state().addHandlerDepTo(eval_handler);
+    
+    
+    
+    
+    
+    if (eval_computed == ASTState.NON_CYCLE || eval_computed == state().cycle()) {
+      state().trace().cacheRead(this, "Constraint.eval()", "", eval_value);
+      return eval_value;
+    }
+    
+    state().enterAttrStoreEval(eval_handler);
+    eval_value = eval_compute();
+    if (state().inCircle()) {
+      eval_computed = state().cycle();
+      state().trace().cacheWrite(this, "Constraint.eval()", "", eval_value);
+    } else {
+      eval_computed = ASTState.NON_CYCLE;
+      state().trace().cacheWrite(this, "Constraint.eval()", "", eval_value);
+    }
+    
+    state().exitAttrStoreEval(eval_handler);
+    
+    
+    
+    
+    
+    
+    return eval_value;
+  }
+  /** @apilevel internal */
+  private boolean eval_compute() {
+          //check if from get(0) to get(1) is the correct sequence,
+          //this constraint is not used while
+          return this.getRels().get(0).moveSeq()==this.getRels().get(1).ID();
+      }
+  /** @apilevel internal */
+  public ASTNode rewriteTo() {
+    return super.rewriteTo();
+  }
+  /** @apilevel internal */
+  public boolean canRewrite() {
+    return false;
+  }
+
+}
diff --git a/src/gen/java/org/jastadd/ag/ast/CheckSize.java b/src/gen/java/org/jastadd/ag/ast/CheckSize.java
new file mode 100644
index 0000000000000000000000000000000000000000..e4a38842c4ec5bf39deda3a45d6d483a84d58768
--- /dev/null
+++ b/src/gen/java/org/jastadd/ag/ast/CheckSize.java
@@ -0,0 +1,390 @@
+/* This file was generated with JastAdd2 (http://jastadd.org) version 2.3.5 */
+package org.jastadd.ag.ast;
+import java.util.*;
+/**
+ * @ast node
+ * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\ag.ast:10
+ * @astdecl CheckSize : Atom ::= <_impl_Rel:java.util.List<Pillar>>;
+ * @production CheckSize : {@link Atom};
+
+ */
+public class CheckSize extends Atom implements Cloneable {
+  /**
+   * @aspect ReferenceCreation
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:111
+   */
+  public static CheckSize createRef(String ref) {
+    Unresolved$CheckSize unresolvedNode = new Unresolved$CheckSize();
+    unresolvedNode.setUnresolved$Token(ref);
+    unresolvedNode.setUnresolved$ResolveOpposite(true);
+    return unresolvedNode;
+  }
+  /**
+   * @aspect ReferenceCreation
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:117
+   */
+  public static CheckSize createRefDirection(String ref) {
+    Unresolved$CheckSize unresolvedNode = new Unresolved$CheckSize();
+    unresolvedNode.setUnresolved$Token(ref);
+    unresolvedNode.setUnresolved$ResolveOpposite(false);
+    return unresolvedNode;
+  }
+  /**
+   * @aspect ResolverTrigger
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:265
+   */
+  public void resolveAll() {
+    super.resolveAll();
+  }
+  /**
+   * @aspect RefResolverHelpers
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:573
+   */
+  Unresolved$Node$Interface as$Unresolved() {
+    return null;
+  }
+  /**
+   * @aspect RefResolverHelpers
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:579
+   */
+  boolean is$Unresolved() {
+    return false;
+  }
+  /**
+   * @declaredat ASTNode:1
+   */
+  public CheckSize() {
+    super();
+  }
+  /**
+   * Initializes the child array to the correct size.
+   * Initializes List and Opt nta children.
+   * @apilevel internal
+   * @ast method
+   * @declaredat ASTNode:10
+   */
+  public void init$Children() {
+    state().enterConstruction();
+    state().exitConstruction();
+  }
+  /**
+   * @declaredat ASTNode:14
+   */
+  @ASTNodeAnnotation.Constructor(
+    name = {"_impl_Rel"},
+    type = {"java.util.List<Pillar>"},
+    kind = {"Token"}
+  )
+  public CheckSize(java.util.List<Pillar> p0) {
+state().enterConstruction();
+    set_impl_Rel(p0);
+state().exitConstruction();
+  }
+  /** @apilevel low-level 
+   * @declaredat ASTNode:25
+   */
+  protected int numChildren() {
+    
+    state().addHandlerDepTo(numChildren_handler);
+    return 0;
+  }
+  /**
+   * @apilevel internal
+   * @declaredat ASTNode:33
+   */
+  public boolean mayHaveRewrite() {
+    return false;
+  }
+  /** @apilevel internal 
+   * @declaredat ASTNode:37
+   */
+  public void flushAttrCache() {
+  }
+  /** @apilevel internal 
+   * @declaredat ASTNode:40
+   */
+  public void flushCollectionCache() {
+  }
+  /** @apilevel internal 
+   * @declaredat ASTNode:43
+   */
+  public CheckSize clone() throws CloneNotSupportedException {
+    CheckSize node = (CheckSize) super.clone();
+    return node;
+  }
+  /** @apilevel internal 
+   * @declaredat ASTNode:48
+   */
+  public CheckSize copy() {
+    try {
+      CheckSize node = (CheckSize) clone();
+      node.parent = null;
+      if (children != null) {
+        node.children = (ASTNode[]) children.clone();
+      }
+      node.inc_state = inc_CLONED;
+      for (int i = 0; node.children != null && i < node.children.length; i++) {
+        node.children[i] = null;
+      }
+      inc_copyHandlers(node);
+      return node;
+    } catch (CloneNotSupportedException e) {
+      throw new Error("Error: clone not supported for " + getClass().getName());
+    }
+  }
+  /**
+   * Create a deep copy of the AST subtree at this node.
+   * The copy is dangling, i.e. has no parent.
+   * @return dangling copy of the subtree at this node
+   * @apilevel low-level
+   * @deprecated Please use treeCopy or treeCopyNoTransform instead
+   * @declaredat ASTNode:72
+   */
+  @Deprecated
+  public CheckSize fullCopy() {
+    return treeCopyNoTransform();
+  }
+  /**
+   * Create a deep copy of the AST subtree at this node.
+   * The copy is dangling, i.e. has no parent.
+   * @return dangling copy of the subtree at this node
+   * @apilevel low-level
+   * @declaredat ASTNode:82
+   */
+  public CheckSize treeCopyNoTransform() {
+    CheckSize tree = (CheckSize) copy();
+    if (children != null) {
+      for (int i = 0; i < children.length; ++i) {
+        ASTNode child = (ASTNode) children[i];
+        if (child != null) {
+          child = child.treeCopyNoTransform();
+          tree.children[i] = child;
+          child.parent = tree;
+        }
+      }
+    }
+    return tree;
+  }
+  /**
+   * Create a deep copy of the AST subtree at this node.
+   * The subtree of this node is traversed to trigger rewrites before copy.
+   * The copy is dangling, i.e. has no parent.
+   * @return dangling copy of the subtree at this node
+   * @apilevel low-level
+   * @declaredat ASTNode:103
+   */
+  public CheckSize treeCopy() {
+    CheckSize tree = (CheckSize) copy();
+    if (children != null) {
+      for (int i = 0; i < children.length; ++i) {
+        ASTNode child = (ASTNode) getChild(i);
+        if (child != null) {
+          child = child.treeCopy();
+          tree.children[i] = child;
+          child.parent = tree;
+        }
+      }
+    }
+    return tree;
+  }
+  /** @apilevel internal 
+   * @declaredat ASTNode:118
+   */
+  protected boolean childIsNTA(int index) {
+    return super.childIsNTA(index);
+  }
+  /**
+   * @declaredat ASTNode:121
+   */
+  protected ASTNode$DepGraphNode eval_handler;
+  /**
+   * @declaredat ASTNode:122
+   */
+  protected void inc_copyHandlers(CheckSize copy) {
+    super.inc_copyHandlers(copy);
+
+        if (eval_handler != null) {
+          copy.eval_handler = ASTNode$DepGraphNode.createAttrHandler(eval_handler, copy);
+        }
+  }
+  /** @apilevel internal 
+   * @declaredat ASTNode:131
+   */
+  public void reactToDependencyChange(String attrID, Object _parameters) {
+    super.reactToDependencyChange(attrID, _parameters);
+  }
+  /**
+   * @declaredat ASTNode:138
+   */
+  private boolean inc_throwAway_visited = false;
+  /** @apilevel internal 
+   * @declaredat ASTNode:140
+   */
+  public void inc_throwAway() {
+  if (inc_throwAway_visited) {
+    return;
+  }
+  inc_throwAway_visited = true;
+  inc_state = inc_GARBAGE;
+  super.inc_throwAway();
+  if (eval_handler != null) {
+    eval_handler.throwAway();
+  }
+  inc_throwAway_visited = false;
+}
+  /**
+   * @declaredat ASTNode:152
+   */
+  private boolean inc_cleanupListeners_visited = false;
+  /**
+   * @declaredat ASTNode:153
+   */
+  public void cleanupListeners() {
+  if (inc_cleanupListeners_visited) {
+    return;
+  }
+  inc_cleanupListeners_visited = true;
+  if (get_impl_Rel_handler != null) {
+    get_impl_Rel_handler.cleanupListeners();
+  }
+  if (eval_handler != null) {
+    eval_handler.cleanupListeners();
+  }
+  super.cleanupListeners();
+  inc_cleanupListeners_visited = false;
+}
+  /**
+   * @declaredat ASTNode:167
+   */
+  private boolean inc_cleanupListenersInTree_visited = false;
+  /**
+   * @declaredat ASTNode:168
+   */
+  public void cleanupListenersInTree() {
+  if (inc_cleanupListenersInTree_visited) {
+    return;
+  }
+  inc_cleanupListenersInTree_visited = true;
+  cleanupListeners();
+  for (int i = 0; children != null && i < children.length; i++) {
+    ASTNode child = children[i];
+    if (child == null) {
+      continue;
+    }
+    child.cleanupListenersInTree();
+  }
+  inc_cleanupListenersInTree_visited = false;
+}
+  /**
+   */
+  protected ASTNode$DepGraphNode get_impl_Rel_handler = ASTNode$DepGraphNode.createAstHandler(this, "get_impl_Rel", null);
+  /**
+   * Replaces the lexeme _impl_Rel.
+   * @param value The new value for the lexeme _impl_Rel.
+   * @apilevel high-level
+   */
+  public CheckSize set_impl_Rel(java.util.List<Pillar> value) {
+    tokenjava_util_List_Pillar___impl_Rel = value;
+    
+    if (state().disableDeps == 0 && !state().IN_ATTR_STORE_EVAL) {
+      get_impl_Rel_handler.notifyDependencies();
+    
+    
+    
+    
+    }
+    return this;
+  }
+  /**
+   * Retrieves the value for the lexeme _impl_Rel.
+   * @return The value for the lexeme _impl_Rel.
+   * @apilevel high-level
+   */
+  @ASTNodeAnnotation.Token(name="_impl_Rel")
+  public java.util.List<Pillar> get_impl_Rel() {
+    
+    state().addHandlerDepTo(get_impl_Rel_handler);
+    return tokenjava_util_List_Pillar___impl_Rel;
+  }
+  /** @apilevel internal */
+  private void eval_reset() {
+    state().trace().flushAttr(this, "Constraint.eval()", "", eval_value);
+    eval_computed = null;
+  }
+  /** @apilevel internal */
+  protected ASTState.Cycle eval_computed = null;
+
+  /** @apilevel internal */
+  protected boolean eval_value;
+
+  /**
+   * @attribute syn
+   * @aspect Constraints
+   * @declaredat E:\\project\\20211201\\src\\main\\jastadd\\hanoi\\Constraints.jrag:14
+   */
+  @ASTNodeAnnotation.Attribute(kind=ASTNodeAnnotation.Kind.SYN)
+  @ASTNodeAnnotation.Source(aspect="Constraints", declaredAt="E:\\project\\20211201\\src\\main\\jastadd\\hanoi\\Constraints.jrag:3")
+  public boolean eval() {
+    ASTState state = state();
+    
+    if (eval_handler == null) {
+      eval_handler = new ASTNode$DepGraphNode(this, "eval", null, ASTNode.inc_EMPTY) {
+        @Override public void reactToDependencyChange() {
+          {
+            eval_computed = null;
+            eval_handler.notifyDependencies();
+            CheckSize.this.state().trace().flushIncAttr(CheckSize.this, "eval", "", "");
+          }
+        }
+      };
+    }
+    state().addHandlerDepTo(eval_handler);
+    
+    
+    
+    
+    
+    if (eval_computed == ASTState.NON_CYCLE || eval_computed == state().cycle()) {
+      state().trace().cacheRead(this, "Constraint.eval()", "", eval_value);
+      return eval_value;
+    }
+    
+    state().enterAttrStoreEval(eval_handler);
+    eval_value = eval_compute();
+    if (state().inCircle()) {
+      eval_computed = state().cycle();
+      state().trace().cacheWrite(this, "Constraint.eval()", "", eval_value);
+    } else {
+      eval_computed = ASTState.NON_CYCLE;
+      state().trace().cacheWrite(this, "Constraint.eval()", "", eval_value);
+    }
+    
+    state().exitAttrStoreEval(eval_handler);
+    
+    
+    
+    
+    
+    
+    return eval_value;
+  }
+  /** @apilevel internal */
+  private boolean eval_compute() {
+          //if the origin pillar and the target pillar are not empty
+          if((this.getRels().get(0).getNumDisk()>0)&&(this.getRels().get(1).getNumDisk()>0)){
+          //compare the size of the top disks on the origin and target pillar,
+          //the disks can be get by getDisk(#Disks-1).
+              return this.getRels().get(0).getDisk(this.getRels().get(0).getNumDisk()-1).smallerThan(this.getRels().get(1).getDisk(this.getRels().get(1).getNumDisk()-1));
+          }
+          return false;
+      }
+  /** @apilevel internal */
+  public ASTNode rewriteTo() {
+    return super.rewriteTo();
+  }
+  /** @apilevel internal */
+  public boolean canRewrite() {
+    return false;
+  }
+
+}
diff --git a/src/gen/java/org/jastadd/ag/ast/Conjunction.java b/src/gen/java/org/jastadd/ag/ast/Conjunction.java
new file mode 100644
index 0000000000000000000000000000000000000000..17d31f6778b69805fd995b85acbdd465218b5ecf
--- /dev/null
+++ b/src/gen/java/org/jastadd/ag/ast/Conjunction.java
@@ -0,0 +1,406 @@
+/* This file was generated with JastAdd2 (http://jastadd.org) version 2.3.5 */
+package org.jastadd.ag.ast;
+import java.util.*;
+/**
+ * @ast node
+ * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\ag.ast:6
+ * @astdecl Conjunction : BinaryConstraint ::= Left:Constraint Right:Constraint;
+ * @production Conjunction : {@link BinaryConstraint};
+
+ */
+public class Conjunction extends BinaryConstraint implements Cloneable {
+  /**
+   * @aspect ReferenceCreation
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:63
+   */
+  public static Conjunction createRef(String ref) {
+    Unresolved$Conjunction unresolvedNode = new Unresolved$Conjunction();
+    unresolvedNode.setUnresolved$Token(ref);
+    unresolvedNode.setUnresolved$ResolveOpposite(true);
+    return unresolvedNode;
+  }
+  /**
+   * @aspect ReferenceCreation
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:69
+   */
+  public static Conjunction createRefDirection(String ref) {
+    Unresolved$Conjunction unresolvedNode = new Unresolved$Conjunction();
+    unresolvedNode.setUnresolved$Token(ref);
+    unresolvedNode.setUnresolved$ResolveOpposite(false);
+    return unresolvedNode;
+  }
+  /**
+   * @aspect ResolverTrigger
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:249
+   */
+  public void resolveAll() {
+    super.resolveAll();
+  }
+  /**
+   * @aspect RefResolverHelpers
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:461
+   */
+  Unresolved$Node$Interface as$Unresolved() {
+    return null;
+  }
+  /**
+   * @aspect RefResolverHelpers
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:467
+   */
+  boolean is$Unresolved() {
+    return false;
+  }
+  /**
+   * @declaredat ASTNode:1
+   */
+  public Conjunction() {
+    super();
+  }
+  /**
+   * Initializes the child array to the correct size.
+   * Initializes List and Opt nta children.
+   * @apilevel internal
+   * @ast method
+   * @declaredat ASTNode:10
+   */
+  public void init$Children() {
+    children = new ASTNode[2];  getChild_handler = new ASTNode$DepGraphNode[children.length];
+    state().enterConstruction();
+    state().exitConstruction();
+  }
+  /**
+   * @declaredat ASTNode:15
+   */
+  @ASTNodeAnnotation.Constructor(
+    name = {"Left", "Right"},
+    type = {"Constraint", "Constraint"},
+    kind = {"Child", "Child"}
+  )
+  public Conjunction(Constraint p0, Constraint p1) {
+state().enterConstruction();
+    setChild(p0, 0);
+    setChild(p1, 1);
+state().exitConstruction();
+  }
+  /** @apilevel low-level 
+   * @declaredat ASTNode:27
+   */
+  protected int numChildren() {
+    
+    state().addHandlerDepTo(numChildren_handler);
+    return 2;
+  }
+  /**
+   * @apilevel internal
+   * @declaredat ASTNode:35
+   */
+  public boolean mayHaveRewrite() {
+    return false;
+  }
+  /** @apilevel internal 
+   * @declaredat ASTNode:39
+   */
+  public void flushAttrCache() {
+  }
+  /** @apilevel internal 
+   * @declaredat ASTNode:42
+   */
+  public void flushCollectionCache() {
+  }
+  /** @apilevel internal 
+   * @declaredat ASTNode:45
+   */
+  public Conjunction clone() throws CloneNotSupportedException {
+    Conjunction node = (Conjunction) super.clone();
+    return node;
+  }
+  /** @apilevel internal 
+   * @declaredat ASTNode:50
+   */
+  public Conjunction copy() {
+    try {
+      Conjunction node = (Conjunction) clone();
+      node.parent = null;
+      if (children != null) {
+        node.children = (ASTNode[]) children.clone();
+      }
+      node.inc_state = inc_CLONED;
+      for (int i = 0; node.children != null && i < node.children.length; i++) {
+        node.children[i] = null;
+      }
+      inc_copyHandlers(node);
+      return node;
+    } catch (CloneNotSupportedException e) {
+      throw new Error("Error: clone not supported for " + getClass().getName());
+    }
+  }
+  /**
+   * Create a deep copy of the AST subtree at this node.
+   * The copy is dangling, i.e. has no parent.
+   * @return dangling copy of the subtree at this node
+   * @apilevel low-level
+   * @deprecated Please use treeCopy or treeCopyNoTransform instead
+   * @declaredat ASTNode:74
+   */
+  @Deprecated
+  public Conjunction fullCopy() {
+    return treeCopyNoTransform();
+  }
+  /**
+   * Create a deep copy of the AST subtree at this node.
+   * The copy is dangling, i.e. has no parent.
+   * @return dangling copy of the subtree at this node
+   * @apilevel low-level
+   * @declaredat ASTNode:84
+   */
+  public Conjunction treeCopyNoTransform() {
+    Conjunction tree = (Conjunction) copy();
+    if (children != null) {
+      for (int i = 0; i < children.length; ++i) {
+        ASTNode child = (ASTNode) children[i];
+        if (child != null) {
+          child = child.treeCopyNoTransform();
+          tree.children[i] = child;
+          child.parent = tree;
+        }
+      }
+    }
+    return tree;
+  }
+  /**
+   * Create a deep copy of the AST subtree at this node.
+   * The subtree of this node is traversed to trigger rewrites before copy.
+   * The copy is dangling, i.e. has no parent.
+   * @return dangling copy of the subtree at this node
+   * @apilevel low-level
+   * @declaredat ASTNode:105
+   */
+  public Conjunction treeCopy() {
+    Conjunction tree = (Conjunction) copy();
+    if (children != null) {
+      for (int i = 0; i < children.length; ++i) {
+        ASTNode child = (ASTNode) getChild(i);
+        if (child != null) {
+          child = child.treeCopy();
+          tree.children[i] = child;
+          child.parent = tree;
+        }
+      }
+    }
+    return tree;
+  }
+  /** @apilevel internal 
+   * @declaredat ASTNode:120
+   */
+  protected boolean childIsNTA(int index) {
+    return super.childIsNTA(index);
+  }
+  /**
+   * @declaredat ASTNode:123
+   */
+  protected ASTNode$DepGraphNode eval_handler;
+  /**
+   * @declaredat ASTNode:124
+   */
+  protected void inc_copyHandlers(Conjunction copy) {
+    super.inc_copyHandlers(copy);
+
+        if (eval_handler != null) {
+          copy.eval_handler = ASTNode$DepGraphNode.createAttrHandler(eval_handler, copy);
+        }
+  }
+  /** @apilevel internal 
+   * @declaredat ASTNode:133
+   */
+  public void reactToDependencyChange(String attrID, Object _parameters) {
+    super.reactToDependencyChange(attrID, _parameters);
+  }
+  /**
+   * @declaredat ASTNode:140
+   */
+  private boolean inc_throwAway_visited = false;
+  /** @apilevel internal 
+   * @declaredat ASTNode:142
+   */
+  public void inc_throwAway() {
+  if (inc_throwAway_visited) {
+    return;
+  }
+  inc_throwAway_visited = true;
+  inc_state = inc_GARBAGE;
+  super.inc_throwAway();
+  if (eval_handler != null) {
+    eval_handler.throwAway();
+  }
+  inc_throwAway_visited = false;
+}
+  /**
+   * @declaredat ASTNode:154
+   */
+  private boolean inc_cleanupListeners_visited = false;
+  /**
+   * @declaredat ASTNode:155
+   */
+  public void cleanupListeners() {
+  if (inc_cleanupListeners_visited) {
+    return;
+  }
+  inc_cleanupListeners_visited = true;
+  if (eval_handler != null) {
+    eval_handler.cleanupListeners();
+  }
+  super.cleanupListeners();
+  inc_cleanupListeners_visited = false;
+}
+  /**
+   * @declaredat ASTNode:166
+   */
+  private boolean inc_cleanupListenersInTree_visited = false;
+  /**
+   * @declaredat ASTNode:167
+   */
+  public void cleanupListenersInTree() {
+  if (inc_cleanupListenersInTree_visited) {
+    return;
+  }
+  inc_cleanupListenersInTree_visited = true;
+  cleanupListeners();
+  for (int i = 0; children != null && i < children.length; i++) {
+    ASTNode child = children[i];
+    if (child == null) {
+      continue;
+    }
+    child.cleanupListenersInTree();
+  }
+  inc_cleanupListenersInTree_visited = false;
+}
+  /**
+   * Replaces the Left child.
+   * @param node The new node to replace the Left child.
+   * @apilevel high-level
+   */
+  public Conjunction setLeft(Constraint node) {
+    setChild(node, 0);
+    return this;
+  }
+  /**
+   * Retrieves the Left child.
+   * @return The current node used as the Left child.
+   * @apilevel high-level
+   */
+  @ASTNodeAnnotation.Child(name="Left")
+  public Constraint getLeft() {
+    return (Constraint) getChild(0);
+  }
+  /**
+   * Retrieves the Left child.
+   * <p><em>This method does not invoke AST transformations.</em></p>
+   * @return The current node used as the Left child.
+   * @apilevel low-level
+   */
+  public Constraint getLeftNoTransform() {
+    return (Constraint) getChildNoTransform(0);
+  }
+  /**
+   * Replaces the Right child.
+   * @param node The new node to replace the Right child.
+   * @apilevel high-level
+   */
+  public Conjunction setRight(Constraint node) {
+    setChild(node, 1);
+    return this;
+  }
+  /**
+   * Retrieves the Right child.
+   * @return The current node used as the Right child.
+   * @apilevel high-level
+   */
+  @ASTNodeAnnotation.Child(name="Right")
+  public Constraint getRight() {
+    return (Constraint) getChild(1);
+  }
+  /**
+   * Retrieves the Right child.
+   * <p><em>This method does not invoke AST transformations.</em></p>
+   * @return The current node used as the Right child.
+   * @apilevel low-level
+   */
+  public Constraint getRightNoTransform() {
+    return (Constraint) getChildNoTransform(1);
+  }
+  /** @apilevel internal */
+  private void eval_reset() {
+    state().trace().flushAttr(this, "Constraint.eval()", "", eval_value);
+    eval_computed = null;
+  }
+  /** @apilevel internal */
+  protected ASTState.Cycle eval_computed = null;
+
+  /** @apilevel internal */
+  protected boolean eval_value;
+
+  /**
+   * @attribute syn
+   * @aspect Constraints
+   * @declaredat E:\\project\\20211201\\src\\main\\jastadd\\hanoi\\Constraints.jrag:4
+   */
+  @ASTNodeAnnotation.Attribute(kind=ASTNodeAnnotation.Kind.SYN)
+  @ASTNodeAnnotation.Source(aspect="Constraints", declaredAt="E:\\project\\20211201\\src\\main\\jastadd\\hanoi\\Constraints.jrag:3")
+  public boolean eval() {
+    ASTState state = state();
+    
+    if (eval_handler == null) {
+      eval_handler = new ASTNode$DepGraphNode(this, "eval", null, ASTNode.inc_EMPTY) {
+        @Override public void reactToDependencyChange() {
+          {
+            eval_computed = null;
+            eval_handler.notifyDependencies();
+            Conjunction.this.state().trace().flushIncAttr(Conjunction.this, "eval", "", "");
+          }
+        }
+      };
+    }
+    state().addHandlerDepTo(eval_handler);
+    
+    
+    
+    
+    
+    if (eval_computed == ASTState.NON_CYCLE || eval_computed == state().cycle()) {
+      state().trace().cacheRead(this, "Constraint.eval()", "", eval_value);
+      return eval_value;
+    }
+    
+    state().enterAttrStoreEval(eval_handler);
+    eval_value = eval_compute();
+    if (state().inCircle()) {
+      eval_computed = state().cycle();
+      state().trace().cacheWrite(this, "Constraint.eval()", "", eval_value);
+    } else {
+      eval_computed = ASTState.NON_CYCLE;
+      state().trace().cacheWrite(this, "Constraint.eval()", "", eval_value);
+    }
+    
+    state().exitAttrStoreEval(eval_handler);
+    
+    
+    
+    
+    
+    
+    return eval_value;
+  }
+  /** @apilevel internal */
+  private boolean eval_compute() {
+          return this.getLeft().eval() && this.getRight().eval();
+      }
+  /** @apilevel internal */
+  public ASTNode rewriteTo() {
+    return super.rewriteTo();
+  }
+  /** @apilevel internal */
+  public boolean canRewrite() {
+    return false;
+  }
+
+}
diff --git a/src/gen/java/org/jastadd/ag/ast/Constraint.java b/src/gen/java/org/jastadd/ag/ast/Constraint.java
new file mode 100644
index 0000000000000000000000000000000000000000..c26d6a7f8920d95751dea421ef595db8d29ba86c
--- /dev/null
+++ b/src/gen/java/org/jastadd/ag/ast/Constraint.java
@@ -0,0 +1,225 @@
+/* This file was generated with JastAdd2 (http://jastadd.org) version 2.3.5 */
+package org.jastadd.ag.ast;
+import java.util.*;
+/**
+ * @ast node
+ * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\ag.ast:2
+ * @astdecl Constraint : ASTNode;
+ * @production Constraint : {@link ASTNode};
+
+ */
+public abstract class Constraint extends ASTNode<ASTNode> implements Cloneable {
+  /**
+   * @aspect ReferenceCreation
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:15
+   */
+  public static Constraint createRef(String ref) {
+    Unresolved$CheckSize unresolvedNode = new Unresolved$CheckSize();
+    unresolvedNode.setUnresolved$Token(ref);
+    unresolvedNode.setUnresolved$ResolveOpposite(true);
+    return unresolvedNode;
+  }
+  /**
+   * @aspect ReferenceCreation
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:21
+   */
+  public static Constraint createRefDirection(String ref) {
+    Unresolved$CheckSize unresolvedNode = new Unresolved$CheckSize();
+    unresolvedNode.setUnresolved$Token(ref);
+    unresolvedNode.setUnresolved$ResolveOpposite(false);
+    return unresolvedNode;
+  }
+  /**
+   * @aspect ResolverTrigger
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:232
+   */
+  public void resolveAll() {
+    super.resolveAll();
+  }
+  /**
+   * @aspect RefResolverHelpers
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:349
+   */
+  Unresolved$Node$Interface as$Unresolved() {
+    return null;
+  }
+  /**
+   * @aspect RefResolverHelpers
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:355
+   */
+  boolean is$Unresolved() {
+    return false;
+  }
+  /**
+   * @declaredat ASTNode:1
+   */
+  public Constraint() {
+    super();
+  }
+  /**
+   * Initializes the child array to the correct size.
+   * Initializes List and Opt nta children.
+   * @apilevel internal
+   * @ast method
+   * @declaredat ASTNode:10
+   */
+  public void init$Children() {
+    state().enterConstruction();
+    state().exitConstruction();
+  }
+  /** @apilevel low-level 
+   * @declaredat ASTNode:15
+   */
+  protected int numChildren() {
+    
+    state().addHandlerDepTo(numChildren_handler);
+    return 0;
+  }
+  /**
+   * @apilevel internal
+   * @declaredat ASTNode:23
+   */
+  public boolean mayHaveRewrite() {
+    return false;
+  }
+  /** @apilevel internal 
+   * @declaredat ASTNode:27
+   */
+  public void flushAttrCache() {
+  }
+  /** @apilevel internal 
+   * @declaredat ASTNode:30
+   */
+  public void flushCollectionCache() {
+  }
+  /** @apilevel internal 
+   * @declaredat ASTNode:33
+   */
+  public Constraint clone() throws CloneNotSupportedException {
+    Constraint node = (Constraint) super.clone();
+    return node;
+  }
+  /**
+   * Create a deep copy of the AST subtree at this node.
+   * The copy is dangling, i.e. has no parent.
+   * @return dangling copy of the subtree at this node
+   * @apilevel low-level
+   * @deprecated Please use treeCopy or treeCopyNoTransform instead
+   * @declaredat ASTNode:44
+   */
+  @Deprecated
+  public abstract Constraint fullCopy();
+  /**
+   * Create a deep copy of the AST subtree at this node.
+   * The copy is dangling, i.e. has no parent.
+   * @return dangling copy of the subtree at this node
+   * @apilevel low-level
+   * @declaredat ASTNode:52
+   */
+  public abstract Constraint treeCopyNoTransform();
+  /**
+   * Create a deep copy of the AST subtree at this node.
+   * The subtree of this node is traversed to trigger rewrites before copy.
+   * The copy is dangling, i.e. has no parent.
+   * @return dangling copy of the subtree at this node
+   * @apilevel low-level
+   * @declaredat ASTNode:60
+   */
+  public abstract Constraint treeCopy();
+  /** @apilevel internal 
+   * @declaredat ASTNode:62
+   */
+  protected boolean childIsNTA(int index) {
+    return super.childIsNTA(index);
+  }
+  /**
+   * @declaredat ASTNode:65
+   */
+  protected ASTNode$DepGraphNode eval_handler;
+  /**
+   * @declaredat ASTNode:66
+   */
+  protected void inc_copyHandlers(Constraint copy) {
+    super.inc_copyHandlers(copy);
+
+        if (eval_handler != null) {
+          copy.eval_handler = ASTNode$DepGraphNode.createAttrHandler(eval_handler, copy);
+        }
+  }
+  /** @apilevel internal 
+   * @declaredat ASTNode:75
+   */
+  public void reactToDependencyChange(String attrID, Object _parameters) {
+    super.reactToDependencyChange(attrID, _parameters);
+  }
+  /**
+   * @declaredat ASTNode:82
+   */
+  private boolean inc_throwAway_visited = false;
+  /** @apilevel internal 
+   * @declaredat ASTNode:84
+   */
+  public void inc_throwAway() {
+  if (inc_throwAway_visited) {
+    return;
+  }
+  inc_throwAway_visited = true;
+  inc_state = inc_GARBAGE;
+  super.inc_throwAway();
+  inc_throwAway_visited = false;
+}
+  /**
+   * @declaredat ASTNode:93
+   */
+  private boolean inc_cleanupListeners_visited = false;
+  /**
+   * @declaredat ASTNode:94
+   */
+  public void cleanupListeners() {
+  if (inc_cleanupListeners_visited) {
+    return;
+  }
+  inc_cleanupListeners_visited = true;
+  super.cleanupListeners();
+  inc_cleanupListeners_visited = false;
+}
+  /**
+   * @declaredat ASTNode:102
+   */
+  private boolean inc_cleanupListenersInTree_visited = false;
+  /**
+   * @declaredat ASTNode:103
+   */
+  public void cleanupListenersInTree() {
+  if (inc_cleanupListenersInTree_visited) {
+    return;
+  }
+  inc_cleanupListenersInTree_visited = true;
+  cleanupListeners();
+  for (int i = 0; children != null && i < children.length; i++) {
+    ASTNode child = children[i];
+    if (child == null) {
+      continue;
+    }
+    child.cleanupListenersInTree();
+  }
+  inc_cleanupListenersInTree_visited = false;
+}
+  /**
+   * @attribute syn
+   * @aspect Constraints
+   * @declaredat E:\\project\\20211201\\src\\main\\jastadd\\hanoi\\Constraints.jrag:3
+   */
+  @ASTNodeAnnotation.Attribute(kind=ASTNodeAnnotation.Kind.SYN)
+  @ASTNodeAnnotation.Source(aspect="Constraints", declaredAt="E:\\project\\20211201\\src\\main\\jastadd\\hanoi\\Constraints.jrag:3")
+  public abstract boolean eval();
+  /** @apilevel internal */
+  public ASTNode rewriteTo() {
+    return super.rewriteTo();
+  }
+  /** @apilevel internal */
+  public boolean canRewrite() {
+    return false;
+  }
+
+}
diff --git a/src/gen/java/org/jastadd/ag/ast/Disjunction.java b/src/gen/java/org/jastadd/ag/ast/Disjunction.java
new file mode 100644
index 0000000000000000000000000000000000000000..5e9aea0496809f6e986e17f39c0bb1ca3dc3b7a7
--- /dev/null
+++ b/src/gen/java/org/jastadd/ag/ast/Disjunction.java
@@ -0,0 +1,406 @@
+/* This file was generated with JastAdd2 (http://jastadd.org) version 2.3.5 */
+package org.jastadd.ag.ast;
+import java.util.*;
+/**
+ * @ast node
+ * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\ag.ast:7
+ * @astdecl Disjunction : BinaryConstraint ::= Left:Constraint Right:Constraint;
+ * @production Disjunction : {@link BinaryConstraint};
+
+ */
+public class Disjunction extends BinaryConstraint implements Cloneable {
+  /**
+   * @aspect ReferenceCreation
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:75
+   */
+  public static Disjunction createRef(String ref) {
+    Unresolved$Disjunction unresolvedNode = new Unresolved$Disjunction();
+    unresolvedNode.setUnresolved$Token(ref);
+    unresolvedNode.setUnresolved$ResolveOpposite(true);
+    return unresolvedNode;
+  }
+  /**
+   * @aspect ReferenceCreation
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:81
+   */
+  public static Disjunction createRefDirection(String ref) {
+    Unresolved$Disjunction unresolvedNode = new Unresolved$Disjunction();
+    unresolvedNode.setUnresolved$Token(ref);
+    unresolvedNode.setUnresolved$ResolveOpposite(false);
+    return unresolvedNode;
+  }
+  /**
+   * @aspect ResolverTrigger
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:253
+   */
+  public void resolveAll() {
+    super.resolveAll();
+  }
+  /**
+   * @aspect RefResolverHelpers
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:489
+   */
+  Unresolved$Node$Interface as$Unresolved() {
+    return null;
+  }
+  /**
+   * @aspect RefResolverHelpers
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:495
+   */
+  boolean is$Unresolved() {
+    return false;
+  }
+  /**
+   * @declaredat ASTNode:1
+   */
+  public Disjunction() {
+    super();
+  }
+  /**
+   * Initializes the child array to the correct size.
+   * Initializes List and Opt nta children.
+   * @apilevel internal
+   * @ast method
+   * @declaredat ASTNode:10
+   */
+  public void init$Children() {
+    children = new ASTNode[2];  getChild_handler = new ASTNode$DepGraphNode[children.length];
+    state().enterConstruction();
+    state().exitConstruction();
+  }
+  /**
+   * @declaredat ASTNode:15
+   */
+  @ASTNodeAnnotation.Constructor(
+    name = {"Left", "Right"},
+    type = {"Constraint", "Constraint"},
+    kind = {"Child", "Child"}
+  )
+  public Disjunction(Constraint p0, Constraint p1) {
+state().enterConstruction();
+    setChild(p0, 0);
+    setChild(p1, 1);
+state().exitConstruction();
+  }
+  /** @apilevel low-level 
+   * @declaredat ASTNode:27
+   */
+  protected int numChildren() {
+    
+    state().addHandlerDepTo(numChildren_handler);
+    return 2;
+  }
+  /**
+   * @apilevel internal
+   * @declaredat ASTNode:35
+   */
+  public boolean mayHaveRewrite() {
+    return false;
+  }
+  /** @apilevel internal 
+   * @declaredat ASTNode:39
+   */
+  public void flushAttrCache() {
+  }
+  /** @apilevel internal 
+   * @declaredat ASTNode:42
+   */
+  public void flushCollectionCache() {
+  }
+  /** @apilevel internal 
+   * @declaredat ASTNode:45
+   */
+  public Disjunction clone() throws CloneNotSupportedException {
+    Disjunction node = (Disjunction) super.clone();
+    return node;
+  }
+  /** @apilevel internal 
+   * @declaredat ASTNode:50
+   */
+  public Disjunction copy() {
+    try {
+      Disjunction node = (Disjunction) clone();
+      node.parent = null;
+      if (children != null) {
+        node.children = (ASTNode[]) children.clone();
+      }
+      node.inc_state = inc_CLONED;
+      for (int i = 0; node.children != null && i < node.children.length; i++) {
+        node.children[i] = null;
+      }
+      inc_copyHandlers(node);
+      return node;
+    } catch (CloneNotSupportedException e) {
+      throw new Error("Error: clone not supported for " + getClass().getName());
+    }
+  }
+  /**
+   * Create a deep copy of the AST subtree at this node.
+   * The copy is dangling, i.e. has no parent.
+   * @return dangling copy of the subtree at this node
+   * @apilevel low-level
+   * @deprecated Please use treeCopy or treeCopyNoTransform instead
+   * @declaredat ASTNode:74
+   */
+  @Deprecated
+  public Disjunction fullCopy() {
+    return treeCopyNoTransform();
+  }
+  /**
+   * Create a deep copy of the AST subtree at this node.
+   * The copy is dangling, i.e. has no parent.
+   * @return dangling copy of the subtree at this node
+   * @apilevel low-level
+   * @declaredat ASTNode:84
+   */
+  public Disjunction treeCopyNoTransform() {
+    Disjunction tree = (Disjunction) copy();
+    if (children != null) {
+      for (int i = 0; i < children.length; ++i) {
+        ASTNode child = (ASTNode) children[i];
+        if (child != null) {
+          child = child.treeCopyNoTransform();
+          tree.children[i] = child;
+          child.parent = tree;
+        }
+      }
+    }
+    return tree;
+  }
+  /**
+   * Create a deep copy of the AST subtree at this node.
+   * The subtree of this node is traversed to trigger rewrites before copy.
+   * The copy is dangling, i.e. has no parent.
+   * @return dangling copy of the subtree at this node
+   * @apilevel low-level
+   * @declaredat ASTNode:105
+   */
+  public Disjunction treeCopy() {
+    Disjunction tree = (Disjunction) copy();
+    if (children != null) {
+      for (int i = 0; i < children.length; ++i) {
+        ASTNode child = (ASTNode) getChild(i);
+        if (child != null) {
+          child = child.treeCopy();
+          tree.children[i] = child;
+          child.parent = tree;
+        }
+      }
+    }
+    return tree;
+  }
+  /** @apilevel internal 
+   * @declaredat ASTNode:120
+   */
+  protected boolean childIsNTA(int index) {
+    return super.childIsNTA(index);
+  }
+  /**
+   * @declaredat ASTNode:123
+   */
+  protected ASTNode$DepGraphNode eval_handler;
+  /**
+   * @declaredat ASTNode:124
+   */
+  protected void inc_copyHandlers(Disjunction copy) {
+    super.inc_copyHandlers(copy);
+
+        if (eval_handler != null) {
+          copy.eval_handler = ASTNode$DepGraphNode.createAttrHandler(eval_handler, copy);
+        }
+  }
+  /** @apilevel internal 
+   * @declaredat ASTNode:133
+   */
+  public void reactToDependencyChange(String attrID, Object _parameters) {
+    super.reactToDependencyChange(attrID, _parameters);
+  }
+  /**
+   * @declaredat ASTNode:140
+   */
+  private boolean inc_throwAway_visited = false;
+  /** @apilevel internal 
+   * @declaredat ASTNode:142
+   */
+  public void inc_throwAway() {
+  if (inc_throwAway_visited) {
+    return;
+  }
+  inc_throwAway_visited = true;
+  inc_state = inc_GARBAGE;
+  super.inc_throwAway();
+  if (eval_handler != null) {
+    eval_handler.throwAway();
+  }
+  inc_throwAway_visited = false;
+}
+  /**
+   * @declaredat ASTNode:154
+   */
+  private boolean inc_cleanupListeners_visited = false;
+  /**
+   * @declaredat ASTNode:155
+   */
+  public void cleanupListeners() {
+  if (inc_cleanupListeners_visited) {
+    return;
+  }
+  inc_cleanupListeners_visited = true;
+  if (eval_handler != null) {
+    eval_handler.cleanupListeners();
+  }
+  super.cleanupListeners();
+  inc_cleanupListeners_visited = false;
+}
+  /**
+   * @declaredat ASTNode:166
+   */
+  private boolean inc_cleanupListenersInTree_visited = false;
+  /**
+   * @declaredat ASTNode:167
+   */
+  public void cleanupListenersInTree() {
+  if (inc_cleanupListenersInTree_visited) {
+    return;
+  }
+  inc_cleanupListenersInTree_visited = true;
+  cleanupListeners();
+  for (int i = 0; children != null && i < children.length; i++) {
+    ASTNode child = children[i];
+    if (child == null) {
+      continue;
+    }
+    child.cleanupListenersInTree();
+  }
+  inc_cleanupListenersInTree_visited = false;
+}
+  /**
+   * Replaces the Left child.
+   * @param node The new node to replace the Left child.
+   * @apilevel high-level
+   */
+  public Disjunction setLeft(Constraint node) {
+    setChild(node, 0);
+    return this;
+  }
+  /**
+   * Retrieves the Left child.
+   * @return The current node used as the Left child.
+   * @apilevel high-level
+   */
+  @ASTNodeAnnotation.Child(name="Left")
+  public Constraint getLeft() {
+    return (Constraint) getChild(0);
+  }
+  /**
+   * Retrieves the Left child.
+   * <p><em>This method does not invoke AST transformations.</em></p>
+   * @return The current node used as the Left child.
+   * @apilevel low-level
+   */
+  public Constraint getLeftNoTransform() {
+    return (Constraint) getChildNoTransform(0);
+  }
+  /**
+   * Replaces the Right child.
+   * @param node The new node to replace the Right child.
+   * @apilevel high-level
+   */
+  public Disjunction setRight(Constraint node) {
+    setChild(node, 1);
+    return this;
+  }
+  /**
+   * Retrieves the Right child.
+   * @return The current node used as the Right child.
+   * @apilevel high-level
+   */
+  @ASTNodeAnnotation.Child(name="Right")
+  public Constraint getRight() {
+    return (Constraint) getChild(1);
+  }
+  /**
+   * Retrieves the Right child.
+   * <p><em>This method does not invoke AST transformations.</em></p>
+   * @return The current node used as the Right child.
+   * @apilevel low-level
+   */
+  public Constraint getRightNoTransform() {
+    return (Constraint) getChildNoTransform(1);
+  }
+  /** @apilevel internal */
+  private void eval_reset() {
+    state().trace().flushAttr(this, "Constraint.eval()", "", eval_value);
+    eval_computed = null;
+  }
+  /** @apilevel internal */
+  protected ASTState.Cycle eval_computed = null;
+
+  /** @apilevel internal */
+  protected boolean eval_value;
+
+  /**
+   * @attribute syn
+   * @aspect Constraints
+   * @declaredat E:\\project\\20211201\\src\\main\\jastadd\\hanoi\\Constraints.jrag:7
+   */
+  @ASTNodeAnnotation.Attribute(kind=ASTNodeAnnotation.Kind.SYN)
+  @ASTNodeAnnotation.Source(aspect="Constraints", declaredAt="E:\\project\\20211201\\src\\main\\jastadd\\hanoi\\Constraints.jrag:3")
+  public boolean eval() {
+    ASTState state = state();
+    
+    if (eval_handler == null) {
+      eval_handler = new ASTNode$DepGraphNode(this, "eval", null, ASTNode.inc_EMPTY) {
+        @Override public void reactToDependencyChange() {
+          {
+            eval_computed = null;
+            eval_handler.notifyDependencies();
+            Disjunction.this.state().trace().flushIncAttr(Disjunction.this, "eval", "", "");
+          }
+        }
+      };
+    }
+    state().addHandlerDepTo(eval_handler);
+    
+    
+    
+    
+    
+    if (eval_computed == ASTState.NON_CYCLE || eval_computed == state().cycle()) {
+      state().trace().cacheRead(this, "Constraint.eval()", "", eval_value);
+      return eval_value;
+    }
+    
+    state().enterAttrStoreEval(eval_handler);
+    eval_value = eval_compute();
+    if (state().inCircle()) {
+      eval_computed = state().cycle();
+      state().trace().cacheWrite(this, "Constraint.eval()", "", eval_value);
+    } else {
+      eval_computed = ASTState.NON_CYCLE;
+      state().trace().cacheWrite(this, "Constraint.eval()", "", eval_value);
+    }
+    
+    state().exitAttrStoreEval(eval_handler);
+    
+    
+    
+    
+    
+    
+    return eval_value;
+  }
+  /** @apilevel internal */
+  private boolean eval_compute() {
+          return this.getLeft().eval() || this.getRight().eval();
+      }
+  /** @apilevel internal */
+  public ASTNode rewriteTo() {
+    return super.rewriteTo();
+  }
+  /** @apilevel internal */
+  public boolean canRewrite() {
+    return false;
+  }
+
+}
diff --git a/src/gen/java/org/jastadd/ag/ast/Disk.java b/src/gen/java/org/jastadd/ag/ast/Disk.java
new file mode 100644
index 0000000000000000000000000000000000000000..62622cb03e0b7662261c0dec153f9cbf342c18df
--- /dev/null
+++ b/src/gen/java/org/jastadd/ag/ast/Disk.java
@@ -0,0 +1,405 @@
+/* This file was generated with JastAdd2 (http://jastadd.org) version 2.3.5 */
+package org.jastadd.ag.ast;
+import java.util.*;
+/**
+ * @ast node
+ * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\ag.ast:16
+ * @astdecl Disk : ASTNode ::= <Size:int>;
+ * @production Disk : {@link ASTNode} ::= <span class="component">&lt;Size:{@link int}&gt;</span>;
+
+ */
+public class Disk extends ASTNode<ASTNode> implements Cloneable {
+  /**
+   * @aspect ReferenceCreation
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:183
+   */
+  public static Disk createRef(String ref) {
+    Unresolved$Disk unresolvedNode = new Unresolved$Disk();
+    unresolvedNode.setUnresolved$Token(ref);
+    unresolvedNode.setUnresolved$ResolveOpposite(true);
+    return unresolvedNode;
+  }
+  /**
+   * @aspect ReferenceCreation
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:189
+   */
+  public static Disk createRefDirection(String ref) {
+    Unresolved$Disk unresolvedNode = new Unresolved$Disk();
+    unresolvedNode.setUnresolved$Token(ref);
+    unresolvedNode.setUnresolved$ResolveOpposite(false);
+    return unresolvedNode;
+  }
+  /**
+   * @aspect ResolverTrigger
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:289
+   */
+  public void resolveAll() {
+    super.resolveAll();
+  }
+  /**
+   * @aspect RefResolverHelpers
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:741
+   */
+  Unresolved$Node$Interface as$Unresolved() {
+    return null;
+  }
+  /**
+   * @aspect RefResolverHelpers
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:747
+   */
+  boolean is$Unresolved() {
+    return false;
+  }
+  /**
+   * @declaredat ASTNode:1
+   */
+  public Disk() {
+    super();
+  }
+  /**
+   * Initializes the child array to the correct size.
+   * Initializes List and Opt nta children.
+   * @apilevel internal
+   * @ast method
+   * @declaredat ASTNode:10
+   */
+  public void init$Children() {
+    state().enterConstruction();
+    state().exitConstruction();
+  }
+  /**
+   * @declaredat ASTNode:14
+   */
+  @ASTNodeAnnotation.Constructor(
+    name = {"Size"},
+    type = {"int"},
+    kind = {"Token"}
+  )
+  public Disk(int p0) {
+state().enterConstruction();
+    setSize(p0);
+state().exitConstruction();
+  }
+  /** @apilevel low-level 
+   * @declaredat ASTNode:25
+   */
+  protected int numChildren() {
+    
+    state().addHandlerDepTo(numChildren_handler);
+    return 0;
+  }
+  /**
+   * @apilevel internal
+   * @declaredat ASTNode:33
+   */
+  public boolean mayHaveRewrite() {
+    return false;
+  }
+  /** @apilevel internal 
+   * @declaredat ASTNode:37
+   */
+  public void flushAttrCache() {
+  }
+  /** @apilevel internal 
+   * @declaredat ASTNode:40
+   */
+  public void flushCollectionCache() {
+  }
+  /** @apilevel internal 
+   * @declaredat ASTNode:43
+   */
+  public Disk clone() throws CloneNotSupportedException {
+    Disk node = (Disk) super.clone();
+    return node;
+  }
+  /** @apilevel internal 
+   * @declaredat ASTNode:48
+   */
+  public Disk copy() {
+    try {
+      Disk node = (Disk) clone();
+      node.parent = null;
+      if (children != null) {
+        node.children = (ASTNode[]) children.clone();
+      }
+      node.inc_state = inc_CLONED;
+      for (int i = 0; node.children != null && i < node.children.length; i++) {
+        node.children[i] = null;
+      }
+      inc_copyHandlers(node);
+      return node;
+    } catch (CloneNotSupportedException e) {
+      throw new Error("Error: clone not supported for " + getClass().getName());
+    }
+  }
+  /**
+   * Create a deep copy of the AST subtree at this node.
+   * The copy is dangling, i.e. has no parent.
+   * @return dangling copy of the subtree at this node
+   * @apilevel low-level
+   * @deprecated Please use treeCopy or treeCopyNoTransform instead
+   * @declaredat ASTNode:72
+   */
+  @Deprecated
+  public Disk fullCopy() {
+    return treeCopyNoTransform();
+  }
+  /**
+   * Create a deep copy of the AST subtree at this node.
+   * The copy is dangling, i.e. has no parent.
+   * @return dangling copy of the subtree at this node
+   * @apilevel low-level
+   * @declaredat ASTNode:82
+   */
+  public Disk treeCopyNoTransform() {
+    Disk tree = (Disk) copy();
+    if (children != null) {
+      for (int i = 0; i < children.length; ++i) {
+        ASTNode child = (ASTNode) children[i];
+        if (child != null) {
+          child = child.treeCopyNoTransform();
+          tree.children[i] = child;
+          child.parent = tree;
+        }
+      }
+    }
+    return tree;
+  }
+  /**
+   * Create a deep copy of the AST subtree at this node.
+   * The subtree of this node is traversed to trigger rewrites before copy.
+   * The copy is dangling, i.e. has no parent.
+   * @return dangling copy of the subtree at this node
+   * @apilevel low-level
+   * @declaredat ASTNode:103
+   */
+  public Disk treeCopy() {
+    Disk tree = (Disk) copy();
+    if (children != null) {
+      for (int i = 0; i < children.length; ++i) {
+        ASTNode child = (ASTNode) getChild(i);
+        if (child != null) {
+          child = child.treeCopy();
+          tree.children[i] = child;
+          child.parent = tree;
+        }
+      }
+    }
+    return tree;
+  }
+  /** @apilevel internal 
+   * @declaredat ASTNode:118
+   */
+  protected boolean childIsNTA(int index) {
+    return super.childIsNTA(index);
+  }
+  /**
+   * @declaredat ASTNode:121
+   */
+  protected java.util.Map smallerThan_Disk_handler = new java.util.HashMap(4);
+  /**
+   * @declaredat ASTNode:122
+   */
+  protected void inc_copyHandlers(Disk copy) {
+    super.inc_copyHandlers(copy);
+
+        if (getSize_handler != null) {
+          copy.getSize_handler = ASTNode$DepGraphNode.createAstHandler(getSize_handler, copy);
+        }
+        if (smallerThan_Disk_handler != null) {
+          copy.smallerThan_Disk_handler = new java.util.HashMap(4);
+        }
+  }
+  /** @apilevel internal 
+   * @declaredat ASTNode:134
+   */
+  public void reactToDependencyChange(String attrID, Object _parameters) {
+    super.reactToDependencyChange(attrID, _parameters);
+  }
+  /**
+   * @declaredat ASTNode:141
+   */
+  private boolean inc_throwAway_visited = false;
+  /** @apilevel internal 
+   * @declaredat ASTNode:143
+   */
+  public void inc_throwAway() {
+  if (inc_throwAway_visited) {
+    return;
+  }
+  inc_throwAway_visited = true;
+  inc_state = inc_GARBAGE;
+  super.inc_throwAway();
+  if (getSize_handler != null) {
+    getSize_handler.throwAway();
+  }
+  for (java.util.Iterator itr = smallerThan_Disk_handler.values().iterator(); itr.hasNext();) {
+    ASTNode$DepGraphNode handler = (ASTNode$DepGraphNode) itr.next();
+    handler.throwAway();
+  }
+  inc_throwAway_visited = false;
+}
+  /**
+   * @declaredat ASTNode:159
+   */
+  private boolean inc_cleanupListeners_visited = false;
+  /**
+   * @declaredat ASTNode:160
+   */
+  public void cleanupListeners() {
+  if (inc_cleanupListeners_visited) {
+    return;
+  }
+  inc_cleanupListeners_visited = true;
+  if (getSize_handler != null) {
+    getSize_handler.cleanupListeners();
+  }
+  for (java.util.Iterator itr = smallerThan_Disk_handler.values().iterator(); itr.hasNext();) {
+    ASTNode$DepGraphNode handler = (ASTNode$DepGraphNode)itr.next();
+    handler.cleanupListeners();
+  }
+  super.cleanupListeners();
+  inc_cleanupListeners_visited = false;
+}
+  /**
+   * @declaredat ASTNode:175
+   */
+  private boolean inc_cleanupListenersInTree_visited = false;
+  /**
+   * @declaredat ASTNode:176
+   */
+  public void cleanupListenersInTree() {
+  if (inc_cleanupListenersInTree_visited) {
+    return;
+  }
+  inc_cleanupListenersInTree_visited = true;
+  cleanupListeners();
+  for (int i = 0; children != null && i < children.length; i++) {
+    ASTNode child = children[i];
+    if (child == null) {
+      continue;
+    }
+    child.cleanupListenersInTree();
+  }
+  inc_cleanupListenersInTree_visited = false;
+}
+  /**
+   */
+  protected ASTNode$DepGraphNode getSize_handler = ASTNode$DepGraphNode.createAstHandler(this, "getSize", null);
+  /**
+   * Replaces the lexeme Size.
+   * @param value The new value for the lexeme Size.
+   * @apilevel high-level
+   */
+  public Disk setSize(int value) {
+    tokenint_Size = value;
+    
+    if (state().disableDeps == 0 && !state().IN_ATTR_STORE_EVAL) {
+      getSize_handler.notifyDependencies();
+    
+    
+    
+    
+    }
+    return this;
+  }
+  /** @apilevel internal 
+   */
+  protected int tokenint_Size;
+  /**
+   * Retrieves the value for the lexeme Size.
+   * @return The value for the lexeme Size.
+   * @apilevel high-level
+   */
+  @ASTNodeAnnotation.Token(name="Size")
+  public int getSize() {
+    
+    state().addHandlerDepTo(getSize_handler);
+    return tokenint_Size;
+  }
+  /** @apilevel internal */
+  private void smallerThan_Disk_reset() {
+    state().trace().flushAttr(this, "Disk.smallerThan(Disk)", "", smallerThan_Disk_values);
+    smallerThan_Disk_computed = null;
+    smallerThan_Disk_values = null;
+  }
+  /** @apilevel internal */
+  protected java.util.Map smallerThan_Disk_values;
+  /** @apilevel internal */
+  protected java.util.Map smallerThan_Disk_computed;
+  /**
+   * @attribute syn
+   * @aspect CanMove
+   * @declaredat E:\\project\\20211201\\src\\main\\jastadd\\hanoi\\CanMove.jrag:2
+   */
+  @ASTNodeAnnotation.Attribute(kind=ASTNodeAnnotation.Kind.SYN)
+  @ASTNodeAnnotation.Source(aspect="CanMove", declaredAt="E:\\project\\20211201\\src\\main\\jastadd\\hanoi\\CanMove.jrag:2")
+  public boolean smallerThan(Disk D) {
+    Object _parameters = D;
+    if (smallerThan_Disk_computed == null) smallerThan_Disk_computed = new java.util.HashMap(4);
+    if (smallerThan_Disk_values == null) smallerThan_Disk_values = new java.util.HashMap(4);
+    ASTState state = state();
+    
+    if (!smallerThan_Disk_handler.containsKey(_parameters)) {
+      smallerThan_Disk_handler.put(_parameters, new ASTNode$DepGraphNode(this, "smallerThan_Disk", _parameters, ASTNode.inc_EMPTY) {
+        @Override public void reactToDependencyChange() {
+          if (smallerThan_Disk_values != null && smallerThan_Disk_values.containsKey(fParams)) {
+            smallerThan_Disk_values.remove(fParams);
+            ASTNode$DepGraphNode handler = (ASTNode$DepGraphNode) smallerThan_Disk_handler.remove(fParams);
+            handler.throwAway();
+            handler.notifyDependencies();
+          }
+        }
+      });
+    }
+    state().addHandlerDepTo((ASTNode$DepGraphNode)smallerThan_Disk_handler.get(_parameters));
+    
+    
+    
+    
+    
+    if (smallerThan_Disk_values.containsKey(_parameters)
+        && smallerThan_Disk_computed.containsKey(_parameters)
+        && (smallerThan_Disk_computed.get(_parameters) == ASTState.NON_CYCLE || smallerThan_Disk_computed.get(_parameters) == state().cycle())) {
+      state().trace().cacheRead(this, "Disk.smallerThan(Disk)", _parameters, smallerThan_Disk_values.get(_parameters));
+      return (Boolean) smallerThan_Disk_values.get(_parameters);
+    }
+    
+    state().enterAttrStoreEval((ASTNode$DepGraphNode)smallerThan_Disk_handler.get(_parameters));
+    boolean smallerThan_Disk_value = smallerThan_compute(D);
+    if (state().inCircle()) {
+      smallerThan_Disk_values.put(_parameters, smallerThan_Disk_value);
+      smallerThan_Disk_computed.put(_parameters, state().cycle());
+      state().trace().cacheWrite(this, "Disk.smallerThan(Disk)", _parameters, smallerThan_Disk_value);
+    } else {
+      smallerThan_Disk_values.put(_parameters, smallerThan_Disk_value);
+      smallerThan_Disk_computed.put(_parameters, ASTState.NON_CYCLE);
+      state().trace().cacheWrite(this, "Disk.smallerThan(Disk)", _parameters, smallerThan_Disk_value);
+    }
+    
+    state().exitAttrStoreEval((ASTNode$DepGraphNode)smallerThan_Disk_handler.get(_parameters));
+    
+    
+    
+    
+    
+    
+    return smallerThan_Disk_value;
+  }
+  /** @apilevel internal */
+  private boolean smallerThan_compute(Disk D) {
+      if(this.getSize() < D.getSize()){
+        return true;
+      }
+        return false;
+    }
+  /** @apilevel internal */
+  public ASTNode rewriteTo() {
+    return super.rewriteTo();
+  }
+  /** @apilevel internal */
+  public boolean canRewrite() {
+    return false;
+  }
+
+}
diff --git a/src/gen/java/org/jastadd/ag/ast/Hanoi.java b/src/gen/java/org/jastadd/ag/ast/Hanoi.java
new file mode 100644
index 0000000000000000000000000000000000000000..64ae7b018d95e6338c584ad473fa78fb937734b3
--- /dev/null
+++ b/src/gen/java/org/jastadd/ag/ast/Hanoi.java
@@ -0,0 +1,581 @@
+/* This file was generated with JastAdd2 (http://jastadd.org) version 2.3.5 */
+package org.jastadd.ag.ast;
+import java.util.*;
+/**
+ * @ast node
+ * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\ag.ast:15
+ * @astdecl Hanoi : ASTNode ::= Pillar* <AmountD:int>;
+ * @production Hanoi : {@link ASTNode} ::= <span class="component">{@link Pillar}*</span> <span class="component">&lt;AmountD:{@link int}&gt;</span>;
+
+ */
+public class Hanoi extends ASTNode<ASTNode> implements Cloneable {
+  /**
+   * @aspect Initialisation
+   * @declaredat E:\\project\\20211201\\src\\main\\jastadd\\hanoi\\Initialisation.jrag:6
+   */
+  public boolean Initialisation(int sumDisk)
+  {
+    this.setAmountD(sumDisk);
+    int sumPillar = 3;
+    Disk[] D = new Disk[sumDisk];
+    Pillar[] P = new Pillar[3];
+    for(int i = 0; i < 3; i++)
+    {
+      P[i] = new Pillar();
+    }
+    for(int i = 0; i < sumDisk; i++)
+    {
+      D[i] = new Disk(i + 1);
+      System.out.println("Disk: " + i + "; size: " + D[i].getSize());
+    }
+    for(int i = sumDisk - 1; i >= 0; i--)
+    {
+      P[0].addDisk(D[i]);
+    }
+    for(int i = 0; i < 3; i++)
+    {
+      this.addPillar(P[i]);
+    } 
+    this.present();
+    return true;
+  }
+  /**
+   * @aspect Initialisation
+   * @declaredat E:\\project\\20211201\\src\\main\\jastadd\\hanoi\\Initialisation.jrag:33
+   */
+  public boolean present()
+  {
+    int sumPillar = 3;
+    for(int i = 0; i < 3; i++)
+    {
+      if(this.getPillar(i).getNumDisk() > 0){
+        System.out.println("Pillar_" + i + " has Disks:");
+        for(int j = 0; j < this.getAmountD(); j++){
+          int temp = this.getPillar(i).getDisk(j).getSize();
+          System.out.println("Disk: " + (temp - 1) + "; Size: " + temp + ".");
+        }
+      }
+      else{
+        System.out.println("Pillar_" + i + " is empty.");
+      }
+    }
+    return true; 
+  }
+  /**
+   * @aspect Initialisation
+   * @declaredat E:\\project\\20211201\\src\\main\\jastadd\\hanoi\\Initialisation.jrag:51
+   */
+  public boolean play(){
+    boolean turn = true;//parity check
+    int count = 1;//count the turn
+    int location = 0;//log which pillar the smallest disk is on at the moment
+    while(true){
+      //check if all the disks are moved to the last pillar
+      if(this.getPillar(2).getNumDisk() == this.getAmountD()){
+        break;
+      }
+      for(int i = 0; i < 3; i++){
+        for(int j = 0; j < 3; j++){
+          if(this.getPillar(2).getNumDisk() == this.getAmountD()){
+            break;
+          }
+          if(i==j){
+            continue;
+          }else{
+            Root root = new Root();
+            int temp = root.check(this.getPillar(i), this.getPillar(j), turn);
+            if(temp == 1){//odd turn valid move
+              if(this.getPillar(i).moveSeq()==j){//origin != target
+                this.getPillar(i).moveTo(this.getPillar(j));
+                System.out.println("Disk_" + (this.getPillar(j).getDisk(this.getPillar(j).getNumDisk()-1).getSize()-1) + ": " + i + "->" + j);
+                System.out.println("Round: " + count++);
+                location = j;//log where the smallest disk is
+                turn = !turn;//change turn
+                break;
+              }
+            }else if(temp == 2 && !(location == i)){//even turn and valid move
+              //Origin != location since we don't move the smallest disk in even turns
+              this.getPillar(i).moveTo(this.getPillar(j));
+              System.out.println("Disk_" + (this.getPillar(j).getDisk(this.getPillar(j).getNumDisk()-1).getSize()-1) + ": " + i + "->" + j);
+              System.out.println("Round: " + count++);
+              turn = !turn;
+              break;
+            }
+          }
+        }
+      }
+    }
+    return true;
+  }
+  /**
+   * @aspect ReferenceCreation
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:171
+   */
+  public static Hanoi createRef(String ref) {
+    Unresolved$Hanoi unresolvedNode = new Unresolved$Hanoi();
+    unresolvedNode.setUnresolved$Token(ref);
+    unresolvedNode.setUnresolved$ResolveOpposite(true);
+    return unresolvedNode;
+  }
+  /**
+   * @aspect ReferenceCreation
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:177
+   */
+  public static Hanoi createRefDirection(String ref) {
+    Unresolved$Hanoi unresolvedNode = new Unresolved$Hanoi();
+    unresolvedNode.setUnresolved$Token(ref);
+    unresolvedNode.setUnresolved$ResolveOpposite(false);
+    return unresolvedNode;
+  }
+  /**
+   * @aspect ResolverTrigger
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:285
+   */
+  public void resolveAll() {
+    super.resolveAll();
+  }
+  /**
+   * @aspect RefResolverHelpers
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:713
+   */
+  Unresolved$Node$Interface as$Unresolved() {
+    return null;
+  }
+  /**
+   * @aspect RefResolverHelpers
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:719
+   */
+  boolean is$Unresolved() {
+    return false;
+  }
+  /**
+   * @declaredat ASTNode:1
+   */
+  public Hanoi() {
+    super();
+  }
+  /**
+   * Initializes the child array to the correct size.
+   * Initializes List and Opt nta children.
+   * @apilevel internal
+   * @ast method
+   * @declaredat ASTNode:10
+   */
+  public void init$Children() {
+    children = new ASTNode[1];  getChild_handler = new ASTNode$DepGraphNode[children.length];
+    state().enterConstruction();
+    setChild(new JastAddList(), 0);
+    state().exitConstruction();
+  }
+  /**
+   * @declaredat ASTNode:16
+   */
+  @ASTNodeAnnotation.Constructor(
+    name = {"Pillar", "AmountD"},
+    type = {"JastAddList<Pillar>", "int"},
+    kind = {"List", "Token"}
+  )
+  public Hanoi(JastAddList<Pillar> p0, int p1) {
+state().enterConstruction();
+    setChild(p0, 0);
+    setAmountD(p1);
+state().exitConstruction();
+  }
+  /** @apilevel low-level 
+   * @declaredat ASTNode:28
+   */
+  protected int numChildren() {
+    
+    state().addHandlerDepTo(numChildren_handler);
+    return 1;
+  }
+  /**
+   * @apilevel internal
+   * @declaredat ASTNode:36
+   */
+  public boolean mayHaveRewrite() {
+    return false;
+  }
+  /** @apilevel internal 
+   * @declaredat ASTNode:40
+   */
+  public void flushAttrCache() {
+  }
+  /** @apilevel internal 
+   * @declaredat ASTNode:43
+   */
+  public void flushCollectionCache() {
+  }
+  /** @apilevel internal 
+   * @declaredat ASTNode:46
+   */
+  public Hanoi clone() throws CloneNotSupportedException {
+    Hanoi node = (Hanoi) super.clone();
+    return node;
+  }
+  /** @apilevel internal 
+   * @declaredat ASTNode:51
+   */
+  public Hanoi copy() {
+    try {
+      Hanoi node = (Hanoi) clone();
+      node.parent = null;
+      if (children != null) {
+        node.children = (ASTNode[]) children.clone();
+      }
+      node.inc_state = inc_CLONED;
+      for (int i = 0; node.children != null && i < node.children.length; i++) {
+        node.children[i] = null;
+      }
+      inc_copyHandlers(node);
+      return node;
+    } catch (CloneNotSupportedException e) {
+      throw new Error("Error: clone not supported for " + getClass().getName());
+    }
+  }
+  /**
+   * Create a deep copy of the AST subtree at this node.
+   * The copy is dangling, i.e. has no parent.
+   * @return dangling copy of the subtree at this node
+   * @apilevel low-level
+   * @deprecated Please use treeCopy or treeCopyNoTransform instead
+   * @declaredat ASTNode:75
+   */
+  @Deprecated
+  public Hanoi fullCopy() {
+    return treeCopyNoTransform();
+  }
+  /**
+   * Create a deep copy of the AST subtree at this node.
+   * The copy is dangling, i.e. has no parent.
+   * @return dangling copy of the subtree at this node
+   * @apilevel low-level
+   * @declaredat ASTNode:85
+   */
+  public Hanoi treeCopyNoTransform() {
+    Hanoi tree = (Hanoi) copy();
+    if (children != null) {
+      for (int i = 0; i < children.length; ++i) {
+        ASTNode child = (ASTNode) children[i];
+        if (child != null) {
+          child = child.treeCopyNoTransform();
+          tree.children[i] = child;
+          child.parent = tree;
+        }
+      }
+    }
+    return tree;
+  }
+  /**
+   * Create a deep copy of the AST subtree at this node.
+   * The subtree of this node is traversed to trigger rewrites before copy.
+   * The copy is dangling, i.e. has no parent.
+   * @return dangling copy of the subtree at this node
+   * @apilevel low-level
+   * @declaredat ASTNode:106
+   */
+  public Hanoi treeCopy() {
+    Hanoi tree = (Hanoi) copy();
+    if (children != null) {
+      for (int i = 0; i < children.length; ++i) {
+        ASTNode child = (ASTNode) getChild(i);
+        if (child != null) {
+          child = child.treeCopy();
+          tree.children[i] = child;
+          child.parent = tree;
+        }
+      }
+    }
+    return tree;
+  }
+  /** @apilevel internal 
+   * @declaredat ASTNode:121
+   */
+  protected boolean childIsNTA(int index) {
+    return super.childIsNTA(index);
+  }
+  /**
+   * @declaredat ASTNode:124
+   */
+  protected void inc_copyHandlers(Hanoi copy) {
+    super.inc_copyHandlers(copy);
+
+        if (getAmountD_handler != null) {
+          copy.getAmountD_handler = ASTNode$DepGraphNode.createAstHandler(getAmountD_handler, copy);
+        }
+  }
+  /** @apilevel internal 
+   * @declaredat ASTNode:133
+   */
+  public void reactToDependencyChange(String attrID, Object _parameters) {
+    super.reactToDependencyChange(attrID, _parameters);
+  }
+  /**
+   * @declaredat ASTNode:140
+   */
+  private boolean inc_throwAway_visited = false;
+  /** @apilevel internal 
+   * @declaredat ASTNode:142
+   */
+  public void inc_throwAway() {
+  if (inc_throwAway_visited) {
+    return;
+  }
+  inc_throwAway_visited = true;
+  inc_state = inc_GARBAGE;
+  super.inc_throwAway();
+  if (getAmountD_handler != null) {
+    getAmountD_handler.throwAway();
+  }
+  inc_throwAway_visited = false;
+}
+  /**
+   * @declaredat ASTNode:154
+   */
+  private boolean inc_cleanupListeners_visited = false;
+  /**
+   * @declaredat ASTNode:155
+   */
+  public void cleanupListeners() {
+  if (inc_cleanupListeners_visited) {
+    return;
+  }
+  inc_cleanupListeners_visited = true;
+  if (getAmountD_handler != null) {
+    getAmountD_handler.cleanupListeners();
+  }
+  super.cleanupListeners();
+  inc_cleanupListeners_visited = false;
+}
+  /**
+   * @declaredat ASTNode:166
+   */
+  private boolean inc_cleanupListenersInTree_visited = false;
+  /**
+   * @declaredat ASTNode:167
+   */
+  public void cleanupListenersInTree() {
+  if (inc_cleanupListenersInTree_visited) {
+    return;
+  }
+  inc_cleanupListenersInTree_visited = true;
+  cleanupListeners();
+  for (int i = 0; children != null && i < children.length; i++) {
+    ASTNode child = children[i];
+    if (child == null) {
+      continue;
+    }
+    child.cleanupListenersInTree();
+  }
+  inc_cleanupListenersInTree_visited = false;
+}
+  /**
+   * Replaces the Pillar list.
+   * @param list The new list node to be used as the Pillar list.
+   * @apilevel high-level
+   */
+  public Hanoi setPillarList(JastAddList<Pillar> list) {
+    setChild(list, 0);
+    return this;
+  }
+  /**
+   * Retrieves the number of children in the Pillar list.
+   * @return Number of children in the Pillar list.
+   * @apilevel high-level
+   */
+  public int getNumPillar() {
+    return getPillarList().getNumChild();
+  }
+  /**
+   * Retrieves the number of children in the Pillar list.
+   * Calling this method will not trigger rewrites.
+   * @return Number of children in the Pillar list.
+   * @apilevel low-level
+   */
+  public int getNumPillarNoTransform() {
+    return getPillarListNoTransform().getNumChildNoTransform();
+  }
+  /**
+   * Retrieves the element at index {@code i} in the Pillar list.
+   * @param i Index of the element to return.
+   * @return The element at position {@code i} in the Pillar list.
+   * @apilevel high-level
+   */
+  public Pillar getPillar(int i) {
+    return (Pillar) getPillarList().getChild(i);
+  }
+  /**
+   * Check whether the Pillar list has any children.
+   * @return {@code true} if it has at least one child, {@code false} otherwise.
+   * @apilevel high-level
+   */
+  public boolean hasPillar() {
+    return getPillarList().getNumChild() != 0;
+  }
+  /**
+   * Append an element to the Pillar list.
+   * @param node The element to append to the Pillar list.
+   * @apilevel high-level
+   */
+  public Hanoi addPillar(Pillar node) {
+    JastAddList<Pillar> list = (parent == null) ? getPillarListNoTransform() : getPillarList();
+    list.addChild(node);
+    return this;
+  }
+  /** @apilevel low-level 
+   */
+  public Hanoi addPillarNoTransform(Pillar node) {
+    JastAddList<Pillar> list = getPillarListNoTransform();
+    list.addChild(node);
+    return this;
+  }
+  /**
+   * Replaces the Pillar list element at index {@code i} with the new node {@code node}.
+   * @param node The new node to replace the old list element.
+   * @param i The list index of the node to be replaced.
+   * @apilevel high-level
+   */
+  public Hanoi setPillar(Pillar node, int i) {
+    JastAddList<Pillar> list = getPillarList();
+    list.setChild(node, i);
+    return this;
+  }
+  /**
+   * Retrieves the Pillar list.
+   * @return The node representing the Pillar list.
+   * @apilevel high-level
+   */
+  @ASTNodeAnnotation.ListChild(name="Pillar")
+  public JastAddList<Pillar> getPillarList() {
+    JastAddList<Pillar> list = (JastAddList<Pillar>) getChild(0);
+    return list;
+  }
+  /**
+   * Retrieves the Pillar list.
+   * <p><em>This method does not invoke AST transformations.</em></p>
+   * @return The node representing the Pillar list.
+   * @apilevel low-level
+   */
+  public JastAddList<Pillar> getPillarListNoTransform() {
+    return (JastAddList<Pillar>) getChildNoTransform(0);
+  }
+  /**
+   * @return the element at index {@code i} in the Pillar list without
+   * triggering rewrites.
+   */
+  public Pillar getPillarNoTransform(int i) {
+    return (Pillar) getPillarListNoTransform().getChildNoTransform(i);
+  }
+  /**
+   * Retrieves the Pillar list.
+   * @return The node representing the Pillar list.
+   * @apilevel high-level
+   */
+  public JastAddList<Pillar> getPillars() {
+    return getPillarList();
+  }
+  /**
+   * Retrieves the Pillar list.
+   * <p><em>This method does not invoke AST transformations.</em></p>
+   * @return The node representing the Pillar list.
+   * @apilevel low-level
+   */
+  public JastAddList<Pillar> getPillarsNoTransform() {
+    return getPillarListNoTransform();
+  }
+  /**
+   */
+  protected ASTNode$DepGraphNode getAmountD_handler = ASTNode$DepGraphNode.createAstHandler(this, "getAmountD", null);
+  /**
+   * Replaces the lexeme AmountD.
+   * @param value The new value for the lexeme AmountD.
+   * @apilevel high-level
+   */
+  public Hanoi setAmountD(int value) {
+    tokenint_AmountD = value;
+    
+    if (state().disableDeps == 0 && !state().IN_ATTR_STORE_EVAL) {
+      getAmountD_handler.notifyDependencies();
+    
+    
+    
+    
+    }
+    return this;
+  }
+  /** @apilevel internal 
+   */
+  protected int tokenint_AmountD;
+  /**
+   * Retrieves the value for the lexeme AmountD.
+   * @return The value for the lexeme AmountD.
+   * @apilevel high-level
+   */
+  @ASTNodeAnnotation.Token(name="AmountD")
+  public int getAmountD() {
+    
+    state().addHandlerDepTo(getAmountD_handler);
+    return tokenint_AmountD;
+  }
+  /**
+   * @declaredat E:\\project\\20211201\\src\\main\\jastadd\\hanoi\\CanMove.jrag:12
+   * @apilevel internal
+   */
+  public int Define_moveSeq(ASTNode _callerNode, ASTNode _childNode) {
+    if (_callerNode == getPillarListNoTransform()) {
+      // @declaredat E:\\project\\20211201\\src\\main\\jastadd\\hanoi\\CanMove.jrag:13
+      int i = _callerNode.getIndexOfChild(_childNode);
+      {
+          if(this.getAmountD()%2 == 1){
+            return (i+2)%3;
+          }else{
+            return (i+1)%3;
+          }
+        }
+    }
+    else {
+      return getParent().Define_moveSeq(this, _callerNode);
+    }
+  }
+  /**
+   * @declaredat E:\\project\\20211201\\src\\main\\jastadd\\hanoi\\CanMove.jrag:12
+   * @apilevel internal
+   * @return {@code true} if this node has an equation for the inherited attribute moveSeq
+   */
+  protected boolean canDefine_moveSeq(ASTNode _callerNode, ASTNode _childNode) {
+    return true;
+  }
+  /**
+   * @declaredat E:\\project\\20211201\\src\\main\\jastadd\\hanoi\\CanMove.jrag:20
+   * @apilevel internal
+   */
+  public int Define_ID(ASTNode _callerNode, ASTNode _childNode) {
+    if (_callerNode == getPillarListNoTransform()) {
+      // @declaredat E:\\project\\20211201\\src\\main\\jastadd\\hanoi\\CanMove.jrag:21
+      int i = _callerNode.getIndexOfChild(_childNode);
+      {
+          return i;
+        }
+    }
+    else {
+      return getParent().Define_ID(this, _callerNode);
+    }
+  }
+  /**
+   * @declaredat E:\\project\\20211201\\src\\main\\jastadd\\hanoi\\CanMove.jrag:20
+   * @apilevel internal
+   * @return {@code true} if this node has an equation for the inherited attribute ID
+   */
+  protected boolean canDefine_ID(ASTNode _callerNode, ASTNode _childNode) {
+    return true;
+  }
+  /** @apilevel internal */
+  public ASTNode rewriteTo() {
+    return super.rewriteTo();
+  }
+  /** @apilevel internal */
+  public boolean canRewrite() {
+    return false;
+  }
+
+}
diff --git a/src/gen/java/org/jastadd/ag/ast/Implication.java b/src/gen/java/org/jastadd/ag/ast/Implication.java
new file mode 100644
index 0000000000000000000000000000000000000000..80c8ebae25e1de4de4a247ea6d1d870021879144
--- /dev/null
+++ b/src/gen/java/org/jastadd/ag/ast/Implication.java
@@ -0,0 +1,406 @@
+/* This file was generated with JastAdd2 (http://jastadd.org) version 2.3.5 */
+package org.jastadd.ag.ast;
+import java.util.*;
+/**
+ * @ast node
+ * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\ag.ast:8
+ * @astdecl Implication : BinaryConstraint ::= Left:Constraint Right:Constraint;
+ * @production Implication : {@link BinaryConstraint};
+
+ */
+public class Implication extends BinaryConstraint implements Cloneable {
+  /**
+   * @aspect ReferenceCreation
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:87
+   */
+  public static Implication createRef(String ref) {
+    Unresolved$Implication unresolvedNode = new Unresolved$Implication();
+    unresolvedNode.setUnresolved$Token(ref);
+    unresolvedNode.setUnresolved$ResolveOpposite(true);
+    return unresolvedNode;
+  }
+  /**
+   * @aspect ReferenceCreation
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:93
+   */
+  public static Implication createRefDirection(String ref) {
+    Unresolved$Implication unresolvedNode = new Unresolved$Implication();
+    unresolvedNode.setUnresolved$Token(ref);
+    unresolvedNode.setUnresolved$ResolveOpposite(false);
+    return unresolvedNode;
+  }
+  /**
+   * @aspect ResolverTrigger
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:257
+   */
+  public void resolveAll() {
+    super.resolveAll();
+  }
+  /**
+   * @aspect RefResolverHelpers
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:517
+   */
+  Unresolved$Node$Interface as$Unresolved() {
+    return null;
+  }
+  /**
+   * @aspect RefResolverHelpers
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:523
+   */
+  boolean is$Unresolved() {
+    return false;
+  }
+  /**
+   * @declaredat ASTNode:1
+   */
+  public Implication() {
+    super();
+  }
+  /**
+   * Initializes the child array to the correct size.
+   * Initializes List and Opt nta children.
+   * @apilevel internal
+   * @ast method
+   * @declaredat ASTNode:10
+   */
+  public void init$Children() {
+    children = new ASTNode[2];  getChild_handler = new ASTNode$DepGraphNode[children.length];
+    state().enterConstruction();
+    state().exitConstruction();
+  }
+  /**
+   * @declaredat ASTNode:15
+   */
+  @ASTNodeAnnotation.Constructor(
+    name = {"Left", "Right"},
+    type = {"Constraint", "Constraint"},
+    kind = {"Child", "Child"}
+  )
+  public Implication(Constraint p0, Constraint p1) {
+state().enterConstruction();
+    setChild(p0, 0);
+    setChild(p1, 1);
+state().exitConstruction();
+  }
+  /** @apilevel low-level 
+   * @declaredat ASTNode:27
+   */
+  protected int numChildren() {
+    
+    state().addHandlerDepTo(numChildren_handler);
+    return 2;
+  }
+  /**
+   * @apilevel internal
+   * @declaredat ASTNode:35
+   */
+  public boolean mayHaveRewrite() {
+    return false;
+  }
+  /** @apilevel internal 
+   * @declaredat ASTNode:39
+   */
+  public void flushAttrCache() {
+  }
+  /** @apilevel internal 
+   * @declaredat ASTNode:42
+   */
+  public void flushCollectionCache() {
+  }
+  /** @apilevel internal 
+   * @declaredat ASTNode:45
+   */
+  public Implication clone() throws CloneNotSupportedException {
+    Implication node = (Implication) super.clone();
+    return node;
+  }
+  /** @apilevel internal 
+   * @declaredat ASTNode:50
+   */
+  public Implication copy() {
+    try {
+      Implication node = (Implication) clone();
+      node.parent = null;
+      if (children != null) {
+        node.children = (ASTNode[]) children.clone();
+      }
+      node.inc_state = inc_CLONED;
+      for (int i = 0; node.children != null && i < node.children.length; i++) {
+        node.children[i] = null;
+      }
+      inc_copyHandlers(node);
+      return node;
+    } catch (CloneNotSupportedException e) {
+      throw new Error("Error: clone not supported for " + getClass().getName());
+    }
+  }
+  /**
+   * Create a deep copy of the AST subtree at this node.
+   * The copy is dangling, i.e. has no parent.
+   * @return dangling copy of the subtree at this node
+   * @apilevel low-level
+   * @deprecated Please use treeCopy or treeCopyNoTransform instead
+   * @declaredat ASTNode:74
+   */
+  @Deprecated
+  public Implication fullCopy() {
+    return treeCopyNoTransform();
+  }
+  /**
+   * Create a deep copy of the AST subtree at this node.
+   * The copy is dangling, i.e. has no parent.
+   * @return dangling copy of the subtree at this node
+   * @apilevel low-level
+   * @declaredat ASTNode:84
+   */
+  public Implication treeCopyNoTransform() {
+    Implication tree = (Implication) copy();
+    if (children != null) {
+      for (int i = 0; i < children.length; ++i) {
+        ASTNode child = (ASTNode) children[i];
+        if (child != null) {
+          child = child.treeCopyNoTransform();
+          tree.children[i] = child;
+          child.parent = tree;
+        }
+      }
+    }
+    return tree;
+  }
+  /**
+   * Create a deep copy of the AST subtree at this node.
+   * The subtree of this node is traversed to trigger rewrites before copy.
+   * The copy is dangling, i.e. has no parent.
+   * @return dangling copy of the subtree at this node
+   * @apilevel low-level
+   * @declaredat ASTNode:105
+   */
+  public Implication treeCopy() {
+    Implication tree = (Implication) copy();
+    if (children != null) {
+      for (int i = 0; i < children.length; ++i) {
+        ASTNode child = (ASTNode) getChild(i);
+        if (child != null) {
+          child = child.treeCopy();
+          tree.children[i] = child;
+          child.parent = tree;
+        }
+      }
+    }
+    return tree;
+  }
+  /** @apilevel internal 
+   * @declaredat ASTNode:120
+   */
+  protected boolean childIsNTA(int index) {
+    return super.childIsNTA(index);
+  }
+  /**
+   * @declaredat ASTNode:123
+   */
+  protected ASTNode$DepGraphNode eval_handler;
+  /**
+   * @declaredat ASTNode:124
+   */
+  protected void inc_copyHandlers(Implication copy) {
+    super.inc_copyHandlers(copy);
+
+        if (eval_handler != null) {
+          copy.eval_handler = ASTNode$DepGraphNode.createAttrHandler(eval_handler, copy);
+        }
+  }
+  /** @apilevel internal 
+   * @declaredat ASTNode:133
+   */
+  public void reactToDependencyChange(String attrID, Object _parameters) {
+    super.reactToDependencyChange(attrID, _parameters);
+  }
+  /**
+   * @declaredat ASTNode:140
+   */
+  private boolean inc_throwAway_visited = false;
+  /** @apilevel internal 
+   * @declaredat ASTNode:142
+   */
+  public void inc_throwAway() {
+  if (inc_throwAway_visited) {
+    return;
+  }
+  inc_throwAway_visited = true;
+  inc_state = inc_GARBAGE;
+  super.inc_throwAway();
+  if (eval_handler != null) {
+    eval_handler.throwAway();
+  }
+  inc_throwAway_visited = false;
+}
+  /**
+   * @declaredat ASTNode:154
+   */
+  private boolean inc_cleanupListeners_visited = false;
+  /**
+   * @declaredat ASTNode:155
+   */
+  public void cleanupListeners() {
+  if (inc_cleanupListeners_visited) {
+    return;
+  }
+  inc_cleanupListeners_visited = true;
+  if (eval_handler != null) {
+    eval_handler.cleanupListeners();
+  }
+  super.cleanupListeners();
+  inc_cleanupListeners_visited = false;
+}
+  /**
+   * @declaredat ASTNode:166
+   */
+  private boolean inc_cleanupListenersInTree_visited = false;
+  /**
+   * @declaredat ASTNode:167
+   */
+  public void cleanupListenersInTree() {
+  if (inc_cleanupListenersInTree_visited) {
+    return;
+  }
+  inc_cleanupListenersInTree_visited = true;
+  cleanupListeners();
+  for (int i = 0; children != null && i < children.length; i++) {
+    ASTNode child = children[i];
+    if (child == null) {
+      continue;
+    }
+    child.cleanupListenersInTree();
+  }
+  inc_cleanupListenersInTree_visited = false;
+}
+  /**
+   * Replaces the Left child.
+   * @param node The new node to replace the Left child.
+   * @apilevel high-level
+   */
+  public Implication setLeft(Constraint node) {
+    setChild(node, 0);
+    return this;
+  }
+  /**
+   * Retrieves the Left child.
+   * @return The current node used as the Left child.
+   * @apilevel high-level
+   */
+  @ASTNodeAnnotation.Child(name="Left")
+  public Constraint getLeft() {
+    return (Constraint) getChild(0);
+  }
+  /**
+   * Retrieves the Left child.
+   * <p><em>This method does not invoke AST transformations.</em></p>
+   * @return The current node used as the Left child.
+   * @apilevel low-level
+   */
+  public Constraint getLeftNoTransform() {
+    return (Constraint) getChildNoTransform(0);
+  }
+  /**
+   * Replaces the Right child.
+   * @param node The new node to replace the Right child.
+   * @apilevel high-level
+   */
+  public Implication setRight(Constraint node) {
+    setChild(node, 1);
+    return this;
+  }
+  /**
+   * Retrieves the Right child.
+   * @return The current node used as the Right child.
+   * @apilevel high-level
+   */
+  @ASTNodeAnnotation.Child(name="Right")
+  public Constraint getRight() {
+    return (Constraint) getChild(1);
+  }
+  /**
+   * Retrieves the Right child.
+   * <p><em>This method does not invoke AST transformations.</em></p>
+   * @return The current node used as the Right child.
+   * @apilevel low-level
+   */
+  public Constraint getRightNoTransform() {
+    return (Constraint) getChildNoTransform(1);
+  }
+  /** @apilevel internal */
+  private void eval_reset() {
+    state().trace().flushAttr(this, "Constraint.eval()", "", eval_value);
+    eval_computed = null;
+  }
+  /** @apilevel internal */
+  protected ASTState.Cycle eval_computed = null;
+
+  /** @apilevel internal */
+  protected boolean eval_value;
+
+  /**
+   * @attribute syn
+   * @aspect Constraints
+   * @declaredat E:\\project\\20211201\\src\\main\\jastadd\\hanoi\\Constraints.jrag:10
+   */
+  @ASTNodeAnnotation.Attribute(kind=ASTNodeAnnotation.Kind.SYN)
+  @ASTNodeAnnotation.Source(aspect="Constraints", declaredAt="E:\\project\\20211201\\src\\main\\jastadd\\hanoi\\Constraints.jrag:3")
+  public boolean eval() {
+    ASTState state = state();
+    
+    if (eval_handler == null) {
+      eval_handler = new ASTNode$DepGraphNode(this, "eval", null, ASTNode.inc_EMPTY) {
+        @Override public void reactToDependencyChange() {
+          {
+            eval_computed = null;
+            eval_handler.notifyDependencies();
+            Implication.this.state().trace().flushIncAttr(Implication.this, "eval", "", "");
+          }
+        }
+      };
+    }
+    state().addHandlerDepTo(eval_handler);
+    
+    
+    
+    
+    
+    if (eval_computed == ASTState.NON_CYCLE || eval_computed == state().cycle()) {
+      state().trace().cacheRead(this, "Constraint.eval()", "", eval_value);
+      return eval_value;
+    }
+    
+    state().enterAttrStoreEval(eval_handler);
+    eval_value = eval_compute();
+    if (state().inCircle()) {
+      eval_computed = state().cycle();
+      state().trace().cacheWrite(this, "Constraint.eval()", "", eval_value);
+    } else {
+      eval_computed = ASTState.NON_CYCLE;
+      state().trace().cacheWrite(this, "Constraint.eval()", "", eval_value);
+    }
+    
+    state().exitAttrStoreEval(eval_handler);
+    
+    
+    
+    
+    
+    
+    return eval_value;
+  }
+  /** @apilevel internal */
+  private boolean eval_compute() {
+          return (!this.getLeft().eval()) || this.getRight().eval();
+      }
+  /** @apilevel internal */
+  public ASTNode rewriteTo() {
+    return super.rewriteTo();
+  }
+  /** @apilevel internal */
+  public boolean canRewrite() {
+    return false;
+  }
+
+}
diff --git a/src/gen/java/org/jastadd/ag/ast/JastAddList.java b/src/gen/java/org/jastadd/ag/ast/JastAddList.java
new file mode 100644
index 0000000000000000000000000000000000000000..59cd32f47a4039c7d54bac7a96b8e9f284e17679
--- /dev/null
+++ b/src/gen/java/org/jastadd/ag/ast/JastAddList.java
@@ -0,0 +1,269 @@
+/* This file was generated with JastAdd2 (http://jastadd.org) version 2.3.5 */
+package org.jastadd.ag.ast;
+import java.util.*;
+/**
+ * @ast node
+ * @astdecl JastAddList : ASTNode;
+ * @production JastAddList : {@link ASTNode};
+
+ */
+public class JastAddList<T extends ASTNode> extends ASTNode<T> implements Cloneable, Iterable<T> {
+  /**
+   * @declaredat ASTNode:1
+   */
+  public JastAddList() {
+    super();
+  }
+  /**
+   * Initializes the child array to the correct size.
+   * Initializes List and Opt nta children.
+   * @apilevel internal
+   * @ast method
+   * @declaredat ASTNode:10
+   */
+  public void init$Children() {
+    state().enterConstruction();
+    state().exitConstruction();
+  }
+  /**
+   * @declaredat ASTNode:14
+   */
+  public JastAddList(T... initialChildren) {
+    state().enterConstruction();
+    children = new ASTNode[initialChildren.length];
+      getChild_handler = new ASTNode$DepGraphNode[children.length];
+    for (int i = 0; i < children.length; ++i) {
+      addChild(initialChildren[i]);
+    }
+    state().exitConstruction();
+  }
+  /**
+   * @declaredat ASTNode:25
+   */
+  public JastAddList<T> add(T node) {
+    addChild(node);
+    return this;
+  }
+  /**
+   * @declaredat ASTNode:30
+   */
+  public JastAddList<T> addAll(Iterable<? extends T> c) {
+    for (T node : c) {
+      addChild(node);
+    }
+    return this;
+  }
+  /**
+   * @declaredat ASTNode:37
+   */
+  public JastAddList<T> insertChild(ASTNode node, int i) {
+    super.insertChild(node, i);
+    return this;
+  }
+  /**
+   * @declaredat ASTNode:42
+   */
+  public JastAddList<T> addChild(T node) {
+    super.addChild(node);
+    return this;
+  }
+  /** @apilevel low-level 
+   * @declaredat ASTNode:48
+   */
+  public void removeChild(int i) {
+    super.removeChild(i);
+  }
+  /**
+   * @declaredat ASTNode:52
+   */
+  public int getNumChild() {
+    return getNumChildNoTransform();
+  }
+  /** @return an iterator to iterate over elements in this list node. 
+   * @declaredat ASTNode:57
+   */
+  @Override
+  public java.util.Iterator<T> iterator() {
+    return astChildIterator();
+  }
+  /**
+   * @apilevel internal
+   * @declaredat ASTNode:64
+   */
+  public boolean mayHaveRewrite() {
+    return false;
+  }
+  /** @apilevel internal 
+   * @declaredat ASTNode:68
+   */
+  public void flushAttrCache() {
+  }
+  /** @apilevel internal 
+   * @declaredat ASTNode:71
+   */
+  public void flushCollectionCache() {
+  }
+  /** @apilevel internal 
+   * @declaredat ASTNode:74
+   */
+  public JastAddList<T> clone() throws CloneNotSupportedException {
+    JastAddList node = (JastAddList) super.clone();
+    return node;
+  }
+  /** @apilevel internal 
+   * @declaredat ASTNode:79
+   */
+  public JastAddList<T> copy() {
+    try {
+      JastAddList node = (JastAddList) clone();
+      node.parent = null;
+      if (children != null) {
+        node.children = (ASTNode[]) children.clone();
+      }
+      node.inc_state = inc_CLONED;
+      for (int i = 0; node.children != null && i < node.children.length; i++) {
+        node.children[i] = null;
+      }
+      inc_copyHandlers(node);
+      return node;
+    } catch (CloneNotSupportedException e) {
+      throw new Error("Error: clone not supported for " + getClass().getName());
+    }
+  }
+  /**
+   * Create a deep copy of the AST subtree at this node.
+   * The copy is dangling, i.e. has no parent.
+   * @return dangling copy of the subtree at this node
+   * @apilevel low-level
+   * @deprecated Please use treeCopy or treeCopyNoTransform instead
+   * @declaredat ASTNode:103
+   */
+  @Deprecated
+  public JastAddList<T> fullCopy() {
+    return treeCopyNoTransform();
+  }
+  /**
+   * Create a deep copy of the AST subtree at this node.
+   * The copy is dangling, i.e. has no parent.
+   * @return dangling copy of the subtree at this node
+   * @apilevel low-level
+   * @declaredat ASTNode:113
+   */
+  public JastAddList<T> treeCopyNoTransform() {
+    JastAddList tree = (JastAddList) copy();
+    if (children != null) {
+      for (int i = 0; i < children.length; ++i) {
+        ASTNode child = (ASTNode) children[i];
+        if (child != null) {
+          child = child.treeCopyNoTransform();
+          tree.children[i] = child;
+          child.parent = tree;
+        }
+      }
+    }
+    return tree;
+  }
+  /**
+   * Create a deep copy of the AST subtree at this node.
+   * The subtree of this node is traversed to trigger rewrites before copy.
+   * The copy is dangling, i.e. has no parent.
+   * @return dangling copy of the subtree at this node
+   * @apilevel low-level
+   * @declaredat ASTNode:134
+   */
+  public JastAddList<T> treeCopy() {
+    JastAddList tree = (JastAddList) copy();
+    if (children != null) {
+      for (int i = 0; i < children.length; ++i) {
+        ASTNode child = (ASTNode) getChild(i);
+        if (child != null) {
+          child = child.treeCopy();
+          tree.children[i] = child;
+          child.parent = tree;
+        }
+      }
+    }
+    return tree;
+  }
+  /** @apilevel internal 
+   * @declaredat ASTNode:149
+   */
+  protected boolean childIsNTA(int index) {
+    return super.childIsNTA(index);
+  }
+  /**
+   * @declaredat ASTNode:152
+   */
+  protected void inc_copyHandlers(JastAddList copy) {
+    super.inc_copyHandlers(copy);
+
+  }
+  /** @apilevel internal 
+   * @declaredat ASTNode:158
+   */
+  public void reactToDependencyChange(String attrID, Object _parameters) {
+    super.reactToDependencyChange(attrID, _parameters);
+  }
+  /**
+   * @declaredat ASTNode:165
+   */
+  private boolean inc_throwAway_visited = false;
+  /** @apilevel internal 
+   * @declaredat ASTNode:167
+   */
+  public void inc_throwAway() {
+  if (inc_throwAway_visited) {
+    return;
+  }
+  inc_throwAway_visited = true;
+  inc_state = inc_GARBAGE;
+  super.inc_throwAway();
+  inc_throwAway_visited = false;
+}
+  /**
+   * @declaredat ASTNode:176
+   */
+  private boolean inc_cleanupListeners_visited = false;
+  /**
+   * @declaredat ASTNode:177
+   */
+  public void cleanupListeners() {
+  if (inc_cleanupListeners_visited) {
+    return;
+  }
+  inc_cleanupListeners_visited = true;
+  super.cleanupListeners();
+  inc_cleanupListeners_visited = false;
+}
+  /**
+   * @declaredat ASTNode:185
+   */
+  private boolean inc_cleanupListenersInTree_visited = false;
+  /**
+   * @declaredat ASTNode:186
+   */
+  public void cleanupListenersInTree() {
+  if (inc_cleanupListenersInTree_visited) {
+    return;
+  }
+  inc_cleanupListenersInTree_visited = true;
+  cleanupListeners();
+  for (int i = 0; children != null && i < children.length; i++) {
+    ASTNode child = children[i];
+    if (child == null) {
+      continue;
+    }
+    child.cleanupListenersInTree();
+  }
+  inc_cleanupListenersInTree_visited = false;
+}
+  /** @apilevel internal */
+  public ASTNode rewriteTo() {
+    return super.rewriteTo();
+  }
+  /** @apilevel internal */
+  public boolean canRewrite() {
+    return false;
+  }
+
+}
diff --git a/src/gen/java/org/jastadd/ag/ast/Negation.java b/src/gen/java/org/jastadd/ag/ast/Negation.java
new file mode 100644
index 0000000000000000000000000000000000000000..34f02eec349b0a18d00c4bcf74d98814088aa7bb
--- /dev/null
+++ b/src/gen/java/org/jastadd/ag/ast/Negation.java
@@ -0,0 +1,374 @@
+/* This file was generated with JastAdd2 (http://jastadd.org) version 2.3.5 */
+package org.jastadd.ag.ast;
+import java.util.*;
+/**
+ * @ast node
+ * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\ag.ast:9
+ * @astdecl Negation : UnaryConstraint ::= Constraint;
+ * @production Negation : {@link UnaryConstraint};
+
+ */
+public class Negation extends UnaryConstraint implements Cloneable {
+  /**
+   * @aspect ReferenceCreation
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:99
+   */
+  public static Negation createRef(String ref) {
+    Unresolved$Negation unresolvedNode = new Unresolved$Negation();
+    unresolvedNode.setUnresolved$Token(ref);
+    unresolvedNode.setUnresolved$ResolveOpposite(true);
+    return unresolvedNode;
+  }
+  /**
+   * @aspect ReferenceCreation
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:105
+   */
+  public static Negation createRefDirection(String ref) {
+    Unresolved$Negation unresolvedNode = new Unresolved$Negation();
+    unresolvedNode.setUnresolved$Token(ref);
+    unresolvedNode.setUnresolved$ResolveOpposite(false);
+    return unresolvedNode;
+  }
+  /**
+   * @aspect ResolverTrigger
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:261
+   */
+  public void resolveAll() {
+    super.resolveAll();
+  }
+  /**
+   * @aspect RefResolverHelpers
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:545
+   */
+  Unresolved$Node$Interface as$Unresolved() {
+    return null;
+  }
+  /**
+   * @aspect RefResolverHelpers
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:551
+   */
+  boolean is$Unresolved() {
+    return false;
+  }
+  /**
+   * @declaredat ASTNode:1
+   */
+  public Negation() {
+    super();
+  }
+  /**
+   * Initializes the child array to the correct size.
+   * Initializes List and Opt nta children.
+   * @apilevel internal
+   * @ast method
+   * @declaredat ASTNode:10
+   */
+  public void init$Children() {
+    children = new ASTNode[1];  getChild_handler = new ASTNode$DepGraphNode[children.length];
+    state().enterConstruction();
+    state().exitConstruction();
+  }
+  /**
+   * @declaredat ASTNode:15
+   */
+  @ASTNodeAnnotation.Constructor(
+    name = {"Constraint"},
+    type = {"Constraint"},
+    kind = {"Child"}
+  )
+  public Negation(Constraint p0) {
+state().enterConstruction();
+    setChild(p0, 0);
+state().exitConstruction();
+  }
+  /** @apilevel low-level 
+   * @declaredat ASTNode:26
+   */
+  protected int numChildren() {
+    
+    state().addHandlerDepTo(numChildren_handler);
+    return 1;
+  }
+  /**
+   * @apilevel internal
+   * @declaredat ASTNode:34
+   */
+  public boolean mayHaveRewrite() {
+    return false;
+  }
+  /** @apilevel internal 
+   * @declaredat ASTNode:38
+   */
+  public void flushAttrCache() {
+  }
+  /** @apilevel internal 
+   * @declaredat ASTNode:41
+   */
+  public void flushCollectionCache() {
+  }
+  /** @apilevel internal 
+   * @declaredat ASTNode:44
+   */
+  public Negation clone() throws CloneNotSupportedException {
+    Negation node = (Negation) super.clone();
+    return node;
+  }
+  /** @apilevel internal 
+   * @declaredat ASTNode:49
+   */
+  public Negation copy() {
+    try {
+      Negation node = (Negation) clone();
+      node.parent = null;
+      if (children != null) {
+        node.children = (ASTNode[]) children.clone();
+      }
+      node.inc_state = inc_CLONED;
+      for (int i = 0; node.children != null && i < node.children.length; i++) {
+        node.children[i] = null;
+      }
+      inc_copyHandlers(node);
+      return node;
+    } catch (CloneNotSupportedException e) {
+      throw new Error("Error: clone not supported for " + getClass().getName());
+    }
+  }
+  /**
+   * Create a deep copy of the AST subtree at this node.
+   * The copy is dangling, i.e. has no parent.
+   * @return dangling copy of the subtree at this node
+   * @apilevel low-level
+   * @deprecated Please use treeCopy or treeCopyNoTransform instead
+   * @declaredat ASTNode:73
+   */
+  @Deprecated
+  public Negation fullCopy() {
+    return treeCopyNoTransform();
+  }
+  /**
+   * Create a deep copy of the AST subtree at this node.
+   * The copy is dangling, i.e. has no parent.
+   * @return dangling copy of the subtree at this node
+   * @apilevel low-level
+   * @declaredat ASTNode:83
+   */
+  public Negation treeCopyNoTransform() {
+    Negation tree = (Negation) copy();
+    if (children != null) {
+      for (int i = 0; i < children.length; ++i) {
+        ASTNode child = (ASTNode) children[i];
+        if (child != null) {
+          child = child.treeCopyNoTransform();
+          tree.children[i] = child;
+          child.parent = tree;
+        }
+      }
+    }
+    return tree;
+  }
+  /**
+   * Create a deep copy of the AST subtree at this node.
+   * The subtree of this node is traversed to trigger rewrites before copy.
+   * The copy is dangling, i.e. has no parent.
+   * @return dangling copy of the subtree at this node
+   * @apilevel low-level
+   * @declaredat ASTNode:104
+   */
+  public Negation treeCopy() {
+    Negation tree = (Negation) copy();
+    if (children != null) {
+      for (int i = 0; i < children.length; ++i) {
+        ASTNode child = (ASTNode) getChild(i);
+        if (child != null) {
+          child = child.treeCopy();
+          tree.children[i] = child;
+          child.parent = tree;
+        }
+      }
+    }
+    return tree;
+  }
+  /** @apilevel internal 
+   * @declaredat ASTNode:119
+   */
+  protected boolean childIsNTA(int index) {
+    return super.childIsNTA(index);
+  }
+  /**
+   * @declaredat ASTNode:122
+   */
+  protected ASTNode$DepGraphNode eval_handler;
+  /**
+   * @declaredat ASTNode:123
+   */
+  protected void inc_copyHandlers(Negation copy) {
+    super.inc_copyHandlers(copy);
+
+        if (eval_handler != null) {
+          copy.eval_handler = ASTNode$DepGraphNode.createAttrHandler(eval_handler, copy);
+        }
+  }
+  /** @apilevel internal 
+   * @declaredat ASTNode:132
+   */
+  public void reactToDependencyChange(String attrID, Object _parameters) {
+    super.reactToDependencyChange(attrID, _parameters);
+  }
+  /**
+   * @declaredat ASTNode:139
+   */
+  private boolean inc_throwAway_visited = false;
+  /** @apilevel internal 
+   * @declaredat ASTNode:141
+   */
+  public void inc_throwAway() {
+  if (inc_throwAway_visited) {
+    return;
+  }
+  inc_throwAway_visited = true;
+  inc_state = inc_GARBAGE;
+  super.inc_throwAway();
+  if (eval_handler != null) {
+    eval_handler.throwAway();
+  }
+  inc_throwAway_visited = false;
+}
+  /**
+   * @declaredat ASTNode:153
+   */
+  private boolean inc_cleanupListeners_visited = false;
+  /**
+   * @declaredat ASTNode:154
+   */
+  public void cleanupListeners() {
+  if (inc_cleanupListeners_visited) {
+    return;
+  }
+  inc_cleanupListeners_visited = true;
+  if (eval_handler != null) {
+    eval_handler.cleanupListeners();
+  }
+  super.cleanupListeners();
+  inc_cleanupListeners_visited = false;
+}
+  /**
+   * @declaredat ASTNode:165
+   */
+  private boolean inc_cleanupListenersInTree_visited = false;
+  /**
+   * @declaredat ASTNode:166
+   */
+  public void cleanupListenersInTree() {
+  if (inc_cleanupListenersInTree_visited) {
+    return;
+  }
+  inc_cleanupListenersInTree_visited = true;
+  cleanupListeners();
+  for (int i = 0; children != null && i < children.length; i++) {
+    ASTNode child = children[i];
+    if (child == null) {
+      continue;
+    }
+    child.cleanupListenersInTree();
+  }
+  inc_cleanupListenersInTree_visited = false;
+}
+  /**
+   * Replaces the Constraint child.
+   * @param node The new node to replace the Constraint child.
+   * @apilevel high-level
+   */
+  public Negation setConstraint(Constraint node) {
+    setChild(node, 0);
+    return this;
+  }
+  /**
+   * Retrieves the Constraint child.
+   * @return The current node used as the Constraint child.
+   * @apilevel high-level
+   */
+  @ASTNodeAnnotation.Child(name="Constraint")
+  public Constraint getConstraint() {
+    return (Constraint) getChild(0);
+  }
+  /**
+   * Retrieves the Constraint child.
+   * <p><em>This method does not invoke AST transformations.</em></p>
+   * @return The current node used as the Constraint child.
+   * @apilevel low-level
+   */
+  public Constraint getConstraintNoTransform() {
+    return (Constraint) getChildNoTransform(0);
+  }
+  /** @apilevel internal */
+  private void eval_reset() {
+    state().trace().flushAttr(this, "Constraint.eval()", "", eval_value);
+    eval_computed = null;
+  }
+  /** @apilevel internal */
+  protected ASTState.Cycle eval_computed = null;
+
+  /** @apilevel internal */
+  protected boolean eval_value;
+
+  /**
+   * @attribute syn
+   * @aspect Constraints
+   * @declaredat E:\\project\\20211201\\src\\main\\jastadd\\hanoi\\Constraints.jrag:13
+   */
+  @ASTNodeAnnotation.Attribute(kind=ASTNodeAnnotation.Kind.SYN)
+  @ASTNodeAnnotation.Source(aspect="Constraints", declaredAt="E:\\project\\20211201\\src\\main\\jastadd\\hanoi\\Constraints.jrag:3")
+  public boolean eval() {
+    ASTState state = state();
+    
+    if (eval_handler == null) {
+      eval_handler = new ASTNode$DepGraphNode(this, "eval", null, ASTNode.inc_EMPTY) {
+        @Override public void reactToDependencyChange() {
+          {
+            eval_computed = null;
+            eval_handler.notifyDependencies();
+            Negation.this.state().trace().flushIncAttr(Negation.this, "eval", "", "");
+          }
+        }
+      };
+    }
+    state().addHandlerDepTo(eval_handler);
+    
+    
+    
+    
+    
+    if (eval_computed == ASTState.NON_CYCLE || eval_computed == state().cycle()) {
+      state().trace().cacheRead(this, "Constraint.eval()", "", eval_value);
+      return eval_value;
+    }
+    
+    state().enterAttrStoreEval(eval_handler);
+    eval_value = !getConstraint().eval();
+    if (state().inCircle()) {
+      eval_computed = state().cycle();
+      state().trace().cacheWrite(this, "Constraint.eval()", "", eval_value);
+    } else {
+      eval_computed = ASTState.NON_CYCLE;
+      state().trace().cacheWrite(this, "Constraint.eval()", "", eval_value);
+    }
+    
+    state().exitAttrStoreEval(eval_handler);
+    
+    
+    
+    
+    
+    
+    return eval_value;
+  }
+  /** @apilevel internal */
+  public ASTNode rewriteTo() {
+    return super.rewriteTo();
+  }
+  /** @apilevel internal */
+  public boolean canRewrite() {
+    return false;
+  }
+
+}
diff --git a/src/gen/java/org/jastadd/ag/ast/OnoDisk.java b/src/gen/java/org/jastadd/ag/ast/OnoDisk.java
new file mode 100644
index 0000000000000000000000000000000000000000..b1a9d9c25800e5ca2cf452afe9ba14eff13274a8
--- /dev/null
+++ b/src/gen/java/org/jastadd/ag/ast/OnoDisk.java
@@ -0,0 +1,385 @@
+/* This file was generated with JastAdd2 (http://jastadd.org) version 2.3.5 */
+package org.jastadd.ag.ast;
+import java.util.*;
+/**
+ * @ast node
+ * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\ag.ast:12
+ * @astdecl OnoDisk : Atom ::= <_impl_Rel:java.util.List<Pillar>>;
+ * @production OnoDisk : {@link Atom};
+
+ */
+public class OnoDisk extends Atom implements Cloneable {
+  /**
+   * @aspect ReferenceCreation
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:135
+   */
+  public static OnoDisk createRef(String ref) {
+    Unresolved$OnoDisk unresolvedNode = new Unresolved$OnoDisk();
+    unresolvedNode.setUnresolved$Token(ref);
+    unresolvedNode.setUnresolved$ResolveOpposite(true);
+    return unresolvedNode;
+  }
+  /**
+   * @aspect ReferenceCreation
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:141
+   */
+  public static OnoDisk createRefDirection(String ref) {
+    Unresolved$OnoDisk unresolvedNode = new Unresolved$OnoDisk();
+    unresolvedNode.setUnresolved$Token(ref);
+    unresolvedNode.setUnresolved$ResolveOpposite(false);
+    return unresolvedNode;
+  }
+  /**
+   * @aspect ResolverTrigger
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:273
+   */
+  public void resolveAll() {
+    super.resolveAll();
+  }
+  /**
+   * @aspect RefResolverHelpers
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:629
+   */
+  Unresolved$Node$Interface as$Unresolved() {
+    return null;
+  }
+  /**
+   * @aspect RefResolverHelpers
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:635
+   */
+  boolean is$Unresolved() {
+    return false;
+  }
+  /**
+   * @declaredat ASTNode:1
+   */
+  public OnoDisk() {
+    super();
+  }
+  /**
+   * Initializes the child array to the correct size.
+   * Initializes List and Opt nta children.
+   * @apilevel internal
+   * @ast method
+   * @declaredat ASTNode:10
+   */
+  public void init$Children() {
+    state().enterConstruction();
+    state().exitConstruction();
+  }
+  /**
+   * @declaredat ASTNode:14
+   */
+  @ASTNodeAnnotation.Constructor(
+    name = {"_impl_Rel"},
+    type = {"java.util.List<Pillar>"},
+    kind = {"Token"}
+  )
+  public OnoDisk(java.util.List<Pillar> p0) {
+state().enterConstruction();
+    set_impl_Rel(p0);
+state().exitConstruction();
+  }
+  /** @apilevel low-level 
+   * @declaredat ASTNode:25
+   */
+  protected int numChildren() {
+    
+    state().addHandlerDepTo(numChildren_handler);
+    return 0;
+  }
+  /**
+   * @apilevel internal
+   * @declaredat ASTNode:33
+   */
+  public boolean mayHaveRewrite() {
+    return false;
+  }
+  /** @apilevel internal 
+   * @declaredat ASTNode:37
+   */
+  public void flushAttrCache() {
+  }
+  /** @apilevel internal 
+   * @declaredat ASTNode:40
+   */
+  public void flushCollectionCache() {
+  }
+  /** @apilevel internal 
+   * @declaredat ASTNode:43
+   */
+  public OnoDisk clone() throws CloneNotSupportedException {
+    OnoDisk node = (OnoDisk) super.clone();
+    return node;
+  }
+  /** @apilevel internal 
+   * @declaredat ASTNode:48
+   */
+  public OnoDisk copy() {
+    try {
+      OnoDisk node = (OnoDisk) clone();
+      node.parent = null;
+      if (children != null) {
+        node.children = (ASTNode[]) children.clone();
+      }
+      node.inc_state = inc_CLONED;
+      for (int i = 0; node.children != null && i < node.children.length; i++) {
+        node.children[i] = null;
+      }
+      inc_copyHandlers(node);
+      return node;
+    } catch (CloneNotSupportedException e) {
+      throw new Error("Error: clone not supported for " + getClass().getName());
+    }
+  }
+  /**
+   * Create a deep copy of the AST subtree at this node.
+   * The copy is dangling, i.e. has no parent.
+   * @return dangling copy of the subtree at this node
+   * @apilevel low-level
+   * @deprecated Please use treeCopy or treeCopyNoTransform instead
+   * @declaredat ASTNode:72
+   */
+  @Deprecated
+  public OnoDisk fullCopy() {
+    return treeCopyNoTransform();
+  }
+  /**
+   * Create a deep copy of the AST subtree at this node.
+   * The copy is dangling, i.e. has no parent.
+   * @return dangling copy of the subtree at this node
+   * @apilevel low-level
+   * @declaredat ASTNode:82
+   */
+  public OnoDisk treeCopyNoTransform() {
+    OnoDisk tree = (OnoDisk) copy();
+    if (children != null) {
+      for (int i = 0; i < children.length; ++i) {
+        ASTNode child = (ASTNode) children[i];
+        if (child != null) {
+          child = child.treeCopyNoTransform();
+          tree.children[i] = child;
+          child.parent = tree;
+        }
+      }
+    }
+    return tree;
+  }
+  /**
+   * Create a deep copy of the AST subtree at this node.
+   * The subtree of this node is traversed to trigger rewrites before copy.
+   * The copy is dangling, i.e. has no parent.
+   * @return dangling copy of the subtree at this node
+   * @apilevel low-level
+   * @declaredat ASTNode:103
+   */
+  public OnoDisk treeCopy() {
+    OnoDisk tree = (OnoDisk) copy();
+    if (children != null) {
+      for (int i = 0; i < children.length; ++i) {
+        ASTNode child = (ASTNode) getChild(i);
+        if (child != null) {
+          child = child.treeCopy();
+          tree.children[i] = child;
+          child.parent = tree;
+        }
+      }
+    }
+    return tree;
+  }
+  /** @apilevel internal 
+   * @declaredat ASTNode:118
+   */
+  protected boolean childIsNTA(int index) {
+    return super.childIsNTA(index);
+  }
+  /**
+   * @declaredat ASTNode:121
+   */
+  protected ASTNode$DepGraphNode eval_handler;
+  /**
+   * @declaredat ASTNode:122
+   */
+  protected void inc_copyHandlers(OnoDisk copy) {
+    super.inc_copyHandlers(copy);
+
+        if (eval_handler != null) {
+          copy.eval_handler = ASTNode$DepGraphNode.createAttrHandler(eval_handler, copy);
+        }
+  }
+  /** @apilevel internal 
+   * @declaredat ASTNode:131
+   */
+  public void reactToDependencyChange(String attrID, Object _parameters) {
+    super.reactToDependencyChange(attrID, _parameters);
+  }
+  /**
+   * @declaredat ASTNode:138
+   */
+  private boolean inc_throwAway_visited = false;
+  /** @apilevel internal 
+   * @declaredat ASTNode:140
+   */
+  public void inc_throwAway() {
+  if (inc_throwAway_visited) {
+    return;
+  }
+  inc_throwAway_visited = true;
+  inc_state = inc_GARBAGE;
+  super.inc_throwAway();
+  if (eval_handler != null) {
+    eval_handler.throwAway();
+  }
+  inc_throwAway_visited = false;
+}
+  /**
+   * @declaredat ASTNode:152
+   */
+  private boolean inc_cleanupListeners_visited = false;
+  /**
+   * @declaredat ASTNode:153
+   */
+  public void cleanupListeners() {
+  if (inc_cleanupListeners_visited) {
+    return;
+  }
+  inc_cleanupListeners_visited = true;
+  if (get_impl_Rel_handler != null) {
+    get_impl_Rel_handler.cleanupListeners();
+  }
+  if (eval_handler != null) {
+    eval_handler.cleanupListeners();
+  }
+  super.cleanupListeners();
+  inc_cleanupListeners_visited = false;
+}
+  /**
+   * @declaredat ASTNode:167
+   */
+  private boolean inc_cleanupListenersInTree_visited = false;
+  /**
+   * @declaredat ASTNode:168
+   */
+  public void cleanupListenersInTree() {
+  if (inc_cleanupListenersInTree_visited) {
+    return;
+  }
+  inc_cleanupListenersInTree_visited = true;
+  cleanupListeners();
+  for (int i = 0; children != null && i < children.length; i++) {
+    ASTNode child = children[i];
+    if (child == null) {
+      continue;
+    }
+    child.cleanupListenersInTree();
+  }
+  inc_cleanupListenersInTree_visited = false;
+}
+  /**
+   */
+  protected ASTNode$DepGraphNode get_impl_Rel_handler = ASTNode$DepGraphNode.createAstHandler(this, "get_impl_Rel", null);
+  /**
+   * Replaces the lexeme _impl_Rel.
+   * @param value The new value for the lexeme _impl_Rel.
+   * @apilevel high-level
+   */
+  public OnoDisk set_impl_Rel(java.util.List<Pillar> value) {
+    tokenjava_util_List_Pillar___impl_Rel = value;
+    
+    if (state().disableDeps == 0 && !state().IN_ATTR_STORE_EVAL) {
+      get_impl_Rel_handler.notifyDependencies();
+    
+    
+    
+    
+    }
+    return this;
+  }
+  /**
+   * Retrieves the value for the lexeme _impl_Rel.
+   * @return The value for the lexeme _impl_Rel.
+   * @apilevel high-level
+   */
+  @ASTNodeAnnotation.Token(name="_impl_Rel")
+  public java.util.List<Pillar> get_impl_Rel() {
+    
+    state().addHandlerDepTo(get_impl_Rel_handler);
+    return tokenjava_util_List_Pillar___impl_Rel;
+  }
+  /** @apilevel internal */
+  private void eval_reset() {
+    state().trace().flushAttr(this, "Constraint.eval()", "", eval_value);
+    eval_computed = null;
+  }
+  /** @apilevel internal */
+  protected ASTState.Cycle eval_computed = null;
+
+  /** @apilevel internal */
+  protected boolean eval_value;
+
+  /**
+   * @attribute syn
+   * @aspect Constraints
+   * @declaredat E:\\project\\20211201\\src\\main\\jastadd\\hanoi\\Constraints.jrag:28
+   */
+  @ASTNodeAnnotation.Attribute(kind=ASTNodeAnnotation.Kind.SYN)
+  @ASTNodeAnnotation.Source(aspect="Constraints", declaredAt="E:\\project\\20211201\\src\\main\\jastadd\\hanoi\\Constraints.jrag:3")
+  public boolean eval() {
+    ASTState state = state();
+    
+    if (eval_handler == null) {
+      eval_handler = new ASTNode$DepGraphNode(this, "eval", null, ASTNode.inc_EMPTY) {
+        @Override public void reactToDependencyChange() {
+          {
+            eval_computed = null;
+            eval_handler.notifyDependencies();
+            OnoDisk.this.state().trace().flushIncAttr(OnoDisk.this, "eval", "", "");
+          }
+        }
+      };
+    }
+    state().addHandlerDepTo(eval_handler);
+    
+    
+    
+    
+    
+    if (eval_computed == ASTState.NON_CYCLE || eval_computed == state().cycle()) {
+      state().trace().cacheRead(this, "Constraint.eval()", "", eval_value);
+      return eval_value;
+    }
+    
+    state().enterAttrStoreEval(eval_handler);
+    eval_value = eval_compute();
+    if (state().inCircle()) {
+      eval_computed = state().cycle();
+      state().trace().cacheWrite(this, "Constraint.eval()", "", eval_value);
+    } else {
+      eval_computed = ASTState.NON_CYCLE;
+      state().trace().cacheWrite(this, "Constraint.eval()", "", eval_value);
+    }
+    
+    state().exitAttrStoreEval(eval_handler);
+    
+    
+    
+    
+    
+    
+    return eval_value;
+  }
+  /** @apilevel internal */
+  private boolean eval_compute() {
+          //the origin pillar is empty?
+          return this.getRels().get(0).getNumDisk()==0;
+      }
+  /** @apilevel internal */
+  public ASTNode rewriteTo() {
+    return super.rewriteTo();
+  }
+  /** @apilevel internal */
+  public boolean canRewrite() {
+    return false;
+  }
+
+}
diff --git a/src/gen/java/org/jastadd/ag/ast/Opt.java b/src/gen/java/org/jastadd/ag/ast/Opt.java
new file mode 100644
index 0000000000000000000000000000000000000000..d933085d49faa057d6f1d5ee2b5cd2fbe31b7967
--- /dev/null
+++ b/src/gen/java/org/jastadd/ag/ast/Opt.java
@@ -0,0 +1,216 @@
+/* This file was generated with JastAdd2 (http://jastadd.org) version 2.3.5 */
+package org.jastadd.ag.ast;
+import java.util.*;
+/**
+ * @ast node
+ * @astdecl Opt : ASTNode;
+ * @production Opt : {@link ASTNode};
+
+ */
+public class Opt<T extends ASTNode> extends ASTNode<T> implements Cloneable {
+  /**
+   * @declaredat ASTNode:1
+   */
+  public Opt() {
+    super();
+  }
+  /**
+   * Initializes the child array to the correct size.
+   * Initializes List and Opt nta children.
+   * @apilevel internal
+   * @ast method
+   * @declaredat ASTNode:10
+   */
+  public void init$Children() {
+    state().enterConstruction();
+    state().exitConstruction();
+  }
+  /**
+   * @declaredat ASTNode:14
+   */
+  public Opt(T opt) {
+    state().enterConstruction();
+    setChild(opt, 0);
+    state().exitConstruction();
+  }
+  /**
+   * @apilevel internal
+   * @declaredat ASTNode:22
+   */
+  public boolean mayHaveRewrite() {
+    return false;
+  }
+  /** @apilevel internal 
+   * @declaredat ASTNode:26
+   */
+  public void flushAttrCache() {
+  }
+  /** @apilevel internal 
+   * @declaredat ASTNode:29
+   */
+  public void flushCollectionCache() {
+  }
+  /** @apilevel internal 
+   * @declaredat ASTNode:32
+   */
+  public Opt<T> clone() throws CloneNotSupportedException {
+    Opt node = (Opt) super.clone();
+    return node;
+  }
+  /** @apilevel internal 
+   * @declaredat ASTNode:37
+   */
+  public Opt<T> copy() {
+    try {
+      Opt node = (Opt) clone();
+      node.parent = null;
+      if (children != null) {
+        node.children = (ASTNode[]) children.clone();
+      }
+      node.inc_state = inc_CLONED;
+      for (int i = 0; node.children != null && i < node.children.length; i++) {
+        node.children[i] = null;
+      }
+      inc_copyHandlers(node);
+      return node;
+    } catch (CloneNotSupportedException e) {
+      throw new Error("Error: clone not supported for " + getClass().getName());
+    }
+  }
+  /**
+   * Create a deep copy of the AST subtree at this node.
+   * The copy is dangling, i.e. has no parent.
+   * @return dangling copy of the subtree at this node
+   * @apilevel low-level
+   * @deprecated Please use treeCopy or treeCopyNoTransform instead
+   * @declaredat ASTNode:61
+   */
+  @Deprecated
+  public Opt<T> fullCopy() {
+    return treeCopyNoTransform();
+  }
+  /**
+   * Create a deep copy of the AST subtree at this node.
+   * The copy is dangling, i.e. has no parent.
+   * @return dangling copy of the subtree at this node
+   * @apilevel low-level
+   * @declaredat ASTNode:71
+   */
+  public Opt<T> treeCopyNoTransform() {
+    Opt tree = (Opt) copy();
+    if (children != null) {
+      for (int i = 0; i < children.length; ++i) {
+        ASTNode child = (ASTNode) children[i];
+        if (child != null) {
+          child = child.treeCopyNoTransform();
+          tree.children[i] = child;
+          child.parent = tree;
+        }
+      }
+    }
+    return tree;
+  }
+  /**
+   * Create a deep copy of the AST subtree at this node.
+   * The subtree of this node is traversed to trigger rewrites before copy.
+   * The copy is dangling, i.e. has no parent.
+   * @return dangling copy of the subtree at this node
+   * @apilevel low-level
+   * @declaredat ASTNode:92
+   */
+  public Opt<T> treeCopy() {
+    Opt tree = (Opt) copy();
+    if (children != null) {
+      for (int i = 0; i < children.length; ++i) {
+        ASTNode child = (ASTNode) getChild(i);
+        if (child != null) {
+          child = child.treeCopy();
+          tree.children[i] = child;
+          child.parent = tree;
+        }
+      }
+    }
+    return tree;
+  }
+  /** @apilevel internal 
+   * @declaredat ASTNode:107
+   */
+  protected boolean childIsNTA(int index) {
+    return super.childIsNTA(index);
+  }
+  /**
+   * @declaredat ASTNode:110
+   */
+  protected void inc_copyHandlers(Opt copy) {
+    super.inc_copyHandlers(copy);
+
+  }
+  /** @apilevel internal 
+   * @declaredat ASTNode:116
+   */
+  public void reactToDependencyChange(String attrID, Object _parameters) {
+    super.reactToDependencyChange(attrID, _parameters);
+  }
+  /**
+   * @declaredat ASTNode:123
+   */
+  private boolean inc_throwAway_visited = false;
+  /** @apilevel internal 
+   * @declaredat ASTNode:125
+   */
+  public void inc_throwAway() {
+  if (inc_throwAway_visited) {
+    return;
+  }
+  inc_throwAway_visited = true;
+  inc_state = inc_GARBAGE;
+  super.inc_throwAway();
+  inc_throwAway_visited = false;
+}
+  /**
+   * @declaredat ASTNode:134
+   */
+  private boolean inc_cleanupListeners_visited = false;
+  /**
+   * @declaredat ASTNode:135
+   */
+  public void cleanupListeners() {
+  if (inc_cleanupListeners_visited) {
+    return;
+  }
+  inc_cleanupListeners_visited = true;
+  super.cleanupListeners();
+  inc_cleanupListeners_visited = false;
+}
+  /**
+   * @declaredat ASTNode:143
+   */
+  private boolean inc_cleanupListenersInTree_visited = false;
+  /**
+   * @declaredat ASTNode:144
+   */
+  public void cleanupListenersInTree() {
+  if (inc_cleanupListenersInTree_visited) {
+    return;
+  }
+  inc_cleanupListenersInTree_visited = true;
+  cleanupListeners();
+  for (int i = 0; children != null && i < children.length; i++) {
+    ASTNode child = children[i];
+    if (child == null) {
+      continue;
+    }
+    child.cleanupListenersInTree();
+  }
+  inc_cleanupListenersInTree_visited = false;
+}
+  /** @apilevel internal */
+  public ASTNode rewriteTo() {
+    return super.rewriteTo();
+  }
+  /** @apilevel internal */
+  public boolean canRewrite() {
+    return false;
+  }
+
+}
diff --git a/src/gen/java/org/jastadd/ag/ast/Pair.java b/src/gen/java/org/jastadd/ag/ast/Pair.java
new file mode 100644
index 0000000000000000000000000000000000000000..6f82e72d2ef876584e1c38c6657592ed97f39eea
--- /dev/null
+++ b/src/gen/java/org/jastadd/ag/ast/Pair.java
@@ -0,0 +1,55 @@
+package org.jastadd.ag.ast;
+
+import java.util.*;
+/**
+ * @ast class
+ * @aspect RelAstAPI
+ * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\ag.jadd:64
+ */
+public class Pair<T1, T2> extends java.lang.Object {
+  /**
+   * @aspect RelAstAPI
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\ag.jadd:65
+   */
+  
+    public final T1 _1;
+  /**
+   * @aspect RelAstAPI
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\ag.jadd:66
+   */
+  
+    public final T2 _2;
+  /**
+   * @aspect RelAstAPI
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\ag.jadd:67
+   */
+  
+    public Pair(T1 _1, T2 _2) {
+      ASTNode.assertNotNull(_1);
+      ASTNode.assertNotNull(_2);
+      this._1 = _1;
+      this._2 = _2;
+    }
+  /**
+   * @aspect RelAstAPI
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\ag.jadd:73
+   */
+  
+    public boolean equals(Object other) {
+      if (other instanceof Pair) {
+        Pair<?,?> p = (Pair<?,?>) other;
+        return _1.equals(p._1) && _2.equals(p._2);
+      } else {
+        return false;
+      }
+    }
+  /**
+   * @aspect RelAstAPI
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\ag.jadd:81
+   */
+  
+    public int hashCode() {
+      return 31*_1.hashCode() + _2.hashCode();
+    }
+
+}
diff --git a/src/gen/java/org/jastadd/ag/ast/Pillar.java b/src/gen/java/org/jastadd/ag/ast/Pillar.java
new file mode 100644
index 0000000000000000000000000000000000000000..707725253a6629f5232f777fa15a88216d029e4e
--- /dev/null
+++ b/src/gen/java/org/jastadd/ag/ast/Pillar.java
@@ -0,0 +1,548 @@
+/* This file was generated with JastAdd2 (http://jastadd.org) version 2.3.5 */
+package org.jastadd.ag.ast;
+import java.util.*;
+/**
+ * @ast node
+ * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\ag.ast:17
+ * @astdecl Pillar : ASTNode ::= Disk*;
+ * @production Pillar : {@link ASTNode} ::= <span class="component">{@link Disk}*</span>;
+
+ */
+public class Pillar extends ASTNode<ASTNode> implements Cloneable {
+  /**
+   * @aspect MoveTo
+   * @declaredat E:\\project\\20211201\\src\\main\\jastadd\\hanoi\\MoveTo.jadd:63
+   */
+  public boolean moveTo(Pillar P){
+      int i = this.getNumDisk();
+      P.addDisk(this.getDisk(i-1));
+      this.getDisks().removeChild(i-1);
+      return true;
+  }
+  /**
+   * @aspect ReferenceCreation
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:195
+   */
+  public static Pillar createRef(String ref) {
+    Unresolved$Pillar unresolvedNode = new Unresolved$Pillar();
+    unresolvedNode.setUnresolved$Token(ref);
+    unresolvedNode.setUnresolved$ResolveOpposite(true);
+    return unresolvedNode;
+  }
+  /**
+   * @aspect ReferenceCreation
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:201
+   */
+  public static Pillar createRefDirection(String ref) {
+    Unresolved$Pillar unresolvedNode = new Unresolved$Pillar();
+    unresolvedNode.setUnresolved$Token(ref);
+    unresolvedNode.setUnresolved$ResolveOpposite(false);
+    return unresolvedNode;
+  }
+  /**
+   * @aspect ResolverTrigger
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:293
+   */
+  public void resolveAll() {
+    super.resolveAll();
+  }
+  /**
+   * @aspect RefResolverHelpers
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:769
+   */
+  Unresolved$Node$Interface as$Unresolved() {
+    return null;
+  }
+  /**
+   * @aspect RefResolverHelpers
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:775
+   */
+  boolean is$Unresolved() {
+    return false;
+  }
+  /**
+   * @declaredat ASTNode:1
+   */
+  public Pillar() {
+    super();
+  }
+  /**
+   * Initializes the child array to the correct size.
+   * Initializes List and Opt nta children.
+   * @apilevel internal
+   * @ast method
+   * @declaredat ASTNode:10
+   */
+  public void init$Children() {
+    children = new ASTNode[1];  getChild_handler = new ASTNode$DepGraphNode[children.length];
+    state().enterConstruction();
+    setChild(new JastAddList(), 0);
+    state().exitConstruction();
+  }
+  /**
+   * @declaredat ASTNode:16
+   */
+  @ASTNodeAnnotation.Constructor(
+    name = {"Disk"},
+    type = {"JastAddList<Disk>"},
+    kind = {"List"}
+  )
+  public Pillar(JastAddList<Disk> p0) {
+state().enterConstruction();
+    setChild(p0, 0);
+state().exitConstruction();
+  }
+  /** @apilevel low-level 
+   * @declaredat ASTNode:27
+   */
+  protected int numChildren() {
+    
+    state().addHandlerDepTo(numChildren_handler);
+    return 1;
+  }
+  /**
+   * @apilevel internal
+   * @declaredat ASTNode:35
+   */
+  public boolean mayHaveRewrite() {
+    return false;
+  }
+  /** @apilevel internal 
+   * @declaredat ASTNode:39
+   */
+  public void flushAttrCache() {
+  }
+  /** @apilevel internal 
+   * @declaredat ASTNode:42
+   */
+  public void flushCollectionCache() {
+  }
+  /** @apilevel internal 
+   * @declaredat ASTNode:45
+   */
+  public Pillar clone() throws CloneNotSupportedException {
+    Pillar node = (Pillar) super.clone();
+    return node;
+  }
+  /** @apilevel internal 
+   * @declaredat ASTNode:50
+   */
+  public Pillar copy() {
+    try {
+      Pillar node = (Pillar) clone();
+      node.parent = null;
+      if (children != null) {
+        node.children = (ASTNode[]) children.clone();
+      }
+      node.inc_state = inc_CLONED;
+      for (int i = 0; node.children != null && i < node.children.length; i++) {
+        node.children[i] = null;
+      }
+      inc_copyHandlers(node);
+      return node;
+    } catch (CloneNotSupportedException e) {
+      throw new Error("Error: clone not supported for " + getClass().getName());
+    }
+  }
+  /**
+   * Create a deep copy of the AST subtree at this node.
+   * The copy is dangling, i.e. has no parent.
+   * @return dangling copy of the subtree at this node
+   * @apilevel low-level
+   * @deprecated Please use treeCopy or treeCopyNoTransform instead
+   * @declaredat ASTNode:74
+   */
+  @Deprecated
+  public Pillar fullCopy() {
+    return treeCopyNoTransform();
+  }
+  /**
+   * Create a deep copy of the AST subtree at this node.
+   * The copy is dangling, i.e. has no parent.
+   * @return dangling copy of the subtree at this node
+   * @apilevel low-level
+   * @declaredat ASTNode:84
+   */
+  public Pillar treeCopyNoTransform() {
+    Pillar tree = (Pillar) copy();
+    if (children != null) {
+      for (int i = 0; i < children.length; ++i) {
+        ASTNode child = (ASTNode) children[i];
+        if (child != null) {
+          child = child.treeCopyNoTransform();
+          tree.children[i] = child;
+          child.parent = tree;
+        }
+      }
+    }
+    return tree;
+  }
+  /**
+   * Create a deep copy of the AST subtree at this node.
+   * The subtree of this node is traversed to trigger rewrites before copy.
+   * The copy is dangling, i.e. has no parent.
+   * @return dangling copy of the subtree at this node
+   * @apilevel low-level
+   * @declaredat ASTNode:105
+   */
+  public Pillar treeCopy() {
+    Pillar tree = (Pillar) copy();
+    if (children != null) {
+      for (int i = 0; i < children.length; ++i) {
+        ASTNode child = (ASTNode) getChild(i);
+        if (child != null) {
+          child = child.treeCopy();
+          tree.children[i] = child;
+          child.parent = tree;
+        }
+      }
+    }
+    return tree;
+  }
+  /** @apilevel internal 
+   * @declaredat ASTNode:120
+   */
+  protected boolean childIsNTA(int index) {
+    return super.childIsNTA(index);
+  }
+  /**
+   * @declaredat ASTNode:123
+   */
+  protected ASTNode$DepGraphNode moveSeq_handler;
+  /**
+   * @declaredat ASTNode:124
+   */
+  protected ASTNode$DepGraphNode ID_handler;
+  /**
+   * @declaredat ASTNode:125
+   */
+  protected void inc_copyHandlers(Pillar copy) {
+    super.inc_copyHandlers(copy);
+
+        if (moveSeq_handler != null) {
+          copy.moveSeq_handler = ASTNode$DepGraphNode.createAttrHandler(moveSeq_handler, copy);
+        }
+        if (ID_handler != null) {
+          copy.ID_handler = ASTNode$DepGraphNode.createAttrHandler(ID_handler, copy);
+        }
+  }
+  /** @apilevel internal 
+   * @declaredat ASTNode:137
+   */
+  public void reactToDependencyChange(String attrID, Object _parameters) {
+    super.reactToDependencyChange(attrID, _parameters);
+  }
+  /**
+   * @declaredat ASTNode:144
+   */
+  private boolean inc_throwAway_visited = false;
+  /** @apilevel internal 
+   * @declaredat ASTNode:146
+   */
+  public void inc_throwAway() {
+  if (inc_throwAway_visited) {
+    return;
+  }
+  inc_throwAway_visited = true;
+  inc_state = inc_GARBAGE;
+  super.inc_throwAway();
+  if (moveSeq_handler != null) {
+    moveSeq_handler.throwAway();
+  }
+  if (ID_handler != null) {
+    ID_handler.throwAway();
+  }
+  inc_throwAway_visited = false;
+}
+  /**
+   * @declaredat ASTNode:161
+   */
+  private boolean inc_cleanupListeners_visited = false;
+  /**
+   * @declaredat ASTNode:162
+   */
+  public void cleanupListeners() {
+  if (inc_cleanupListeners_visited) {
+    return;
+  }
+  inc_cleanupListeners_visited = true;
+  if (moveSeq_handler != null) {
+    moveSeq_handler.cleanupListeners();
+  }
+  
+  if (ID_handler != null) {
+    ID_handler.cleanupListeners();
+  }
+  super.cleanupListeners();
+  inc_cleanupListeners_visited = false;
+}
+  /**
+   * @declaredat ASTNode:177
+   */
+  private boolean inc_cleanupListenersInTree_visited = false;
+  /**
+   * @declaredat ASTNode:178
+   */
+  public void cleanupListenersInTree() {
+  if (inc_cleanupListenersInTree_visited) {
+    return;
+  }
+  inc_cleanupListenersInTree_visited = true;
+  cleanupListeners();
+  for (int i = 0; children != null && i < children.length; i++) {
+    ASTNode child = children[i];
+    if (child == null) {
+      continue;
+    }
+    child.cleanupListenersInTree();
+  }
+  inc_cleanupListenersInTree_visited = false;
+}
+  /**
+   * Replaces the Disk list.
+   * @param list The new list node to be used as the Disk list.
+   * @apilevel high-level
+   */
+  public Pillar setDiskList(JastAddList<Disk> list) {
+    setChild(list, 0);
+    return this;
+  }
+  /**
+   * Retrieves the number of children in the Disk list.
+   * @return Number of children in the Disk list.
+   * @apilevel high-level
+   */
+  public int getNumDisk() {
+    return getDiskList().getNumChild();
+  }
+  /**
+   * Retrieves the number of children in the Disk list.
+   * Calling this method will not trigger rewrites.
+   * @return Number of children in the Disk list.
+   * @apilevel low-level
+   */
+  public int getNumDiskNoTransform() {
+    return getDiskListNoTransform().getNumChildNoTransform();
+  }
+  /**
+   * Retrieves the element at index {@code i} in the Disk list.
+   * @param i Index of the element to return.
+   * @return The element at position {@code i} in the Disk list.
+   * @apilevel high-level
+   */
+  public Disk getDisk(int i) {
+    return (Disk) getDiskList().getChild(i);
+  }
+  /**
+   * Check whether the Disk list has any children.
+   * @return {@code true} if it has at least one child, {@code false} otherwise.
+   * @apilevel high-level
+   */
+  public boolean hasDisk() {
+    return getDiskList().getNumChild() != 0;
+  }
+  /**
+   * Append an element to the Disk list.
+   * @param node The element to append to the Disk list.
+   * @apilevel high-level
+   */
+  public Pillar addDisk(Disk node) {
+    JastAddList<Disk> list = (parent == null) ? getDiskListNoTransform() : getDiskList();
+    list.addChild(node);
+    return this;
+  }
+  /** @apilevel low-level 
+   */
+  public Pillar addDiskNoTransform(Disk node) {
+    JastAddList<Disk> list = getDiskListNoTransform();
+    list.addChild(node);
+    return this;
+  }
+  /**
+   * Replaces the Disk list element at index {@code i} with the new node {@code node}.
+   * @param node The new node to replace the old list element.
+   * @param i The list index of the node to be replaced.
+   * @apilevel high-level
+   */
+  public Pillar setDisk(Disk node, int i) {
+    JastAddList<Disk> list = getDiskList();
+    list.setChild(node, i);
+    return this;
+  }
+  /**
+   * Retrieves the Disk list.
+   * @return The node representing the Disk list.
+   * @apilevel high-level
+   */
+  @ASTNodeAnnotation.ListChild(name="Disk")
+  public JastAddList<Disk> getDiskList() {
+    JastAddList<Disk> list = (JastAddList<Disk>) getChild(0);
+    return list;
+  }
+  /**
+   * Retrieves the Disk list.
+   * <p><em>This method does not invoke AST transformations.</em></p>
+   * @return The node representing the Disk list.
+   * @apilevel low-level
+   */
+  public JastAddList<Disk> getDiskListNoTransform() {
+    return (JastAddList<Disk>) getChildNoTransform(0);
+  }
+  /**
+   * @return the element at index {@code i} in the Disk list without
+   * triggering rewrites.
+   */
+  public Disk getDiskNoTransform(int i) {
+    return (Disk) getDiskListNoTransform().getChildNoTransform(i);
+  }
+  /**
+   * Retrieves the Disk list.
+   * @return The node representing the Disk list.
+   * @apilevel high-level
+   */
+  public JastAddList<Disk> getDisks() {
+    return getDiskList();
+  }
+  /**
+   * Retrieves the Disk list.
+   * <p><em>This method does not invoke AST transformations.</em></p>
+   * @return The node representing the Disk list.
+   * @apilevel low-level
+   */
+  public JastAddList<Disk> getDisksNoTransform() {
+    return getDiskListNoTransform();
+  }
+  /**
+   * @attribute inh
+   * @aspect CanMove
+   * @declaredat E:\\project\\20211201\\src\\main\\jastadd\\hanoi\\CanMove.jrag:12
+   */
+  @ASTNodeAnnotation.Attribute(kind=ASTNodeAnnotation.Kind.INH)
+  @ASTNodeAnnotation.Source(aspect="CanMove", declaredAt="E:\\project\\20211201\\src\\main\\jastadd\\hanoi\\CanMove.jrag:12")
+  public int moveSeq() {
+    ASTState state = state();
+    
+    if (moveSeq_handler == null) {
+      moveSeq_handler = new ASTNode$DepGraphNode(this, "moveSeq", null, ASTNode.inc_EMPTY) {
+        @Override public void reactToDependencyChange() {
+          {
+            moveSeq_computed = null;
+            moveSeq_handler.notifyDependencies();
+            Pillar.this.state().trace().flushIncAttr(Pillar.this, "moveSeq", "", "");
+          }
+        }
+      };
+    }
+    state().addHandlerDepTo(moveSeq_handler);
+    
+    
+    
+    
+    
+    if (moveSeq_computed == ASTState.NON_CYCLE || moveSeq_computed == state().cycle()) {
+      state().trace().cacheRead(this, "Pillar.moveSeq()", "", moveSeq_value);
+      return moveSeq_value;
+    }
+    
+    state().enterAttrStoreEval(moveSeq_handler);
+    moveSeq_value = getParent().Define_moveSeq(this, null);
+    if (state().inCircle()) {
+      moveSeq_computed = state().cycle();
+      state().trace().cacheWrite(this, "Pillar.moveSeq()", "", moveSeq_value);
+    } else {
+      moveSeq_computed = ASTState.NON_CYCLE;
+      state().trace().cacheWrite(this, "Pillar.moveSeq()", "", moveSeq_value);
+    }
+    
+    state().exitAttrStoreEval(moveSeq_handler);
+    
+    
+    
+    
+    
+    
+    return moveSeq_value;
+  }
+  /** @apilevel internal */
+  private void moveSeq_reset() {
+    state().trace().flushAttr(this, "Pillar.moveSeq()", "", moveSeq_value);
+    moveSeq_computed = null;
+  }
+  /** @apilevel internal */
+  protected ASTState.Cycle moveSeq_computed = null;
+
+  /** @apilevel internal */
+  protected int moveSeq_value;
+
+  /**
+   * @attribute inh
+   * @aspect CanMove
+   * @declaredat E:\\project\\20211201\\src\\main\\jastadd\\hanoi\\CanMove.jrag:20
+   */
+  @ASTNodeAnnotation.Attribute(kind=ASTNodeAnnotation.Kind.INH)
+  @ASTNodeAnnotation.Source(aspect="CanMove", declaredAt="E:\\project\\20211201\\src\\main\\jastadd\\hanoi\\CanMove.jrag:20")
+  public int ID() {
+    ASTState state = state();
+    
+    if (ID_handler == null) {
+      ID_handler = new ASTNode$DepGraphNode(this, "ID", null, ASTNode.inc_EMPTY) {
+        @Override public void reactToDependencyChange() {
+          {
+            ID_computed = null;
+            ID_handler.notifyDependencies();
+            Pillar.this.state().trace().flushIncAttr(Pillar.this, "ID", "", "");
+          }
+        }
+      };
+    }
+    state().addHandlerDepTo(ID_handler);
+    
+    
+    
+    
+    
+    if (ID_computed == ASTState.NON_CYCLE || ID_computed == state().cycle()) {
+      state().trace().cacheRead(this, "Pillar.ID()", "", ID_value);
+      return ID_value;
+    }
+    
+    state().enterAttrStoreEval(ID_handler);
+    ID_value = getParent().Define_ID(this, null);
+    if (state().inCircle()) {
+      ID_computed = state().cycle();
+      state().trace().cacheWrite(this, "Pillar.ID()", "", ID_value);
+    } else {
+      ID_computed = ASTState.NON_CYCLE;
+      state().trace().cacheWrite(this, "Pillar.ID()", "", ID_value);
+    }
+    
+    state().exitAttrStoreEval(ID_handler);
+    
+    
+    
+    
+    
+    
+    return ID_value;
+  }
+  /** @apilevel internal */
+  private void ID_reset() {
+    state().trace().flushAttr(this, "Pillar.ID()", "", ID_value);
+    ID_computed = null;
+  }
+  /** @apilevel internal */
+  protected ASTState.Cycle ID_computed = null;
+
+  /** @apilevel internal */
+  protected int ID_value;
+
+  /** @apilevel internal */
+  public ASTNode rewriteTo() {
+    return super.rewriteTo();
+  }
+  /** @apilevel internal */
+  public boolean canRewrite() {
+    return false;
+  }
+
+}
diff --git a/src/gen/java/org/jastadd/ag/ast/Root.java b/src/gen/java/org/jastadd/ag/ast/Root.java
new file mode 100644
index 0000000000000000000000000000000000000000..5f880835821520067be842006bf6aad090af2449
--- /dev/null
+++ b/src/gen/java/org/jastadd/ag/ast/Root.java
@@ -0,0 +1,673 @@
+/* This file was generated with JastAdd2 (http://jastadd.org) version 2.3.5 */
+package org.jastadd.ag.ast;
+import java.util.*;
+/**
+ * @ast node
+ * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\ag.ast:1
+ * @astdecl Root : ASTNode ::= BinaryConstraint* UnaryConstraint* Atom*;
+ * @production Root : {@link ASTNode} ::= <span class="component">{@link BinaryConstraint}*</span> <span class="component">{@link UnaryConstraint}*</span> <span class="component">{@link Atom}*</span>;
+
+ */
+public class Root extends ASTNode<ASTNode> implements Cloneable {
+  /**
+   * @aspect MoveTo
+   * @declaredat E:\\project\\20211201\\src\\main\\jastadd\\hanoi\\MoveTo.jadd:2
+   */
+  public int check(Pillar P0, Pillar P1, boolean turn){
+/*for every odd turn(turn==true), move the smallest disk D0 in sequence.
+Therefore, CheckD0 checks for a move from P0 to P1, when D0 is on the top of P0.*/
+    if(turn==true){
+      CheckD0 C=new CheckD0();
+      this.addAtom(C);
+      this.getAtom(0).addRel(P0);
+      if(this.getAtom(0).eval()){
+        return 1;//odd turn and valid move
+      }else{
+        return 0;
+      }
+    }
+/*for every even turn(turn==false), move the disk D on top of P0 to P1:
+D is not D0(the smallest disk).
+There is always one D can be moved in the even turn according to the game rules.
+Statements:
+1.P0 is not empty: not OnoDisk().
+2.When condition 1 holds, P1 can be empty: TnoDisk().
+3.When 1 holds and 2 doesn\u9225\u6a9b hold, D0 < D1(for the disks on the top of P0 and P1 respectively).
+Therefore, we want not OnoDisk() and (TnoDisk() or CheckSize()) to be true.
+
+Conjunction()-------------Negation()--------------OnoDisk()
+                      |
+                      |--------------------Disjunction()-----------TnoDisk()
+                                              |
+                                              |------------------CheckSize()*/
+    Conjunction C0=new Conjunction();
+    Negation C1=new Negation();
+    Disjunction C2=new Disjunction();
+    OnoDisk C3=new OnoDisk();
+    TnoDisk C4=new TnoDisk();
+    CheckSize C5=new CheckSize();
+
+    C0.setLeft(C1);
+    C0.setRight(C2);
+    C1.setConstraint(C3);
+    C2.setLeft(C4);
+    C2.setRight(C5);
+
+    C3.addRel(P0);
+    C4.addRel(P1);
+    C5.addRel(P0);
+    C5.addRel(P1);
+    this.addBinaryConstraint(C0);
+    if(this.getBinaryConstraint(0).eval()){
+      return 2;//even turn and valid move
+    }
+    return 0;
+  }
+  /**
+   * @aspect ReferenceCreation
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:3
+   */
+  public static Root createRef(String ref) {
+    Unresolved$Root unresolvedNode = new Unresolved$Root();
+    unresolvedNode.setUnresolved$Token(ref);
+    unresolvedNode.setUnresolved$ResolveOpposite(true);
+    return unresolvedNode;
+  }
+  /**
+   * @aspect ReferenceCreation
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:9
+   */
+  public static Root createRefDirection(String ref) {
+    Unresolved$Root unresolvedNode = new Unresolved$Root();
+    unresolvedNode.setUnresolved$Token(ref);
+    unresolvedNode.setUnresolved$ResolveOpposite(false);
+    return unresolvedNode;
+  }
+  /**
+   * @aspect ResolverTrigger
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:228
+   */
+  public void resolveAll() {
+    super.resolveAll();
+  }
+  /**
+   * @aspect RefResolverHelpers
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:321
+   */
+  Unresolved$Node$Interface as$Unresolved() {
+    return null;
+  }
+  /**
+   * @aspect RefResolverHelpers
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:327
+   */
+  boolean is$Unresolved() {
+    return false;
+  }
+  /**
+   * @declaredat ASTNode:1
+   */
+  public Root() {
+    super();
+  }
+  /**
+   * Initializes the child array to the correct size.
+   * Initializes List and Opt nta children.
+   * @apilevel internal
+   * @ast method
+   * @declaredat ASTNode:10
+   */
+  public void init$Children() {
+    children = new ASTNode[3];  getChild_handler = new ASTNode$DepGraphNode[children.length];
+    state().enterConstruction();
+    setChild(new JastAddList(), 0);
+    setChild(new JastAddList(), 1);
+    setChild(new JastAddList(), 2);
+    state().exitConstruction();
+  }
+  /**
+   * @declaredat ASTNode:18
+   */
+  @ASTNodeAnnotation.Constructor(
+    name = {"BinaryConstraint", "UnaryConstraint", "Atom"},
+    type = {"JastAddList<BinaryConstraint>", "JastAddList<UnaryConstraint>", "JastAddList<Atom>"},
+    kind = {"List", "List", "List"}
+  )
+  public Root(JastAddList<BinaryConstraint> p0, JastAddList<UnaryConstraint> p1, JastAddList<Atom> p2) {
+state().enterConstruction();
+    setChild(p0, 0);
+    setChild(p1, 1);
+    setChild(p2, 2);
+state().exitConstruction();
+  }
+  /** @apilevel low-level 
+   * @declaredat ASTNode:31
+   */
+  protected int numChildren() {
+    
+    state().addHandlerDepTo(numChildren_handler);
+    return 3;
+  }
+  /**
+   * @apilevel internal
+   * @declaredat ASTNode:39
+   */
+  public boolean mayHaveRewrite() {
+    return false;
+  }
+  /** @apilevel internal 
+   * @declaredat ASTNode:43
+   */
+  public void flushAttrCache() {
+  }
+  /** @apilevel internal 
+   * @declaredat ASTNode:46
+   */
+  public void flushCollectionCache() {
+  }
+  /** @apilevel internal 
+   * @declaredat ASTNode:49
+   */
+  public Root clone() throws CloneNotSupportedException {
+    Root node = (Root) super.clone();
+    return node;
+  }
+  /** @apilevel internal 
+   * @declaredat ASTNode:54
+   */
+  public Root copy() {
+    try {
+      Root node = (Root) clone();
+      node.parent = null;
+      if (children != null) {
+        node.children = (ASTNode[]) children.clone();
+      }
+      node.inc_state = inc_CLONED;
+      for (int i = 0; node.children != null && i < node.children.length; i++) {
+        node.children[i] = null;
+      }
+      inc_copyHandlers(node);
+      return node;
+    } catch (CloneNotSupportedException e) {
+      throw new Error("Error: clone not supported for " + getClass().getName());
+    }
+  }
+  /**
+   * Create a deep copy of the AST subtree at this node.
+   * The copy is dangling, i.e. has no parent.
+   * @return dangling copy of the subtree at this node
+   * @apilevel low-level
+   * @deprecated Please use treeCopy or treeCopyNoTransform instead
+   * @declaredat ASTNode:78
+   */
+  @Deprecated
+  public Root fullCopy() {
+    return treeCopyNoTransform();
+  }
+  /**
+   * Create a deep copy of the AST subtree at this node.
+   * The copy is dangling, i.e. has no parent.
+   * @return dangling copy of the subtree at this node
+   * @apilevel low-level
+   * @declaredat ASTNode:88
+   */
+  public Root treeCopyNoTransform() {
+    Root tree = (Root) copy();
+    if (children != null) {
+      for (int i = 0; i < children.length; ++i) {
+        ASTNode child = (ASTNode) children[i];
+        if (child != null) {
+          child = child.treeCopyNoTransform();
+          tree.children[i] = child;
+          child.parent = tree;
+        }
+      }
+    }
+    return tree;
+  }
+  /**
+   * Create a deep copy of the AST subtree at this node.
+   * The subtree of this node is traversed to trigger rewrites before copy.
+   * The copy is dangling, i.e. has no parent.
+   * @return dangling copy of the subtree at this node
+   * @apilevel low-level
+   * @declaredat ASTNode:109
+   */
+  public Root treeCopy() {
+    Root tree = (Root) copy();
+    if (children != null) {
+      for (int i = 0; i < children.length; ++i) {
+        ASTNode child = (ASTNode) getChild(i);
+        if (child != null) {
+          child = child.treeCopy();
+          tree.children[i] = child;
+          child.parent = tree;
+        }
+      }
+    }
+    return tree;
+  }
+  /** @apilevel internal 
+   * @declaredat ASTNode:124
+   */
+  protected boolean childIsNTA(int index) {
+    return super.childIsNTA(index);
+  }
+  /**
+   * @declaredat ASTNode:127
+   */
+  protected void inc_copyHandlers(Root copy) {
+    super.inc_copyHandlers(copy);
+
+  }
+  /** @apilevel internal 
+   * @declaredat ASTNode:133
+   */
+  public void reactToDependencyChange(String attrID, Object _parameters) {
+    super.reactToDependencyChange(attrID, _parameters);
+  }
+  /**
+   * @declaredat ASTNode:140
+   */
+  private boolean inc_throwAway_visited = false;
+  /** @apilevel internal 
+   * @declaredat ASTNode:142
+   */
+  public void inc_throwAway() {
+  if (inc_throwAway_visited) {
+    return;
+  }
+  inc_throwAway_visited = true;
+  inc_state = inc_GARBAGE;
+  super.inc_throwAway();
+  inc_throwAway_visited = false;
+}
+  /**
+   * @declaredat ASTNode:151
+   */
+  private boolean inc_cleanupListeners_visited = false;
+  /**
+   * @declaredat ASTNode:152
+   */
+  public void cleanupListeners() {
+  if (inc_cleanupListeners_visited) {
+    return;
+  }
+  inc_cleanupListeners_visited = true;
+  super.cleanupListeners();
+  inc_cleanupListeners_visited = false;
+}
+  /**
+   * @declaredat ASTNode:160
+   */
+  private boolean inc_cleanupListenersInTree_visited = false;
+  /**
+   * @declaredat ASTNode:161
+   */
+  public void cleanupListenersInTree() {
+  if (inc_cleanupListenersInTree_visited) {
+    return;
+  }
+  inc_cleanupListenersInTree_visited = true;
+  cleanupListeners();
+  for (int i = 0; children != null && i < children.length; i++) {
+    ASTNode child = children[i];
+    if (child == null) {
+      continue;
+    }
+    child.cleanupListenersInTree();
+  }
+  inc_cleanupListenersInTree_visited = false;
+}
+  /**
+   * Replaces the BinaryConstraint list.
+   * @param list The new list node to be used as the BinaryConstraint list.
+   * @apilevel high-level
+   */
+  public Root setBinaryConstraintList(JastAddList<BinaryConstraint> list) {
+    setChild(list, 0);
+    return this;
+  }
+  /**
+   * Retrieves the number of children in the BinaryConstraint list.
+   * @return Number of children in the BinaryConstraint list.
+   * @apilevel high-level
+   */
+  public int getNumBinaryConstraint() {
+    return getBinaryConstraintList().getNumChild();
+  }
+  /**
+   * Retrieves the number of children in the BinaryConstraint list.
+   * Calling this method will not trigger rewrites.
+   * @return Number of children in the BinaryConstraint list.
+   * @apilevel low-level
+   */
+  public int getNumBinaryConstraintNoTransform() {
+    return getBinaryConstraintListNoTransform().getNumChildNoTransform();
+  }
+  /**
+   * Retrieves the element at index {@code i} in the BinaryConstraint list.
+   * @param i Index of the element to return.
+   * @return The element at position {@code i} in the BinaryConstraint list.
+   * @apilevel high-level
+   */
+  public BinaryConstraint getBinaryConstraint(int i) {
+    return (BinaryConstraint) getBinaryConstraintList().getChild(i);
+  }
+  /**
+   * Check whether the BinaryConstraint list has any children.
+   * @return {@code true} if it has at least one child, {@code false} otherwise.
+   * @apilevel high-level
+   */
+  public boolean hasBinaryConstraint() {
+    return getBinaryConstraintList().getNumChild() != 0;
+  }
+  /**
+   * Append an element to the BinaryConstraint list.
+   * @param node The element to append to the BinaryConstraint list.
+   * @apilevel high-level
+   */
+  public Root addBinaryConstraint(BinaryConstraint node) {
+    JastAddList<BinaryConstraint> list = (parent == null) ? getBinaryConstraintListNoTransform() : getBinaryConstraintList();
+    list.addChild(node);
+    return this;
+  }
+  /** @apilevel low-level 
+   */
+  public Root addBinaryConstraintNoTransform(BinaryConstraint node) {
+    JastAddList<BinaryConstraint> list = getBinaryConstraintListNoTransform();
+    list.addChild(node);
+    return this;
+  }
+  /**
+   * Replaces the BinaryConstraint list element at index {@code i} with the new node {@code node}.
+   * @param node The new node to replace the old list element.
+   * @param i The list index of the node to be replaced.
+   * @apilevel high-level
+   */
+  public Root setBinaryConstraint(BinaryConstraint node, int i) {
+    JastAddList<BinaryConstraint> list = getBinaryConstraintList();
+    list.setChild(node, i);
+    return this;
+  }
+  /**
+   * Retrieves the BinaryConstraint list.
+   * @return The node representing the BinaryConstraint list.
+   * @apilevel high-level
+   */
+  @ASTNodeAnnotation.ListChild(name="BinaryConstraint")
+  public JastAddList<BinaryConstraint> getBinaryConstraintList() {
+    JastAddList<BinaryConstraint> list = (JastAddList<BinaryConstraint>) getChild(0);
+    return list;
+  }
+  /**
+   * Retrieves the BinaryConstraint list.
+   * <p><em>This method does not invoke AST transformations.</em></p>
+   * @return The node representing the BinaryConstraint list.
+   * @apilevel low-level
+   */
+  public JastAddList<BinaryConstraint> getBinaryConstraintListNoTransform() {
+    return (JastAddList<BinaryConstraint>) getChildNoTransform(0);
+  }
+  /**
+   * @return the element at index {@code i} in the BinaryConstraint list without
+   * triggering rewrites.
+   */
+  public BinaryConstraint getBinaryConstraintNoTransform(int i) {
+    return (BinaryConstraint) getBinaryConstraintListNoTransform().getChildNoTransform(i);
+  }
+  /**
+   * Retrieves the BinaryConstraint list.
+   * @return The node representing the BinaryConstraint list.
+   * @apilevel high-level
+   */
+  public JastAddList<BinaryConstraint> getBinaryConstraints() {
+    return getBinaryConstraintList();
+  }
+  /**
+   * Retrieves the BinaryConstraint list.
+   * <p><em>This method does not invoke AST transformations.</em></p>
+   * @return The node representing the BinaryConstraint list.
+   * @apilevel low-level
+   */
+  public JastAddList<BinaryConstraint> getBinaryConstraintsNoTransform() {
+    return getBinaryConstraintListNoTransform();
+  }
+  /**
+   * Replaces the UnaryConstraint list.
+   * @param list The new list node to be used as the UnaryConstraint list.
+   * @apilevel high-level
+   */
+  public Root setUnaryConstraintList(JastAddList<UnaryConstraint> list) {
+    setChild(list, 1);
+    return this;
+  }
+  /**
+   * Retrieves the number of children in the UnaryConstraint list.
+   * @return Number of children in the UnaryConstraint list.
+   * @apilevel high-level
+   */
+  public int getNumUnaryConstraint() {
+    return getUnaryConstraintList().getNumChild();
+  }
+  /**
+   * Retrieves the number of children in the UnaryConstraint list.
+   * Calling this method will not trigger rewrites.
+   * @return Number of children in the UnaryConstraint list.
+   * @apilevel low-level
+   */
+  public int getNumUnaryConstraintNoTransform() {
+    return getUnaryConstraintListNoTransform().getNumChildNoTransform();
+  }
+  /**
+   * Retrieves the element at index {@code i} in the UnaryConstraint list.
+   * @param i Index of the element to return.
+   * @return The element at position {@code i} in the UnaryConstraint list.
+   * @apilevel high-level
+   */
+  public UnaryConstraint getUnaryConstraint(int i) {
+    return (UnaryConstraint) getUnaryConstraintList().getChild(i);
+  }
+  /**
+   * Check whether the UnaryConstraint list has any children.
+   * @return {@code true} if it has at least one child, {@code false} otherwise.
+   * @apilevel high-level
+   */
+  public boolean hasUnaryConstraint() {
+    return getUnaryConstraintList().getNumChild() != 0;
+  }
+  /**
+   * Append an element to the UnaryConstraint list.
+   * @param node The element to append to the UnaryConstraint list.
+   * @apilevel high-level
+   */
+  public Root addUnaryConstraint(UnaryConstraint node) {
+    JastAddList<UnaryConstraint> list = (parent == null) ? getUnaryConstraintListNoTransform() : getUnaryConstraintList();
+    list.addChild(node);
+    return this;
+  }
+  /** @apilevel low-level 
+   */
+  public Root addUnaryConstraintNoTransform(UnaryConstraint node) {
+    JastAddList<UnaryConstraint> list = getUnaryConstraintListNoTransform();
+    list.addChild(node);
+    return this;
+  }
+  /**
+   * Replaces the UnaryConstraint list element at index {@code i} with the new node {@code node}.
+   * @param node The new node to replace the old list element.
+   * @param i The list index of the node to be replaced.
+   * @apilevel high-level
+   */
+  public Root setUnaryConstraint(UnaryConstraint node, int i) {
+    JastAddList<UnaryConstraint> list = getUnaryConstraintList();
+    list.setChild(node, i);
+    return this;
+  }
+  /**
+   * Retrieves the UnaryConstraint list.
+   * @return The node representing the UnaryConstraint list.
+   * @apilevel high-level
+   */
+  @ASTNodeAnnotation.ListChild(name="UnaryConstraint")
+  public JastAddList<UnaryConstraint> getUnaryConstraintList() {
+    JastAddList<UnaryConstraint> list = (JastAddList<UnaryConstraint>) getChild(1);
+    return list;
+  }
+  /**
+   * Retrieves the UnaryConstraint list.
+   * <p><em>This method does not invoke AST transformations.</em></p>
+   * @return The node representing the UnaryConstraint list.
+   * @apilevel low-level
+   */
+  public JastAddList<UnaryConstraint> getUnaryConstraintListNoTransform() {
+    return (JastAddList<UnaryConstraint>) getChildNoTransform(1);
+  }
+  /**
+   * @return the element at index {@code i} in the UnaryConstraint list without
+   * triggering rewrites.
+   */
+  public UnaryConstraint getUnaryConstraintNoTransform(int i) {
+    return (UnaryConstraint) getUnaryConstraintListNoTransform().getChildNoTransform(i);
+  }
+  /**
+   * Retrieves the UnaryConstraint list.
+   * @return The node representing the UnaryConstraint list.
+   * @apilevel high-level
+   */
+  public JastAddList<UnaryConstraint> getUnaryConstraints() {
+    return getUnaryConstraintList();
+  }
+  /**
+   * Retrieves the UnaryConstraint list.
+   * <p><em>This method does not invoke AST transformations.</em></p>
+   * @return The node representing the UnaryConstraint list.
+   * @apilevel low-level
+   */
+  public JastAddList<UnaryConstraint> getUnaryConstraintsNoTransform() {
+    return getUnaryConstraintListNoTransform();
+  }
+  /**
+   * Replaces the Atom list.
+   * @param list The new list node to be used as the Atom list.
+   * @apilevel high-level
+   */
+  public Root setAtomList(JastAddList<Atom> list) {
+    setChild(list, 2);
+    return this;
+  }
+  /**
+   * Retrieves the number of children in the Atom list.
+   * @return Number of children in the Atom list.
+   * @apilevel high-level
+   */
+  public int getNumAtom() {
+    return getAtomList().getNumChild();
+  }
+  /**
+   * Retrieves the number of children in the Atom list.
+   * Calling this method will not trigger rewrites.
+   * @return Number of children in the Atom list.
+   * @apilevel low-level
+   */
+  public int getNumAtomNoTransform() {
+    return getAtomListNoTransform().getNumChildNoTransform();
+  }
+  /**
+   * Retrieves the element at index {@code i} in the Atom list.
+   * @param i Index of the element to return.
+   * @return The element at position {@code i} in the Atom list.
+   * @apilevel high-level
+   */
+  public Atom getAtom(int i) {
+    return (Atom) getAtomList().getChild(i);
+  }
+  /**
+   * Check whether the Atom list has any children.
+   * @return {@code true} if it has at least one child, {@code false} otherwise.
+   * @apilevel high-level
+   */
+  public boolean hasAtom() {
+    return getAtomList().getNumChild() != 0;
+  }
+  /**
+   * Append an element to the Atom list.
+   * @param node The element to append to the Atom list.
+   * @apilevel high-level
+   */
+  public Root addAtom(Atom node) {
+    JastAddList<Atom> list = (parent == null) ? getAtomListNoTransform() : getAtomList();
+    list.addChild(node);
+    return this;
+  }
+  /** @apilevel low-level 
+   */
+  public Root addAtomNoTransform(Atom node) {
+    JastAddList<Atom> list = getAtomListNoTransform();
+    list.addChild(node);
+    return this;
+  }
+  /**
+   * Replaces the Atom list element at index {@code i} with the new node {@code node}.
+   * @param node The new node to replace the old list element.
+   * @param i The list index of the node to be replaced.
+   * @apilevel high-level
+   */
+  public Root setAtom(Atom node, int i) {
+    JastAddList<Atom> list = getAtomList();
+    list.setChild(node, i);
+    return this;
+  }
+  /**
+   * Retrieves the Atom list.
+   * @return The node representing the Atom list.
+   * @apilevel high-level
+   */
+  @ASTNodeAnnotation.ListChild(name="Atom")
+  public JastAddList<Atom> getAtomList() {
+    JastAddList<Atom> list = (JastAddList<Atom>) getChild(2);
+    return list;
+  }
+  /**
+   * Retrieves the Atom list.
+   * <p><em>This method does not invoke AST transformations.</em></p>
+   * @return The node representing the Atom list.
+   * @apilevel low-level
+   */
+  public JastAddList<Atom> getAtomListNoTransform() {
+    return (JastAddList<Atom>) getChildNoTransform(2);
+  }
+  /**
+   * @return the element at index {@code i} in the Atom list without
+   * triggering rewrites.
+   */
+  public Atom getAtomNoTransform(int i) {
+    return (Atom) getAtomListNoTransform().getChildNoTransform(i);
+  }
+  /**
+   * Retrieves the Atom list.
+   * @return The node representing the Atom list.
+   * @apilevel high-level
+   */
+  public JastAddList<Atom> getAtoms() {
+    return getAtomList();
+  }
+  /**
+   * Retrieves the Atom list.
+   * <p><em>This method does not invoke AST transformations.</em></p>
+   * @return The node representing the Atom list.
+   * @apilevel low-level
+   */
+  public JastAddList<Atom> getAtomsNoTransform() {
+    return getAtomListNoTransform();
+  }
+  /** @apilevel internal */
+  public ASTNode rewriteTo() {
+    return super.rewriteTo();
+  }
+  /** @apilevel internal */
+  public boolean canRewrite() {
+    return false;
+  }
+
+}
diff --git a/src/gen/java/org/jastadd/ag/ast/TnoDisk.java b/src/gen/java/org/jastadd/ag/ast/TnoDisk.java
new file mode 100644
index 0000000000000000000000000000000000000000..d9317a470003eab936d15333cfd0d8cc24c3429b
--- /dev/null
+++ b/src/gen/java/org/jastadd/ag/ast/TnoDisk.java
@@ -0,0 +1,385 @@
+/* This file was generated with JastAdd2 (http://jastadd.org) version 2.3.5 */
+package org.jastadd.ag.ast;
+import java.util.*;
+/**
+ * @ast node
+ * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\ag.ast:13
+ * @astdecl TnoDisk : Atom ::= <_impl_Rel:java.util.List<Pillar>>;
+ * @production TnoDisk : {@link Atom};
+
+ */
+public class TnoDisk extends Atom implements Cloneable {
+  /**
+   * @aspect ReferenceCreation
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:147
+   */
+  public static TnoDisk createRef(String ref) {
+    Unresolved$TnoDisk unresolvedNode = new Unresolved$TnoDisk();
+    unresolvedNode.setUnresolved$Token(ref);
+    unresolvedNode.setUnresolved$ResolveOpposite(true);
+    return unresolvedNode;
+  }
+  /**
+   * @aspect ReferenceCreation
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:153
+   */
+  public static TnoDisk createRefDirection(String ref) {
+    Unresolved$TnoDisk unresolvedNode = new Unresolved$TnoDisk();
+    unresolvedNode.setUnresolved$Token(ref);
+    unresolvedNode.setUnresolved$ResolveOpposite(false);
+    return unresolvedNode;
+  }
+  /**
+   * @aspect ResolverTrigger
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:277
+   */
+  public void resolveAll() {
+    super.resolveAll();
+  }
+  /**
+   * @aspect RefResolverHelpers
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:657
+   */
+  Unresolved$Node$Interface as$Unresolved() {
+    return null;
+  }
+  /**
+   * @aspect RefResolverHelpers
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:663
+   */
+  boolean is$Unresolved() {
+    return false;
+  }
+  /**
+   * @declaredat ASTNode:1
+   */
+  public TnoDisk() {
+    super();
+  }
+  /**
+   * Initializes the child array to the correct size.
+   * Initializes List and Opt nta children.
+   * @apilevel internal
+   * @ast method
+   * @declaredat ASTNode:10
+   */
+  public void init$Children() {
+    state().enterConstruction();
+    state().exitConstruction();
+  }
+  /**
+   * @declaredat ASTNode:14
+   */
+  @ASTNodeAnnotation.Constructor(
+    name = {"_impl_Rel"},
+    type = {"java.util.List<Pillar>"},
+    kind = {"Token"}
+  )
+  public TnoDisk(java.util.List<Pillar> p0) {
+state().enterConstruction();
+    set_impl_Rel(p0);
+state().exitConstruction();
+  }
+  /** @apilevel low-level 
+   * @declaredat ASTNode:25
+   */
+  protected int numChildren() {
+    
+    state().addHandlerDepTo(numChildren_handler);
+    return 0;
+  }
+  /**
+   * @apilevel internal
+   * @declaredat ASTNode:33
+   */
+  public boolean mayHaveRewrite() {
+    return false;
+  }
+  /** @apilevel internal 
+   * @declaredat ASTNode:37
+   */
+  public void flushAttrCache() {
+  }
+  /** @apilevel internal 
+   * @declaredat ASTNode:40
+   */
+  public void flushCollectionCache() {
+  }
+  /** @apilevel internal 
+   * @declaredat ASTNode:43
+   */
+  public TnoDisk clone() throws CloneNotSupportedException {
+    TnoDisk node = (TnoDisk) super.clone();
+    return node;
+  }
+  /** @apilevel internal 
+   * @declaredat ASTNode:48
+   */
+  public TnoDisk copy() {
+    try {
+      TnoDisk node = (TnoDisk) clone();
+      node.parent = null;
+      if (children != null) {
+        node.children = (ASTNode[]) children.clone();
+      }
+      node.inc_state = inc_CLONED;
+      for (int i = 0; node.children != null && i < node.children.length; i++) {
+        node.children[i] = null;
+      }
+      inc_copyHandlers(node);
+      return node;
+    } catch (CloneNotSupportedException e) {
+      throw new Error("Error: clone not supported for " + getClass().getName());
+    }
+  }
+  /**
+   * Create a deep copy of the AST subtree at this node.
+   * The copy is dangling, i.e. has no parent.
+   * @return dangling copy of the subtree at this node
+   * @apilevel low-level
+   * @deprecated Please use treeCopy or treeCopyNoTransform instead
+   * @declaredat ASTNode:72
+   */
+  @Deprecated
+  public TnoDisk fullCopy() {
+    return treeCopyNoTransform();
+  }
+  /**
+   * Create a deep copy of the AST subtree at this node.
+   * The copy is dangling, i.e. has no parent.
+   * @return dangling copy of the subtree at this node
+   * @apilevel low-level
+   * @declaredat ASTNode:82
+   */
+  public TnoDisk treeCopyNoTransform() {
+    TnoDisk tree = (TnoDisk) copy();
+    if (children != null) {
+      for (int i = 0; i < children.length; ++i) {
+        ASTNode child = (ASTNode) children[i];
+        if (child != null) {
+          child = child.treeCopyNoTransform();
+          tree.children[i] = child;
+          child.parent = tree;
+        }
+      }
+    }
+    return tree;
+  }
+  /**
+   * Create a deep copy of the AST subtree at this node.
+   * The subtree of this node is traversed to trigger rewrites before copy.
+   * The copy is dangling, i.e. has no parent.
+   * @return dangling copy of the subtree at this node
+   * @apilevel low-level
+   * @declaredat ASTNode:103
+   */
+  public TnoDisk treeCopy() {
+    TnoDisk tree = (TnoDisk) copy();
+    if (children != null) {
+      for (int i = 0; i < children.length; ++i) {
+        ASTNode child = (ASTNode) getChild(i);
+        if (child != null) {
+          child = child.treeCopy();
+          tree.children[i] = child;
+          child.parent = tree;
+        }
+      }
+    }
+    return tree;
+  }
+  /** @apilevel internal 
+   * @declaredat ASTNode:118
+   */
+  protected boolean childIsNTA(int index) {
+    return super.childIsNTA(index);
+  }
+  /**
+   * @declaredat ASTNode:121
+   */
+  protected ASTNode$DepGraphNode eval_handler;
+  /**
+   * @declaredat ASTNode:122
+   */
+  protected void inc_copyHandlers(TnoDisk copy) {
+    super.inc_copyHandlers(copy);
+
+        if (eval_handler != null) {
+          copy.eval_handler = ASTNode$DepGraphNode.createAttrHandler(eval_handler, copy);
+        }
+  }
+  /** @apilevel internal 
+   * @declaredat ASTNode:131
+   */
+  public void reactToDependencyChange(String attrID, Object _parameters) {
+    super.reactToDependencyChange(attrID, _parameters);
+  }
+  /**
+   * @declaredat ASTNode:138
+   */
+  private boolean inc_throwAway_visited = false;
+  /** @apilevel internal 
+   * @declaredat ASTNode:140
+   */
+  public void inc_throwAway() {
+  if (inc_throwAway_visited) {
+    return;
+  }
+  inc_throwAway_visited = true;
+  inc_state = inc_GARBAGE;
+  super.inc_throwAway();
+  if (eval_handler != null) {
+    eval_handler.throwAway();
+  }
+  inc_throwAway_visited = false;
+}
+  /**
+   * @declaredat ASTNode:152
+   */
+  private boolean inc_cleanupListeners_visited = false;
+  /**
+   * @declaredat ASTNode:153
+   */
+  public void cleanupListeners() {
+  if (inc_cleanupListeners_visited) {
+    return;
+  }
+  inc_cleanupListeners_visited = true;
+  if (get_impl_Rel_handler != null) {
+    get_impl_Rel_handler.cleanupListeners();
+  }
+  if (eval_handler != null) {
+    eval_handler.cleanupListeners();
+  }
+  super.cleanupListeners();
+  inc_cleanupListeners_visited = false;
+}
+  /**
+   * @declaredat ASTNode:167
+   */
+  private boolean inc_cleanupListenersInTree_visited = false;
+  /**
+   * @declaredat ASTNode:168
+   */
+  public void cleanupListenersInTree() {
+  if (inc_cleanupListenersInTree_visited) {
+    return;
+  }
+  inc_cleanupListenersInTree_visited = true;
+  cleanupListeners();
+  for (int i = 0; children != null && i < children.length; i++) {
+    ASTNode child = children[i];
+    if (child == null) {
+      continue;
+    }
+    child.cleanupListenersInTree();
+  }
+  inc_cleanupListenersInTree_visited = false;
+}
+  /**
+   */
+  protected ASTNode$DepGraphNode get_impl_Rel_handler = ASTNode$DepGraphNode.createAstHandler(this, "get_impl_Rel", null);
+  /**
+   * Replaces the lexeme _impl_Rel.
+   * @param value The new value for the lexeme _impl_Rel.
+   * @apilevel high-level
+   */
+  public TnoDisk set_impl_Rel(java.util.List<Pillar> value) {
+    tokenjava_util_List_Pillar___impl_Rel = value;
+    
+    if (state().disableDeps == 0 && !state().IN_ATTR_STORE_EVAL) {
+      get_impl_Rel_handler.notifyDependencies();
+    
+    
+    
+    
+    }
+    return this;
+  }
+  /**
+   * Retrieves the value for the lexeme _impl_Rel.
+   * @return The value for the lexeme _impl_Rel.
+   * @apilevel high-level
+   */
+  @ASTNodeAnnotation.Token(name="_impl_Rel")
+  public java.util.List<Pillar> get_impl_Rel() {
+    
+    state().addHandlerDepTo(get_impl_Rel_handler);
+    return tokenjava_util_List_Pillar___impl_Rel;
+  }
+  /** @apilevel internal */
+  private void eval_reset() {
+    state().trace().flushAttr(this, "Constraint.eval()", "", eval_value);
+    eval_computed = null;
+  }
+  /** @apilevel internal */
+  protected ASTState.Cycle eval_computed = null;
+
+  /** @apilevel internal */
+  protected boolean eval_value;
+
+  /**
+   * @attribute syn
+   * @aspect Constraints
+   * @declaredat E:\\project\\20211201\\src\\main\\jastadd\\hanoi\\Constraints.jrag:32
+   */
+  @ASTNodeAnnotation.Attribute(kind=ASTNodeAnnotation.Kind.SYN)
+  @ASTNodeAnnotation.Source(aspect="Constraints", declaredAt="E:\\project\\20211201\\src\\main\\jastadd\\hanoi\\Constraints.jrag:3")
+  public boolean eval() {
+    ASTState state = state();
+    
+    if (eval_handler == null) {
+      eval_handler = new ASTNode$DepGraphNode(this, "eval", null, ASTNode.inc_EMPTY) {
+        @Override public void reactToDependencyChange() {
+          {
+            eval_computed = null;
+            eval_handler.notifyDependencies();
+            TnoDisk.this.state().trace().flushIncAttr(TnoDisk.this, "eval", "", "");
+          }
+        }
+      };
+    }
+    state().addHandlerDepTo(eval_handler);
+    
+    
+    
+    
+    
+    if (eval_computed == ASTState.NON_CYCLE || eval_computed == state().cycle()) {
+      state().trace().cacheRead(this, "Constraint.eval()", "", eval_value);
+      return eval_value;
+    }
+    
+    state().enterAttrStoreEval(eval_handler);
+    eval_value = eval_compute();
+    if (state().inCircle()) {
+      eval_computed = state().cycle();
+      state().trace().cacheWrite(this, "Constraint.eval()", "", eval_value);
+    } else {
+      eval_computed = ASTState.NON_CYCLE;
+      state().trace().cacheWrite(this, "Constraint.eval()", "", eval_value);
+    }
+    
+    state().exitAttrStoreEval(eval_handler);
+    
+    
+    
+    
+    
+    
+    return eval_value;
+  }
+  /** @apilevel internal */
+  private boolean eval_compute() {
+          //the target pillar is empty?
+          return this.getRels().get(0).getNumDisk()==0;
+      }
+  /** @apilevel internal */
+  public ASTNode rewriteTo() {
+    return super.rewriteTo();
+  }
+  /** @apilevel internal */
+  public boolean canRewrite() {
+    return false;
+  }
+
+}
diff --git a/src/gen/java/org/jastadd/ag/ast/UnaryConstraint.java b/src/gen/java/org/jastadd/ag/ast/UnaryConstraint.java
new file mode 100644
index 0000000000000000000000000000000000000000..0cb423a38c7ed3d247301ebb932361829c778f23
--- /dev/null
+++ b/src/gen/java/org/jastadd/ag/ast/UnaryConstraint.java
@@ -0,0 +1,251 @@
+/* This file was generated with JastAdd2 (http://jastadd.org) version 2.3.5 */
+package org.jastadd.ag.ast;
+import java.util.*;
+/**
+ * @ast node
+ * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\ag.ast:4
+ * @astdecl UnaryConstraint : Constraint ::= Constraint;
+ * @production UnaryConstraint : {@link Constraint} ::= <span class="component">{@link Constraint}</span>;
+
+ */
+public abstract class UnaryConstraint extends Constraint implements Cloneable {
+  /**
+   * @aspect ReferenceCreation
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:39
+   */
+  public static UnaryConstraint createRef(String ref) {
+    Unresolved$Negation unresolvedNode = new Unresolved$Negation();
+    unresolvedNode.setUnresolved$Token(ref);
+    unresolvedNode.setUnresolved$ResolveOpposite(true);
+    return unresolvedNode;
+  }
+  /**
+   * @aspect ReferenceCreation
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:45
+   */
+  public static UnaryConstraint createRefDirection(String ref) {
+    Unresolved$Negation unresolvedNode = new Unresolved$Negation();
+    unresolvedNode.setUnresolved$Token(ref);
+    unresolvedNode.setUnresolved$ResolveOpposite(false);
+    return unresolvedNode;
+  }
+  /**
+   * @aspect ResolverTrigger
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:241
+   */
+  public void resolveAll() {
+    super.resolveAll();
+  }
+  /**
+   * @aspect RefResolverHelpers
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:405
+   */
+  Unresolved$Node$Interface as$Unresolved() {
+    return null;
+  }
+  /**
+   * @aspect RefResolverHelpers
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:411
+   */
+  boolean is$Unresolved() {
+    return false;
+  }
+  /**
+   * @declaredat ASTNode:1
+   */
+  public UnaryConstraint() {
+    super();
+  }
+  /**
+   * Initializes the child array to the correct size.
+   * Initializes List and Opt nta children.
+   * @apilevel internal
+   * @ast method
+   * @declaredat ASTNode:10
+   */
+  public void init$Children() {
+    children = new ASTNode[1];  getChild_handler = new ASTNode$DepGraphNode[children.length];
+    state().enterConstruction();
+    state().exitConstruction();
+  }
+  /**
+   * @declaredat ASTNode:15
+   */
+  @ASTNodeAnnotation.Constructor(
+    name = {"Constraint"},
+    type = {"Constraint"},
+    kind = {"Child"}
+  )
+  public UnaryConstraint(Constraint p0) {
+state().enterConstruction();
+    setChild(p0, 0);
+state().exitConstruction();
+  }
+  /** @apilevel low-level 
+   * @declaredat ASTNode:26
+   */
+  protected int numChildren() {
+    
+    state().addHandlerDepTo(numChildren_handler);
+    return 1;
+  }
+  /**
+   * @apilevel internal
+   * @declaredat ASTNode:34
+   */
+  public boolean mayHaveRewrite() {
+    return false;
+  }
+  /** @apilevel internal 
+   * @declaredat ASTNode:38
+   */
+  public void flushAttrCache() {
+  }
+  /** @apilevel internal 
+   * @declaredat ASTNode:41
+   */
+  public void flushCollectionCache() {
+  }
+  /** @apilevel internal 
+   * @declaredat ASTNode:44
+   */
+  public UnaryConstraint clone() throws CloneNotSupportedException {
+    UnaryConstraint node = (UnaryConstraint) super.clone();
+    return node;
+  }
+  /**
+   * Create a deep copy of the AST subtree at this node.
+   * The copy is dangling, i.e. has no parent.
+   * @return dangling copy of the subtree at this node
+   * @apilevel low-level
+   * @deprecated Please use treeCopy or treeCopyNoTransform instead
+   * @declaredat ASTNode:55
+   */
+  @Deprecated
+  public abstract UnaryConstraint fullCopy();
+  /**
+   * Create a deep copy of the AST subtree at this node.
+   * The copy is dangling, i.e. has no parent.
+   * @return dangling copy of the subtree at this node
+   * @apilevel low-level
+   * @declaredat ASTNode:63
+   */
+  public abstract UnaryConstraint treeCopyNoTransform();
+  /**
+   * Create a deep copy of the AST subtree at this node.
+   * The subtree of this node is traversed to trigger rewrites before copy.
+   * The copy is dangling, i.e. has no parent.
+   * @return dangling copy of the subtree at this node
+   * @apilevel low-level
+   * @declaredat ASTNode:71
+   */
+  public abstract UnaryConstraint treeCopy();
+  /** @apilevel internal 
+   * @declaredat ASTNode:73
+   */
+  protected boolean childIsNTA(int index) {
+    return super.childIsNTA(index);
+  }
+  /**
+   * @declaredat ASTNode:76
+   */
+  protected void inc_copyHandlers(UnaryConstraint copy) {
+    super.inc_copyHandlers(copy);
+
+  }
+  /** @apilevel internal 
+   * @declaredat ASTNode:82
+   */
+  public void reactToDependencyChange(String attrID, Object _parameters) {
+    super.reactToDependencyChange(attrID, _parameters);
+  }
+  /**
+   * @declaredat ASTNode:89
+   */
+  private boolean inc_throwAway_visited = false;
+  /** @apilevel internal 
+   * @declaredat ASTNode:91
+   */
+  public void inc_throwAway() {
+  if (inc_throwAway_visited) {
+    return;
+  }
+  inc_throwAway_visited = true;
+  inc_state = inc_GARBAGE;
+  super.inc_throwAway();
+  inc_throwAway_visited = false;
+}
+  /**
+   * @declaredat ASTNode:100
+   */
+  private boolean inc_cleanupListeners_visited = false;
+  /**
+   * @declaredat ASTNode:101
+   */
+  public void cleanupListeners() {
+  if (inc_cleanupListeners_visited) {
+    return;
+  }
+  inc_cleanupListeners_visited = true;
+  super.cleanupListeners();
+  inc_cleanupListeners_visited = false;
+}
+  /**
+   * @declaredat ASTNode:109
+   */
+  private boolean inc_cleanupListenersInTree_visited = false;
+  /**
+   * @declaredat ASTNode:110
+   */
+  public void cleanupListenersInTree() {
+  if (inc_cleanupListenersInTree_visited) {
+    return;
+  }
+  inc_cleanupListenersInTree_visited = true;
+  cleanupListeners();
+  for (int i = 0; children != null && i < children.length; i++) {
+    ASTNode child = children[i];
+    if (child == null) {
+      continue;
+    }
+    child.cleanupListenersInTree();
+  }
+  inc_cleanupListenersInTree_visited = false;
+}
+  /**
+   * Replaces the Constraint child.
+   * @param node The new node to replace the Constraint child.
+   * @apilevel high-level
+   */
+  public UnaryConstraint setConstraint(Constraint node) {
+    setChild(node, 0);
+    return this;
+  }
+  /**
+   * Retrieves the Constraint child.
+   * @return The current node used as the Constraint child.
+   * @apilevel high-level
+   */
+  @ASTNodeAnnotation.Child(name="Constraint")
+  public Constraint getConstraint() {
+    return (Constraint) getChild(0);
+  }
+  /**
+   * Retrieves the Constraint child.
+   * <p><em>This method does not invoke AST transformations.</em></p>
+   * @return The current node used as the Constraint child.
+   * @apilevel low-level
+   */
+  public Constraint getConstraintNoTransform() {
+    return (Constraint) getChildNoTransform(0);
+  }
+  /** @apilevel internal */
+  public ASTNode rewriteTo() {
+    return super.rewriteTo();
+  }
+  /** @apilevel internal */
+  public boolean canRewrite() {
+    return false;
+  }
+
+}
diff --git a/src/gen/java/org/jastadd/ag/ast/Unresolved$Atom.java b/src/gen/java/org/jastadd/ag/ast/Unresolved$Atom.java
new file mode 100644
index 0000000000000000000000000000000000000000..837afa49c1f72c0a9ad264c7167c5f9c17389898
--- /dev/null
+++ b/src/gen/java/org/jastadd/ag/ast/Unresolved$Atom.java
@@ -0,0 +1,69 @@
+package org.jastadd.ag.ast;
+
+import java.util.*;
+/**
+ * @ast class
+ * @aspect RefResolverHelpers
+ * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:361
+ */
+abstract class Unresolved$Atom extends Atom implements Unresolved$Node$Interface {
+  /**
+   * @aspect RefResolverHelpers
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:362
+   */
+  
+    private String unresolved$Token;
+  /**
+   * @aspect RefResolverHelpers
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:363
+   */
+  
+    public String getUnresolved$Token() {
+      return unresolved$Token;
+    }
+  /**
+   * @aspect RefResolverHelpers
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:366
+   */
+  
+    void setUnresolved$Token(String token) {
+      this.unresolved$Token = token;
+    }
+  /**
+   * @aspect RefResolverHelpers
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:369
+   */
+  
+    private boolean unresolved$ResolveOpposite;
+  /**
+   * @aspect RefResolverHelpers
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:370
+   */
+  
+    public boolean getUnresolved$ResolveOpposite() {
+      return unresolved$ResolveOpposite;
+    }
+  /**
+   * @aspect RefResolverHelpers
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:373
+   */
+  
+    void setUnresolved$ResolveOpposite(boolean resolveOpposite) {
+      this.unresolved$ResolveOpposite = resolveOpposite;
+    }
+  /**
+   * @aspect RefResolverHelpers
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:380
+   */
+  Unresolved$Node$Interface as$Unresolved() {
+    return this;
+  }
+  /**
+   * @aspect RefResolverHelpers
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:386
+   */
+  boolean is$Unresolved() {
+    return true;
+  }
+
+}
diff --git a/src/gen/java/org/jastadd/ag/ast/Unresolved$BinaryConstraint.java b/src/gen/java/org/jastadd/ag/ast/Unresolved$BinaryConstraint.java
new file mode 100644
index 0000000000000000000000000000000000000000..87cdaac6260ec1a9d912c71505c5064709ee103b
--- /dev/null
+++ b/src/gen/java/org/jastadd/ag/ast/Unresolved$BinaryConstraint.java
@@ -0,0 +1,69 @@
+package org.jastadd.ag.ast;
+
+import java.util.*;
+/**
+ * @ast class
+ * @aspect RefResolverHelpers
+ * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:417
+ */
+abstract class Unresolved$BinaryConstraint extends BinaryConstraint implements Unresolved$Node$Interface {
+  /**
+   * @aspect RefResolverHelpers
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:418
+   */
+  
+    private String unresolved$Token;
+  /**
+   * @aspect RefResolverHelpers
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:419
+   */
+  
+    public String getUnresolved$Token() {
+      return unresolved$Token;
+    }
+  /**
+   * @aspect RefResolverHelpers
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:422
+   */
+  
+    void setUnresolved$Token(String token) {
+      this.unresolved$Token = token;
+    }
+  /**
+   * @aspect RefResolverHelpers
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:425
+   */
+  
+    private boolean unresolved$ResolveOpposite;
+  /**
+   * @aspect RefResolverHelpers
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:426
+   */
+  
+    public boolean getUnresolved$ResolveOpposite() {
+      return unresolved$ResolveOpposite;
+    }
+  /**
+   * @aspect RefResolverHelpers
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:429
+   */
+  
+    void setUnresolved$ResolveOpposite(boolean resolveOpposite) {
+      this.unresolved$ResolveOpposite = resolveOpposite;
+    }
+  /**
+   * @aspect RefResolverHelpers
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:436
+   */
+  Unresolved$Node$Interface as$Unresolved() {
+    return this;
+  }
+  /**
+   * @aspect RefResolverHelpers
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:442
+   */
+  boolean is$Unresolved() {
+    return true;
+  }
+
+}
diff --git a/src/gen/java/org/jastadd/ag/ast/Unresolved$CheckD0.java b/src/gen/java/org/jastadd/ag/ast/Unresolved$CheckD0.java
new file mode 100644
index 0000000000000000000000000000000000000000..0686a4c72136983479d4155a65bba6cb949c25ff
--- /dev/null
+++ b/src/gen/java/org/jastadd/ag/ast/Unresolved$CheckD0.java
@@ -0,0 +1,69 @@
+package org.jastadd.ag.ast;
+
+import java.util.*;
+/**
+ * @ast class
+ * @aspect RefResolverHelpers
+ * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:669
+ */
+ class Unresolved$CheckD0 extends CheckD0 implements Unresolved$Node$Interface {
+  /**
+   * @aspect RefResolverHelpers
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:670
+   */
+  
+    private String unresolved$Token;
+  /**
+   * @aspect RefResolverHelpers
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:671
+   */
+  
+    public String getUnresolved$Token() {
+      return unresolved$Token;
+    }
+  /**
+   * @aspect RefResolverHelpers
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:674
+   */
+  
+    void setUnresolved$Token(String token) {
+      this.unresolved$Token = token;
+    }
+  /**
+   * @aspect RefResolverHelpers
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:677
+   */
+  
+    private boolean unresolved$ResolveOpposite;
+  /**
+   * @aspect RefResolverHelpers
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:678
+   */
+  
+    public boolean getUnresolved$ResolveOpposite() {
+      return unresolved$ResolveOpposite;
+    }
+  /**
+   * @aspect RefResolverHelpers
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:681
+   */
+  
+    void setUnresolved$ResolveOpposite(boolean resolveOpposite) {
+      this.unresolved$ResolveOpposite = resolveOpposite;
+    }
+  /**
+   * @aspect RefResolverHelpers
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:688
+   */
+  Unresolved$Node$Interface as$Unresolved() {
+    return this;
+  }
+  /**
+   * @aspect RefResolverHelpers
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:694
+   */
+  boolean is$Unresolved() {
+    return true;
+  }
+
+}
diff --git a/src/gen/java/org/jastadd/ag/ast/Unresolved$CheckSeq.java b/src/gen/java/org/jastadd/ag/ast/Unresolved$CheckSeq.java
new file mode 100644
index 0000000000000000000000000000000000000000..9e7972106d6faa926d84de3c1e3f320d8a7ae8bf
--- /dev/null
+++ b/src/gen/java/org/jastadd/ag/ast/Unresolved$CheckSeq.java
@@ -0,0 +1,69 @@
+package org.jastadd.ag.ast;
+
+import java.util.*;
+/**
+ * @ast class
+ * @aspect RefResolverHelpers
+ * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:585
+ */
+ class Unresolved$CheckSeq extends CheckSeq implements Unresolved$Node$Interface {
+  /**
+   * @aspect RefResolverHelpers
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:586
+   */
+  
+    private String unresolved$Token;
+  /**
+   * @aspect RefResolverHelpers
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:587
+   */
+  
+    public String getUnresolved$Token() {
+      return unresolved$Token;
+    }
+  /**
+   * @aspect RefResolverHelpers
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:590
+   */
+  
+    void setUnresolved$Token(String token) {
+      this.unresolved$Token = token;
+    }
+  /**
+   * @aspect RefResolverHelpers
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:593
+   */
+  
+    private boolean unresolved$ResolveOpposite;
+  /**
+   * @aspect RefResolverHelpers
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:594
+   */
+  
+    public boolean getUnresolved$ResolveOpposite() {
+      return unresolved$ResolveOpposite;
+    }
+  /**
+   * @aspect RefResolverHelpers
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:597
+   */
+  
+    void setUnresolved$ResolveOpposite(boolean resolveOpposite) {
+      this.unresolved$ResolveOpposite = resolveOpposite;
+    }
+  /**
+   * @aspect RefResolverHelpers
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:604
+   */
+  Unresolved$Node$Interface as$Unresolved() {
+    return this;
+  }
+  /**
+   * @aspect RefResolverHelpers
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:610
+   */
+  boolean is$Unresolved() {
+    return true;
+  }
+
+}
diff --git a/src/gen/java/org/jastadd/ag/ast/Unresolved$CheckSize.java b/src/gen/java/org/jastadd/ag/ast/Unresolved$CheckSize.java
new file mode 100644
index 0000000000000000000000000000000000000000..e69f1e782723675d7471a8767a1d3d6464d482bd
--- /dev/null
+++ b/src/gen/java/org/jastadd/ag/ast/Unresolved$CheckSize.java
@@ -0,0 +1,69 @@
+package org.jastadd.ag.ast;
+
+import java.util.*;
+/**
+ * @ast class
+ * @aspect RefResolverHelpers
+ * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:557
+ */
+ class Unresolved$CheckSize extends CheckSize implements Unresolved$Node$Interface {
+  /**
+   * @aspect RefResolverHelpers
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:558
+   */
+  
+    private String unresolved$Token;
+  /**
+   * @aspect RefResolverHelpers
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:559
+   */
+  
+    public String getUnresolved$Token() {
+      return unresolved$Token;
+    }
+  /**
+   * @aspect RefResolverHelpers
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:562
+   */
+  
+    void setUnresolved$Token(String token) {
+      this.unresolved$Token = token;
+    }
+  /**
+   * @aspect RefResolverHelpers
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:565
+   */
+  
+    private boolean unresolved$ResolveOpposite;
+  /**
+   * @aspect RefResolverHelpers
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:566
+   */
+  
+    public boolean getUnresolved$ResolveOpposite() {
+      return unresolved$ResolveOpposite;
+    }
+  /**
+   * @aspect RefResolverHelpers
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:569
+   */
+  
+    void setUnresolved$ResolveOpposite(boolean resolveOpposite) {
+      this.unresolved$ResolveOpposite = resolveOpposite;
+    }
+  /**
+   * @aspect RefResolverHelpers
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:576
+   */
+  Unresolved$Node$Interface as$Unresolved() {
+    return this;
+  }
+  /**
+   * @aspect RefResolverHelpers
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:582
+   */
+  boolean is$Unresolved() {
+    return true;
+  }
+
+}
diff --git a/src/gen/java/org/jastadd/ag/ast/Unresolved$Conjunction.java b/src/gen/java/org/jastadd/ag/ast/Unresolved$Conjunction.java
new file mode 100644
index 0000000000000000000000000000000000000000..5b2025f0c99ec6272f895c0fac9216b481921466
--- /dev/null
+++ b/src/gen/java/org/jastadd/ag/ast/Unresolved$Conjunction.java
@@ -0,0 +1,69 @@
+package org.jastadd.ag.ast;
+
+import java.util.*;
+/**
+ * @ast class
+ * @aspect RefResolverHelpers
+ * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:445
+ */
+ class Unresolved$Conjunction extends Conjunction implements Unresolved$Node$Interface {
+  /**
+   * @aspect RefResolverHelpers
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:446
+   */
+  
+    private String unresolved$Token;
+  /**
+   * @aspect RefResolverHelpers
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:447
+   */
+  
+    public String getUnresolved$Token() {
+      return unresolved$Token;
+    }
+  /**
+   * @aspect RefResolverHelpers
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:450
+   */
+  
+    void setUnresolved$Token(String token) {
+      this.unresolved$Token = token;
+    }
+  /**
+   * @aspect RefResolverHelpers
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:453
+   */
+  
+    private boolean unresolved$ResolveOpposite;
+  /**
+   * @aspect RefResolverHelpers
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:454
+   */
+  
+    public boolean getUnresolved$ResolveOpposite() {
+      return unresolved$ResolveOpposite;
+    }
+  /**
+   * @aspect RefResolverHelpers
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:457
+   */
+  
+    void setUnresolved$ResolveOpposite(boolean resolveOpposite) {
+      this.unresolved$ResolveOpposite = resolveOpposite;
+    }
+  /**
+   * @aspect RefResolverHelpers
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:464
+   */
+  Unresolved$Node$Interface as$Unresolved() {
+    return this;
+  }
+  /**
+   * @aspect RefResolverHelpers
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:470
+   */
+  boolean is$Unresolved() {
+    return true;
+  }
+
+}
diff --git a/src/gen/java/org/jastadd/ag/ast/Unresolved$Constraint.java b/src/gen/java/org/jastadd/ag/ast/Unresolved$Constraint.java
new file mode 100644
index 0000000000000000000000000000000000000000..36c4f015bc381e1dacbe9d667a90b9b3ca78d3ae
--- /dev/null
+++ b/src/gen/java/org/jastadd/ag/ast/Unresolved$Constraint.java
@@ -0,0 +1,69 @@
+package org.jastadd.ag.ast;
+
+import java.util.*;
+/**
+ * @ast class
+ * @aspect RefResolverHelpers
+ * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:333
+ */
+abstract class Unresolved$Constraint extends Constraint implements Unresolved$Node$Interface {
+  /**
+   * @aspect RefResolverHelpers
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:334
+   */
+  
+    private String unresolved$Token;
+  /**
+   * @aspect RefResolverHelpers
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:335
+   */
+  
+    public String getUnresolved$Token() {
+      return unresolved$Token;
+    }
+  /**
+   * @aspect RefResolverHelpers
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:338
+   */
+  
+    void setUnresolved$Token(String token) {
+      this.unresolved$Token = token;
+    }
+  /**
+   * @aspect RefResolverHelpers
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:341
+   */
+  
+    private boolean unresolved$ResolveOpposite;
+  /**
+   * @aspect RefResolverHelpers
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:342
+   */
+  
+    public boolean getUnresolved$ResolveOpposite() {
+      return unresolved$ResolveOpposite;
+    }
+  /**
+   * @aspect RefResolverHelpers
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:345
+   */
+  
+    void setUnresolved$ResolveOpposite(boolean resolveOpposite) {
+      this.unresolved$ResolveOpposite = resolveOpposite;
+    }
+  /**
+   * @aspect RefResolverHelpers
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:352
+   */
+  Unresolved$Node$Interface as$Unresolved() {
+    return this;
+  }
+  /**
+   * @aspect RefResolverHelpers
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:358
+   */
+  boolean is$Unresolved() {
+    return true;
+  }
+
+}
diff --git a/src/gen/java/org/jastadd/ag/ast/Unresolved$Disjunction.java b/src/gen/java/org/jastadd/ag/ast/Unresolved$Disjunction.java
new file mode 100644
index 0000000000000000000000000000000000000000..c472bc403979e372a75a921207ca398e6064c686
--- /dev/null
+++ b/src/gen/java/org/jastadd/ag/ast/Unresolved$Disjunction.java
@@ -0,0 +1,69 @@
+package org.jastadd.ag.ast;
+
+import java.util.*;
+/**
+ * @ast class
+ * @aspect RefResolverHelpers
+ * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:473
+ */
+ class Unresolved$Disjunction extends Disjunction implements Unresolved$Node$Interface {
+  /**
+   * @aspect RefResolverHelpers
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:474
+   */
+  
+    private String unresolved$Token;
+  /**
+   * @aspect RefResolverHelpers
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:475
+   */
+  
+    public String getUnresolved$Token() {
+      return unresolved$Token;
+    }
+  /**
+   * @aspect RefResolverHelpers
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:478
+   */
+  
+    void setUnresolved$Token(String token) {
+      this.unresolved$Token = token;
+    }
+  /**
+   * @aspect RefResolverHelpers
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:481
+   */
+  
+    private boolean unresolved$ResolveOpposite;
+  /**
+   * @aspect RefResolverHelpers
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:482
+   */
+  
+    public boolean getUnresolved$ResolveOpposite() {
+      return unresolved$ResolveOpposite;
+    }
+  /**
+   * @aspect RefResolverHelpers
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:485
+   */
+  
+    void setUnresolved$ResolveOpposite(boolean resolveOpposite) {
+      this.unresolved$ResolveOpposite = resolveOpposite;
+    }
+  /**
+   * @aspect RefResolverHelpers
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:492
+   */
+  Unresolved$Node$Interface as$Unresolved() {
+    return this;
+  }
+  /**
+   * @aspect RefResolverHelpers
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:498
+   */
+  boolean is$Unresolved() {
+    return true;
+  }
+
+}
diff --git a/src/gen/java/org/jastadd/ag/ast/Unresolved$Disk.java b/src/gen/java/org/jastadd/ag/ast/Unresolved$Disk.java
new file mode 100644
index 0000000000000000000000000000000000000000..18e5cfb19025a4d6c68fea96b02206bb87baa6f7
--- /dev/null
+++ b/src/gen/java/org/jastadd/ag/ast/Unresolved$Disk.java
@@ -0,0 +1,69 @@
+package org.jastadd.ag.ast;
+
+import java.util.*;
+/**
+ * @ast class
+ * @aspect RefResolverHelpers
+ * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:725
+ */
+ class Unresolved$Disk extends Disk implements Unresolved$Node$Interface {
+  /**
+   * @aspect RefResolverHelpers
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:726
+   */
+  
+    private String unresolved$Token;
+  /**
+   * @aspect RefResolverHelpers
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:727
+   */
+  
+    public String getUnresolved$Token() {
+      return unresolved$Token;
+    }
+  /**
+   * @aspect RefResolverHelpers
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:730
+   */
+  
+    void setUnresolved$Token(String token) {
+      this.unresolved$Token = token;
+    }
+  /**
+   * @aspect RefResolverHelpers
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:733
+   */
+  
+    private boolean unresolved$ResolveOpposite;
+  /**
+   * @aspect RefResolverHelpers
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:734
+   */
+  
+    public boolean getUnresolved$ResolveOpposite() {
+      return unresolved$ResolveOpposite;
+    }
+  /**
+   * @aspect RefResolverHelpers
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:737
+   */
+  
+    void setUnresolved$ResolveOpposite(boolean resolveOpposite) {
+      this.unresolved$ResolveOpposite = resolveOpposite;
+    }
+  /**
+   * @aspect RefResolverHelpers
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:744
+   */
+  Unresolved$Node$Interface as$Unresolved() {
+    return this;
+  }
+  /**
+   * @aspect RefResolverHelpers
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:750
+   */
+  boolean is$Unresolved() {
+    return true;
+  }
+
+}
diff --git a/src/gen/java/org/jastadd/ag/ast/Unresolved$Hanoi.java b/src/gen/java/org/jastadd/ag/ast/Unresolved$Hanoi.java
new file mode 100644
index 0000000000000000000000000000000000000000..5bbe319e114fbc66c85304aa69567e9532025461
--- /dev/null
+++ b/src/gen/java/org/jastadd/ag/ast/Unresolved$Hanoi.java
@@ -0,0 +1,69 @@
+package org.jastadd.ag.ast;
+
+import java.util.*;
+/**
+ * @ast class
+ * @aspect RefResolverHelpers
+ * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:697
+ */
+ class Unresolved$Hanoi extends Hanoi implements Unresolved$Node$Interface {
+  /**
+   * @aspect RefResolverHelpers
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:698
+   */
+  
+    private String unresolved$Token;
+  /**
+   * @aspect RefResolverHelpers
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:699
+   */
+  
+    public String getUnresolved$Token() {
+      return unresolved$Token;
+    }
+  /**
+   * @aspect RefResolverHelpers
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:702
+   */
+  
+    void setUnresolved$Token(String token) {
+      this.unresolved$Token = token;
+    }
+  /**
+   * @aspect RefResolverHelpers
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:705
+   */
+  
+    private boolean unresolved$ResolveOpposite;
+  /**
+   * @aspect RefResolverHelpers
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:706
+   */
+  
+    public boolean getUnresolved$ResolveOpposite() {
+      return unresolved$ResolveOpposite;
+    }
+  /**
+   * @aspect RefResolverHelpers
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:709
+   */
+  
+    void setUnresolved$ResolveOpposite(boolean resolveOpposite) {
+      this.unresolved$ResolveOpposite = resolveOpposite;
+    }
+  /**
+   * @aspect RefResolverHelpers
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:716
+   */
+  Unresolved$Node$Interface as$Unresolved() {
+    return this;
+  }
+  /**
+   * @aspect RefResolverHelpers
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:722
+   */
+  boolean is$Unresolved() {
+    return true;
+  }
+
+}
diff --git a/src/gen/java/org/jastadd/ag/ast/Unresolved$Implication.java b/src/gen/java/org/jastadd/ag/ast/Unresolved$Implication.java
new file mode 100644
index 0000000000000000000000000000000000000000..dd5019125bf118c9a83871191051bdff552d2def
--- /dev/null
+++ b/src/gen/java/org/jastadd/ag/ast/Unresolved$Implication.java
@@ -0,0 +1,69 @@
+package org.jastadd.ag.ast;
+
+import java.util.*;
+/**
+ * @ast class
+ * @aspect RefResolverHelpers
+ * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:501
+ */
+ class Unresolved$Implication extends Implication implements Unresolved$Node$Interface {
+  /**
+   * @aspect RefResolverHelpers
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:502
+   */
+  
+    private String unresolved$Token;
+  /**
+   * @aspect RefResolverHelpers
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:503
+   */
+  
+    public String getUnresolved$Token() {
+      return unresolved$Token;
+    }
+  /**
+   * @aspect RefResolverHelpers
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:506
+   */
+  
+    void setUnresolved$Token(String token) {
+      this.unresolved$Token = token;
+    }
+  /**
+   * @aspect RefResolverHelpers
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:509
+   */
+  
+    private boolean unresolved$ResolveOpposite;
+  /**
+   * @aspect RefResolverHelpers
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:510
+   */
+  
+    public boolean getUnresolved$ResolveOpposite() {
+      return unresolved$ResolveOpposite;
+    }
+  /**
+   * @aspect RefResolverHelpers
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:513
+   */
+  
+    void setUnresolved$ResolveOpposite(boolean resolveOpposite) {
+      this.unresolved$ResolveOpposite = resolveOpposite;
+    }
+  /**
+   * @aspect RefResolverHelpers
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:520
+   */
+  Unresolved$Node$Interface as$Unresolved() {
+    return this;
+  }
+  /**
+   * @aspect RefResolverHelpers
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:526
+   */
+  boolean is$Unresolved() {
+    return true;
+  }
+
+}
diff --git a/src/gen/java/org/jastadd/ag/ast/Unresolved$Negation.java b/src/gen/java/org/jastadd/ag/ast/Unresolved$Negation.java
new file mode 100644
index 0000000000000000000000000000000000000000..898efaf73de018c0165b43b6b27bc8f2dd818acc
--- /dev/null
+++ b/src/gen/java/org/jastadd/ag/ast/Unresolved$Negation.java
@@ -0,0 +1,69 @@
+package org.jastadd.ag.ast;
+
+import java.util.*;
+/**
+ * @ast class
+ * @aspect RefResolverHelpers
+ * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:529
+ */
+ class Unresolved$Negation extends Negation implements Unresolved$Node$Interface {
+  /**
+   * @aspect RefResolverHelpers
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:530
+   */
+  
+    private String unresolved$Token;
+  /**
+   * @aspect RefResolverHelpers
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:531
+   */
+  
+    public String getUnresolved$Token() {
+      return unresolved$Token;
+    }
+  /**
+   * @aspect RefResolverHelpers
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:534
+   */
+  
+    void setUnresolved$Token(String token) {
+      this.unresolved$Token = token;
+    }
+  /**
+   * @aspect RefResolverHelpers
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:537
+   */
+  
+    private boolean unresolved$ResolveOpposite;
+  /**
+   * @aspect RefResolverHelpers
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:538
+   */
+  
+    public boolean getUnresolved$ResolveOpposite() {
+      return unresolved$ResolveOpposite;
+    }
+  /**
+   * @aspect RefResolverHelpers
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:541
+   */
+  
+    void setUnresolved$ResolveOpposite(boolean resolveOpposite) {
+      this.unresolved$ResolveOpposite = resolveOpposite;
+    }
+  /**
+   * @aspect RefResolverHelpers
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:548
+   */
+  Unresolved$Node$Interface as$Unresolved() {
+    return this;
+  }
+  /**
+   * @aspect RefResolverHelpers
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:554
+   */
+  boolean is$Unresolved() {
+    return true;
+  }
+
+}
diff --git a/src/gen/java/org/jastadd/ag/ast/Unresolved$Node$Interface.java b/src/gen/java/org/jastadd/ag/ast/Unresolved$Node$Interface.java
new file mode 100644
index 0000000000000000000000000000000000000000..16df9218a2426af5c3a383a69ce0987ab1dd3516
--- /dev/null
+++ b/src/gen/java/org/jastadd/ag/ast/Unresolved$Node$Interface.java
@@ -0,0 +1,17 @@
+package org.jastadd.ag.ast;
+
+import java.util.*;
+
+/**
+ * @ast interface
+ * @aspect RefResolverHelpers
+ * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:300
+ */
+ interface Unresolved$Node$Interface {
+
+     
+    String getUnresolved$Token();
+
+     
+    boolean getUnresolved$ResolveOpposite();
+}
diff --git a/src/gen/java/org/jastadd/ag/ast/Unresolved$OnoDisk.java b/src/gen/java/org/jastadd/ag/ast/Unresolved$OnoDisk.java
new file mode 100644
index 0000000000000000000000000000000000000000..28297b2eb6391a751fb40699511e460febbca49c
--- /dev/null
+++ b/src/gen/java/org/jastadd/ag/ast/Unresolved$OnoDisk.java
@@ -0,0 +1,69 @@
+package org.jastadd.ag.ast;
+
+import java.util.*;
+/**
+ * @ast class
+ * @aspect RefResolverHelpers
+ * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:613
+ */
+ class Unresolved$OnoDisk extends OnoDisk implements Unresolved$Node$Interface {
+  /**
+   * @aspect RefResolverHelpers
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:614
+   */
+  
+    private String unresolved$Token;
+  /**
+   * @aspect RefResolverHelpers
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:615
+   */
+  
+    public String getUnresolved$Token() {
+      return unresolved$Token;
+    }
+  /**
+   * @aspect RefResolverHelpers
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:618
+   */
+  
+    void setUnresolved$Token(String token) {
+      this.unresolved$Token = token;
+    }
+  /**
+   * @aspect RefResolverHelpers
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:621
+   */
+  
+    private boolean unresolved$ResolveOpposite;
+  /**
+   * @aspect RefResolverHelpers
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:622
+   */
+  
+    public boolean getUnresolved$ResolveOpposite() {
+      return unresolved$ResolveOpposite;
+    }
+  /**
+   * @aspect RefResolverHelpers
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:625
+   */
+  
+    void setUnresolved$ResolveOpposite(boolean resolveOpposite) {
+      this.unresolved$ResolveOpposite = resolveOpposite;
+    }
+  /**
+   * @aspect RefResolverHelpers
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:632
+   */
+  Unresolved$Node$Interface as$Unresolved() {
+    return this;
+  }
+  /**
+   * @aspect RefResolverHelpers
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:638
+   */
+  boolean is$Unresolved() {
+    return true;
+  }
+
+}
diff --git a/src/gen/java/org/jastadd/ag/ast/Unresolved$Pillar.java b/src/gen/java/org/jastadd/ag/ast/Unresolved$Pillar.java
new file mode 100644
index 0000000000000000000000000000000000000000..bd1589d7c37f733d3f5e112bd5abd4baca6d41f3
--- /dev/null
+++ b/src/gen/java/org/jastadd/ag/ast/Unresolved$Pillar.java
@@ -0,0 +1,69 @@
+package org.jastadd.ag.ast;
+
+import java.util.*;
+/**
+ * @ast class
+ * @aspect RefResolverHelpers
+ * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:753
+ */
+ class Unresolved$Pillar extends Pillar implements Unresolved$Node$Interface {
+  /**
+   * @aspect RefResolverHelpers
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:754
+   */
+  
+    private String unresolved$Token;
+  /**
+   * @aspect RefResolverHelpers
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:755
+   */
+  
+    public String getUnresolved$Token() {
+      return unresolved$Token;
+    }
+  /**
+   * @aspect RefResolverHelpers
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:758
+   */
+  
+    void setUnresolved$Token(String token) {
+      this.unresolved$Token = token;
+    }
+  /**
+   * @aspect RefResolverHelpers
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:761
+   */
+  
+    private boolean unresolved$ResolveOpposite;
+  /**
+   * @aspect RefResolverHelpers
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:762
+   */
+  
+    public boolean getUnresolved$ResolveOpposite() {
+      return unresolved$ResolveOpposite;
+    }
+  /**
+   * @aspect RefResolverHelpers
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:765
+   */
+  
+    void setUnresolved$ResolveOpposite(boolean resolveOpposite) {
+      this.unresolved$ResolveOpposite = resolveOpposite;
+    }
+  /**
+   * @aspect RefResolverHelpers
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:772
+   */
+  Unresolved$Node$Interface as$Unresolved() {
+    return this;
+  }
+  /**
+   * @aspect RefResolverHelpers
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:778
+   */
+  boolean is$Unresolved() {
+    return true;
+  }
+
+}
diff --git a/src/gen/java/org/jastadd/ag/ast/Unresolved$Root.java b/src/gen/java/org/jastadd/ag/ast/Unresolved$Root.java
new file mode 100644
index 0000000000000000000000000000000000000000..e076e4676ef6ed85e8bbbcba2489979ec77f3cf9
--- /dev/null
+++ b/src/gen/java/org/jastadd/ag/ast/Unresolved$Root.java
@@ -0,0 +1,69 @@
+package org.jastadd.ag.ast;
+
+import java.util.*;
+/**
+ * @ast class
+ * @aspect RefResolverHelpers
+ * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:305
+ */
+ class Unresolved$Root extends Root implements Unresolved$Node$Interface {
+  /**
+   * @aspect RefResolverHelpers
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:306
+   */
+  
+    private String unresolved$Token;
+  /**
+   * @aspect RefResolverHelpers
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:307
+   */
+  
+    public String getUnresolved$Token() {
+      return unresolved$Token;
+    }
+  /**
+   * @aspect RefResolverHelpers
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:310
+   */
+  
+    void setUnresolved$Token(String token) {
+      this.unresolved$Token = token;
+    }
+  /**
+   * @aspect RefResolverHelpers
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:313
+   */
+  
+    private boolean unresolved$ResolveOpposite;
+  /**
+   * @aspect RefResolverHelpers
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:314
+   */
+  
+    public boolean getUnresolved$ResolveOpposite() {
+      return unresolved$ResolveOpposite;
+    }
+  /**
+   * @aspect RefResolverHelpers
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:317
+   */
+  
+    void setUnresolved$ResolveOpposite(boolean resolveOpposite) {
+      this.unresolved$ResolveOpposite = resolveOpposite;
+    }
+  /**
+   * @aspect RefResolverHelpers
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:324
+   */
+  Unresolved$Node$Interface as$Unresolved() {
+    return this;
+  }
+  /**
+   * @aspect RefResolverHelpers
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:330
+   */
+  boolean is$Unresolved() {
+    return true;
+  }
+
+}
diff --git a/src/gen/java/org/jastadd/ag/ast/Unresolved$TnoDisk.java b/src/gen/java/org/jastadd/ag/ast/Unresolved$TnoDisk.java
new file mode 100644
index 0000000000000000000000000000000000000000..0caa5110016457c61ac7dc01c3b36f48c133402d
--- /dev/null
+++ b/src/gen/java/org/jastadd/ag/ast/Unresolved$TnoDisk.java
@@ -0,0 +1,69 @@
+package org.jastadd.ag.ast;
+
+import java.util.*;
+/**
+ * @ast class
+ * @aspect RefResolverHelpers
+ * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:641
+ */
+ class Unresolved$TnoDisk extends TnoDisk implements Unresolved$Node$Interface {
+  /**
+   * @aspect RefResolverHelpers
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:642
+   */
+  
+    private String unresolved$Token;
+  /**
+   * @aspect RefResolverHelpers
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:643
+   */
+  
+    public String getUnresolved$Token() {
+      return unresolved$Token;
+    }
+  /**
+   * @aspect RefResolverHelpers
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:646
+   */
+  
+    void setUnresolved$Token(String token) {
+      this.unresolved$Token = token;
+    }
+  /**
+   * @aspect RefResolverHelpers
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:649
+   */
+  
+    private boolean unresolved$ResolveOpposite;
+  /**
+   * @aspect RefResolverHelpers
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:650
+   */
+  
+    public boolean getUnresolved$ResolveOpposite() {
+      return unresolved$ResolveOpposite;
+    }
+  /**
+   * @aspect RefResolverHelpers
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:653
+   */
+  
+    void setUnresolved$ResolveOpposite(boolean resolveOpposite) {
+      this.unresolved$ResolveOpposite = resolveOpposite;
+    }
+  /**
+   * @aspect RefResolverHelpers
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:660
+   */
+  Unresolved$Node$Interface as$Unresolved() {
+    return this;
+  }
+  /**
+   * @aspect RefResolverHelpers
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:666
+   */
+  boolean is$Unresolved() {
+    return true;
+  }
+
+}
diff --git a/src/gen/java/org/jastadd/ag/ast/Unresolved$UnaryConstraint.java b/src/gen/java/org/jastadd/ag/ast/Unresolved$UnaryConstraint.java
new file mode 100644
index 0000000000000000000000000000000000000000..a2a3df85557400079e22bf854a4b4997161936c4
--- /dev/null
+++ b/src/gen/java/org/jastadd/ag/ast/Unresolved$UnaryConstraint.java
@@ -0,0 +1,69 @@
+package org.jastadd.ag.ast;
+
+import java.util.*;
+/**
+ * @ast class
+ * @aspect RefResolverHelpers
+ * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:389
+ */
+abstract class Unresolved$UnaryConstraint extends UnaryConstraint implements Unresolved$Node$Interface {
+  /**
+   * @aspect RefResolverHelpers
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:390
+   */
+  
+    private String unresolved$Token;
+  /**
+   * @aspect RefResolverHelpers
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:391
+   */
+  
+    public String getUnresolved$Token() {
+      return unresolved$Token;
+    }
+  /**
+   * @aspect RefResolverHelpers
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:394
+   */
+  
+    void setUnresolved$Token(String token) {
+      this.unresolved$Token = token;
+    }
+  /**
+   * @aspect RefResolverHelpers
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:397
+   */
+  
+    private boolean unresolved$ResolveOpposite;
+  /**
+   * @aspect RefResolverHelpers
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:398
+   */
+  
+    public boolean getUnresolved$ResolveOpposite() {
+      return unresolved$ResolveOpposite;
+    }
+  /**
+   * @aspect RefResolverHelpers
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:401
+   */
+  
+    void setUnresolved$ResolveOpposite(boolean resolveOpposite) {
+      this.unresolved$ResolveOpposite = resolveOpposite;
+    }
+  /**
+   * @aspect RefResolverHelpers
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:408
+   */
+  Unresolved$Node$Interface as$Unresolved() {
+    return this;
+  }
+  /**
+   * @aspect RefResolverHelpers
+   * @declaredat E:\\project\\20211201\\src\\gen\\jastadd\\agRefResolver.jadd:414
+   */
+  boolean is$Unresolved() {
+    return true;
+  }
+
+}
diff --git a/src/main/common/proto/action.proto b/src/main/common/proto/action.proto
new file mode 100644
index 0000000000000000000000000000000000000000..1ec438521601e3c6312f8a87b079a3ebad5a5b64
--- /dev/null
+++ b/src/main/common/proto/action.proto
@@ -0,0 +1,34 @@
+syntax = "proto3";
+
+package behavior;
+
+message Pose {
+    message Position {
+        double x = 1;
+        double y = 2;
+        double z = 3;
+    }
+    message Orientation {
+        double roll = 1;
+        double yaw = 2;
+        double pitch = 3;
+    }
+    Position GoalPosition = 1;
+    Orientation GoalOrientation = 2;
+  
+}
+
+message GraspPose {
+    string PreDirection = 1;
+    Pose GraspPose = 2;
+    string PostDirection = 3;
+}
+
+message PlacePose {
+    string PreDirection = 1;
+    Pose PlacePose = 2;
+    string PostDirection = 3;
+}
+
+
+
diff --git a/src/main/common/proto/feedback.proto b/src/main/common/proto/feedback.proto
new file mode 100644
index 0000000000000000000000000000000000000000..69844db907b235af8fbcc88b7e72606fac8e84c6
--- /dev/null
+++ b/src/main/common/proto/feedback.proto
@@ -0,0 +1,8 @@
+syntax = "proto3";
+
+package feedback;
+
+message Feedback {
+    int32 isSuccess = 1;
+    string error = 2;
+}
\ No newline at end of file
diff --git a/src/main/jastadd/hanoi/CanMove.jrag b/src/main/jastadd/hanoi/CanMove.jrag
new file mode 100644
index 0000000000000000000000000000000000000000..9863f6702ede07e36d5be1ff977137310c0a8d7f
--- /dev/null
+++ b/src/main/jastadd/hanoi/CanMove.jrag
@@ -0,0 +1,24 @@
+aspect CanMove {
+  syn boolean Disk.smallerThan(Disk D) {
+    if(this.getSize() < D.getSize()){
+      return true;
+    }
+      return false;
+  }
+  /*for odd turns, the smallest disk D0 is supposed to move in a certain sequence
+  to eventually move all the disks from P0 to P2.
+  Pillar.moveseq() return the integer who demonstrates the target pillar according to the sequence.
+  the sequence is 0 2 1... when the amount of disks is odd and 0 1 2... when even.*/
+  inh int Pillar.moveSeq();
+  eq Hanoi.getPillar(int i).moveSeq(){
+    if(this.getAmountD()%2 == 1){
+      return (i+2)%3;
+    }else{
+      return (i+1)%3;
+    }
+  }
+  inh int Pillar.ID();
+  eq Hanoi.getPillar(int i).ID(){
+    return i;
+  }
+}
\ No newline at end of file
diff --git a/src/main/jastadd/hanoi/Constraint.relast b/src/main/jastadd/hanoi/Constraint.relast
new file mode 100644
index 0000000000000000000000000000000000000000..dc2211765e576c54b0a278fc560d693ef173ac4c
--- /dev/null
+++ b/src/main/jastadd/hanoi/Constraint.relast
@@ -0,0 +1,18 @@
+Root::=BinaryConstraint* UnaryConstraint* Atom*;
+abstract Constraint;
+abstract Atom:Constraint;
+abstract UnaryConstraint:Constraint ::= Constraint;
+abstract BinaryConstraint:Constraint ::= Left:Constraint Right:Constraint;
+Conjunction:BinaryConstraint;
+Disjunction:BinaryConstraint;
+Implication:BinaryConstraint;
+Negation:UnaryConstraint;
+//the original and target pillar are denoted P0 and P1, the disks on top of them are D0 and D1.
+//CheckD0 is an exception, for whom D0 means the smallest disk.
+CheckSize:Atom;//if D0.getSize()<D1.getSize()
+CheckSeq:Atom; //if P0->P1 is valid sequence, this constraint is not used
+OnoDisk:Atom;  //if P0 is empty
+TnoDisk:Atom;  //if P1 is empty
+CheckD0:Atom;  //if the smallest disk is on the pillar
+
+rel Atom.Rel* -> Pillar;
\ No newline at end of file
diff --git a/src/main/jastadd/hanoi/Constraints.jrag b/src/main/jastadd/hanoi/Constraints.jrag
new file mode 100644
index 0000000000000000000000000000000000000000..20d6e19269e682ff726d8b41234781109640d502
--- /dev/null
+++ b/src/main/jastadd/hanoi/Constraints.jrag
@@ -0,0 +1,45 @@
+import java.util.*;
+aspect Constraints{
+    syn boolean Constraint.eval();
+    eq Conjunction.eval(){
+        return this.getLeft().eval() && this.getRight().eval();
+    }
+    eq Disjunction.eval(){
+        return this.getLeft().eval() || this.getRight().eval();
+    }
+    eq Implication.eval(){
+        return (!this.getLeft().eval()) || this.getRight().eval();
+    }
+    eq Negation.eval()= !getConstraint().eval();
+    eq CheckSize.eval(){
+        //if the origin pillar and the target pillar are not empty
+        if((this.getRels().get(0).getNumDisk()>0)&&(this.getRels().get(1).getNumDisk()>0)){
+        //compare the size of the top disks on the origin and target pillar,
+        //the disks can be get by getDisk(#Disks-1).
+            return this.getRels().get(0).getDisk(this.getRels().get(0).getNumDisk()-1).smallerThan(this.getRels().get(1).getDisk(this.getRels().get(1).getNumDisk()-1));
+        }
+        return false;
+    }
+    eq CheckSeq.eval(){
+        //check if from get(0) to get(1) is the correct sequence,
+        //this constraint is not used while
+        return this.getRels().get(0).moveSeq()==this.getRels().get(1).ID();
+    }
+    eq OnoDisk.eval(){
+        //the origin pillar is empty?
+        return this.getRels().get(0).getNumDisk()==0;
+    }
+    eq TnoDisk.eval(){
+        //the target pillar is empty?
+        return this.getRels().get(0).getNumDisk()==0;
+    }
+    eq CheckD0.eval(){
+        //the pillar has the smallest disk D0 on the top?
+        if(this.getRels().get(0).getNumDisk()>0){
+        //if the pillar is not empty, check if the top disk has size 1.
+            return  this.getRels().get(0).getDisk(this.getRels().get(0).getNumDisk()-1).getSize()==1;
+        }else{
+            return false;
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/main/jastadd/hanoi/Hanoi.relast b/src/main/jastadd/hanoi/Hanoi.relast
new file mode 100644
index 0000000000000000000000000000000000000000..539f59709e29d4fcc46c31acf5b499a47c41a39f
--- /dev/null
+++ b/src/main/jastadd/hanoi/Hanoi.relast
@@ -0,0 +1,3 @@
+Hanoi::=Pillar* <AmountD:int>;//amount of disks, set at the begining
+Disk::=<Size:int>;
+Pillar::=Disk*;
\ No newline at end of file
diff --git a/src/main/jastadd/hanoi/Initialisation.jrag b/src/main/jastadd/hanoi/Initialisation.jrag
new file mode 100644
index 0000000000000000000000000000000000000000..0cd713616278b4702d7399f62380d5e010796c10
--- /dev/null
+++ b/src/main/jastadd/hanoi/Initialisation.jrag
@@ -0,0 +1,93 @@
+import java.util.*;
+aspect Initialisation {
+  /*initialise the Hanoi class with 3 pillars and sumDisk disks
+  each disk is assigned with size from 1 to sumDisk
+  all the disks are on pillar P[0] at the begining*/
+  public boolean Hanoi.Initialisation(int sumDisk)
+  {
+    this.setAmountD(sumDisk);
+    int sumPillar = 3;
+    Disk[] D = new Disk[sumDisk];
+    Pillar[] P = new Pillar[3];
+    for(int i = 0; i < 3; i++)
+    {
+      P[i] = new Pillar();
+    }
+    for(int i = 0; i < sumDisk; i++)
+    {
+      D[i] = new Disk(i + 1);
+      System.out.println("Disk: " + i + "; size: " + D[i].getSize());
+    }
+    for(int i = sumDisk - 1; i >= 0; i--)
+    {
+      P[0].addDisk(D[i]);
+    }
+    for(int i = 0; i < 3; i++)
+    {
+      this.addPillar(P[i]);
+    } 
+    this.present();
+    return true;
+  }
+  //print the result
+  public boolean Hanoi.present()
+  {
+    int sumPillar = 3;
+    for(int i = 0; i < 3; i++)
+    {
+      if(this.getPillar(i).getNumDisk() > 0){
+        System.out.println("Pillar_" + i + " has Disks:");
+        for(int j = 0; j < this.getAmountD(); j++){
+          int temp = this.getPillar(i).getDisk(j).getSize();
+          System.out.println("Disk: " + (temp - 1) + "; Size: " + temp + ".");
+        }
+      }
+      else{
+        System.out.println("Pillar_" + i + " is empty.");
+      }
+    }
+    return true; 
+  } 
+  public boolean Hanoi.play(){
+    boolean turn = true;//parity check
+    int count = 1;//count the turn
+    int location = 0;//log which pillar the smallest disk is on at the moment
+    while(true){
+      //check if all the disks are moved to the last pillar
+      if(this.getPillar(2).getNumDisk() == this.getAmountD()){
+        break;
+      }
+      for(int i = 0; i < 3; i++){
+        for(int j = 0; j < 3; j++){
+          if(this.getPillar(2).getNumDisk() == this.getAmountD()){
+            break;
+          }
+          if(i==j){
+            continue;
+          }else{
+            Root root = new Root();
+            int temp = root.check(this.getPillar(i), this.getPillar(j), turn);
+            if(temp == 1){//odd turn valid move
+              if(this.getPillar(i).moveSeq()==j){//origin != target
+                this.getPillar(i).moveTo(this.getPillar(j));
+                System.out.println("Disk_" + (this.getPillar(j).getDisk(this.getPillar(j).getNumDisk()-1).getSize()-1) + ": " + i + "->" + j);
+                System.out.println("Round: " + count++);
+                location = j;//log where the smallest disk is
+                turn = !turn;//change turn
+                break;
+              }
+            }else if(temp == 2 && !(location == i)){//even turn and valid move
+              //Origin != location since we don't move the smallest disk in even turns
+              this.getPillar(i).moveTo(this.getPillar(j));
+              System.out.println("Disk_" + (this.getPillar(j).getDisk(this.getPillar(j).getNumDisk()-1).getSize()-1) + ": " + i + "->" + j);
+              System.out.println("Round: " + count++);
+              turn = !turn;
+              break;
+            }
+          }
+        }
+      }
+    }
+    return true;
+  }
+}
\ No newline at end of file
diff --git a/src/main/jastadd/hanoi/MoveTo.jadd b/src/main/jastadd/hanoi/MoveTo.jadd
new file mode 100644
index 0000000000000000000000000000000000000000..4afd0d95bb2fd33576ffb3da6913f3bfb0b7555f
--- /dev/null
+++ b/src/main/jastadd/hanoi/MoveTo.jadd
@@ -0,0 +1,69 @@
+aspect MoveTo {
+  public int Root.check(Pillar P0, Pillar P1, boolean turn){
+/*for every odd turn(turn==true), move the smallest disk D0 in sequence.
+Therefore, CheckD0 checks for a move from P0 to P1, when D0 is on the top of P0.*/
+    if(turn==true){
+      CheckD0 C=new CheckD0();
+      this.addAtom(C);
+      this.getAtom(0).addRel(P0);
+      if(this.getAtom(0).eval()){
+        return 1;//odd turn and valid move
+      }else{
+        return 0;
+      }
+    }
+/*for every even turn(turn==false), move the disk D on top of P0 to P1:
+D is not D0(the smallest disk).
+There is always one D can be moved in the even turn according to the game rules.
+Statements:
+1.P0 is not empty: not OnoDisk().
+2.When condition 1 holds, P1 can be empty: TnoDisk().
+3.When 1 holds and 2 doesn’t hold, D0 < D1(for the disks on the top of P0 and P1 respectively).
+Therefore, we want not OnoDisk() and (TnoDisk() or CheckSize()) to be true.
+
+Conjunction()-------------Negation()--------------OnoDisk()
+                      |
+                      |--------------------Disjunction()-----------TnoDisk()
+                                              |
+                                              |------------------CheckSize()*/
+    Conjunction C0=new Conjunction();
+    Negation C1=new Negation();
+    Disjunction C2=new Disjunction();
+    OnoDisk C3=new OnoDisk();
+    TnoDisk C4=new TnoDisk();
+    CheckSize C5=new CheckSize();
+
+    C0.setLeft(C1);
+    C0.setRight(C2);
+    C1.setConstraint(C3);
+    C2.setLeft(C4);
+    C2.setRight(C5);
+
+    C3.addRel(P0);
+    C4.addRel(P1);
+    C5.addRel(P0);
+    C5.addRel(P1);
+    this.addBinaryConstraint(C0);
+    if(this.getBinaryConstraint(0).eval()){
+      return 2;//even turn and valid move
+    }
+    return 0;
+  }
+  /*move the disk from this to P, eg. P0.moveTo(P2).
+                              Hanoi                                        Hanoi
+                                |                                            |
+                ----------------------------------           ----------------------------------
+                |               |                |           |               |                |
+               P0               P1               P2         P0               P1               P2
+                |                                            |                                |
+-----------------------                           -----------------------                     D0
+|     |    ......     |                           |     |    ......     |
+Dn-1  Dn-2            D0                          Dn-1  Dn-2            D1
+  */
+  public boolean Pillar.moveTo(Pillar P){
+      int i = this.getNumDisk();
+      P.addDisk(this.getDisk(i-1));
+      this.getDisks().removeChild(i-1);
+      return true;
+  }
+}
diff --git a/src/main/java/de/tudresden/inf/st/ag/starter/StarterMain.class b/src/main/java/de/tudresden/inf/st/ag/starter/StarterMain.class
new file mode 100644
index 0000000000000000000000000000000000000000..6737b528789546a9c15b980d917bc853f6264faa
Binary files /dev/null and b/src/main/java/de/tudresden/inf/st/ag/starter/StarterMain.class differ
diff --git a/src/main/java/de/tudresden/inf/st/ag/starter/StarterMain.java b/src/main/java/de/tudresden/inf/st/ag/starter/StarterMain.java
new file mode 100644
index 0000000000000000000000000000000000000000..3e92ca875c51667c40ade95b006b949dbe169768
--- /dev/null
+++ b/src/main/java/de/tudresden/inf/st/ag/starter/StarterMain.java
@@ -0,0 +1,37 @@
+package de.tudresden.inf.st.ag.starter;
+import org.jastadd.ag.ast.*;
+import java.util.Scanner;
+import java.io.File;
+import java.io.IOException;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import java.nio.charset.StandardCharsets;
+
+public class StarterMain {
+  public static void main(String[] args){
+    System.out.println("Hello, input amount of disks:");
+    Hanoi hanoi;
+    hanoi = new Hanoi();
+    int amountOfDisk = 0;
+    while(amountOfDisk <= 0){//input #disks
+      Scanner sc=new Scanner(System.in);
+      String s=sc.next();
+      amountOfDisk = checkInt(s);
+    }
+    Root root = new Root();
+    hanoi.Initialisation(amountOfDisk);
+    hanoi.play();
+    System.out.println("Game done.");
+    hanoi.present();
+    }
+
+  public static int checkInt(String str){
+    int a =0;
+    try {
+      a = Integer.parseInt(str);
+      } catch (NumberFormatException e) {
+        return 0;
+      }
+    return a;
+  }  
+}
\ No newline at end of file
diff --git a/src/main/resources/log4j2.xml b/src/main/resources/log4j2.xml
new file mode 100644
index 0000000000000000000000000000000000000000..a555940d0a99e77d3385865b934d7f780433baf5
--- /dev/null
+++ b/src/main/resources/log4j2.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Configuration status="INFO">
+    <Appenders>
+        <Console name="Console" target="SYSTEM_OUT">
+            <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{1.} - %msg%n"/>
+        </Console>
+    </Appenders>
+    <Loggers>
+        <Root level="debug">
+            <AppenderRef ref="Console"/>
+        </Root>
+    </Loggers>
+</Configuration>
diff --git a/uml.md b/uml.md
new file mode 100644
index 0000000000000000000000000000000000000000..87f47a8a0da1ec1daf2be9908ea0a834e1892104
--- /dev/null
+++ b/uml.md
@@ -0,0 +1,131 @@
+```plantuml
+@startuml
+hide circle
+hide methods
+
+class EndTask
+class DeviceOfComponent {
+  Type
+}
+class JointOfComponent
+class Connector {
+  Translation
+}
+class Robot {
+  BasePosition
+  Name
+  Type
+  Role
+  Id
+}
+class EndEffector {
+  InitialPosition
+  InitialOrientation
+}
+abstract class Process {
+  Id
+}
+class Link
+class Place {
+  Place
+}
+class StartTask {
+  CurrentTask
+}
+class EndProcess
+abstract class ComponentProperty {
+  Name
+}
+class RobotModel
+class Movement {
+  GoalPose
+}
+class Grasp {
+  Grasp
+}
+class Physic {
+  CenterOfMass
+  Weight
+}
+class StartProcess
+class WorkProcess {
+  CurrentTask
+}
+class Component {
+  Id
+  IsConnected
+}
+abstract class Property {
+  Name
+}
+class Device {
+  Type
+}
+abstract class Subtask {
+  Id
+}
+abstract class Behavior {
+  Id
+}
+class ActionModel
+class ComponentModel
+class Condition {
+  TypeOfComponent
+  TypeOfNextComponent
+  Position
+  ConnectionSide
+  BoundRange
+}
+class ContainerModel
+class LinkOfComponent
+class WorkFlowTask {
+  IsSucceeded
+  CurrentBehavior
+  WorkPose
+}
+class Joint {
+  MaxRange
+  MaxVelocity
+  MaxEffort
+  MinRange
+  MinVelocity
+  MinEffort
+}
+
+Robot *-- "*" Property 
+RobotModel *-- "*" Robot 
+WorkProcess *-- "*" Subtask 
+Component *-- "*" ComponentProperty 
+Component *-- "1" Condition 
+ActionModel *-- "*" Process 
+ComponentModel *-- "*" Component 
+ContainerModel *-- "1" RobotModel 
+ContainerModel *-- "1" ActionModel 
+ContainerModel *-- "1" ComponentModel 
+WorkFlowTask *-- "*" Behavior 
+
+EndProcess "1" <--> "1" Component 
+StartProcess  --> "1" ComponentModel : GoalComponentModel
+StartTask  --> "1" RobotModel : LinkRobot
+
+Subtask <|-- EndTask
+ComponentProperty <|-- DeviceOfComponent
+ComponentProperty <|-- JointOfComponent
+LinkOfComponent <|-- Connector
+Joint <|-- EndEffector
+Property <|-- Link
+Behavior <|-- Place
+Subtask <|-- StartTask
+Process <|-- EndProcess
+Behavior <|-- Movement
+Behavior <|-- Grasp
+ComponentProperty <|-- Physic
+Process <|-- StartProcess
+Process <|-- WorkProcess
+Property <|-- Device
+ComponentProperty <|-- LinkOfComponent
+Subtask <|-- WorkFlowTask
+Property <|-- Joint
+
+@enduml
+```