diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..a5fdfe8 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +.gradle/ +.idea/ +build/ diff --git a/.tool-versions b/.tool-versions new file mode 100644 index 0000000..cec4efd --- /dev/null +++ b/.tool-versions @@ -0,0 +1 @@ +java adoptopenjdk-11.0.13+8 diff --git a/build.gradle.kts b/build.gradle.kts new file mode 100644 index 0000000..3eff97c --- /dev/null +++ b/build.gradle.kts @@ -0,0 +1,82 @@ +import org.jetbrains.kotlin.gradle.tasks.KotlinCompile + +plugins { + kotlin("jvm") version "1.7.20" + java + id("org.jetbrains.intellij") version "1.9.0" + id("org.jetbrains.grammarkit") version "2021.2.1" +} + +group = "nl.dirkgroot" +version = "1.0-SNAPSHOT" + +repositories { + mavenCentral() +} + +// See https://github.com/JetBrains/gradle-intellij-plugin/ +intellij { + version.set("2022.1.4") + type.set("IC") +} + +sourceSets["main"].java.srcDirs("src/main/gen") + +dependencies { + testImplementation("com.willowtreeapps.assertk:assertk-jvm:0.25") +} + +tasks { + withType { + sourceCompatibility = "11" + targetCompatibility = "11" + } + + withType { + dependsOn("generateLexer") + + kotlinOptions { + jvmTarget = "11" + } + } + + patchPluginXml { + changeNotes.set( + """ + Add change notes here.
+ most HTML tags may be used + """.trimIndent() + ) + } + + generateLexer { + // source flex file + source.set("src/main/grammar/StructurizrDSL.flex") + + // target directory for lexer + targetDir.set("src/main/gen/nl/dirkgroot/structurizr/dsl/") + + // target classname, target file will be targetDir/targetClass.java + targetClass.set("StructurizrDSLLexer") + + // if set, plugin will remove a lexer output file before generating new one. Default: false + purgeOldFiles.set(true) + } + +// generateParser { +// // source bnf file +// source.set("src/main/grammar/StructurizrDSL.bnf") +// +// // optional, task-specific root for the generated files. Default: none +// targetRoot.set("src/main/gen") +// +// // path to a parser file, relative to the targetRoot +// pathToParser.set("/nl/dirkgroot/structurizr/dsl/StructurizrDSLParser") +// +// // path to a directory with generated psi files, relative to the targetRoot +// pathToPsiRoot.set("/nl/dirkgroot/structurizr/dsl/psi") +// +// // if set, the plugin will remove a parser output file and psi output directory before generating new ones. Default: false +// purgeOldFiles.set(true) +// } +} diff --git a/gradle.properties b/gradle.properties new file mode 100644 index 0000000..29e08e8 --- /dev/null +++ b/gradle.properties @@ -0,0 +1 @@ +kotlin.code.style=official \ 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 0000000..7454180 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 0000000..ae04661 --- /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-7.5.1-bin.zip +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew new file mode 100755 index 0000000..3da45c1 --- /dev/null +++ b/gradlew @@ -0,0 +1,234 @@ +#!/bin/sh + +# +# Copyright ? 2015-2021 the original 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 POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions ?$var?, ?${var}?, ?${var:-default}?, ?${var+SET}?, +# ?${var#prefix}?, ?${var%suffix}?, and ?$( cmd )?; +# * compound commands having a testable exit status, especially ?case?; +# * various built-in commands including ?command?, ?set?, and ?ulimit?. +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# +############################################################################## + +# Attempt to set APP_HOME + +# Resolve links: $0 may be a link +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac +done + +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit + +APP_NAME="Gradle" +APP_BASE_NAME=${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 "$*" +} >&2 + +die () { + echo + echo "$*" + echo + exit 1 +} >&2 + +# 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 ;; #( + MSYS* | 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" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac +fi + +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done +fi + +# Collect all arguments for the java command; +# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of +# shell script including quotes and variable substitutions, so put them in +# double quotes to make sure that they get re-expanded; and +# * put everything else in single quotes, so that it's not re-expanded. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + +exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat new file mode 100644 index 0000000..107acd3 --- /dev/null +++ b/gradlew.bat @@ -0,0 +1,89 @@ +@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 execute + +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 execute + +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 + +: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 %* + +: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/settings.gradle.kts b/settings.gradle.kts new file mode 100644 index 0000000..54d2e23 --- /dev/null +++ b/settings.gradle.kts @@ -0,0 +1,2 @@ +rootProject.name = "structurizr-dsl-plugin" + diff --git a/src/main/gen/nl/dirkgroot/structurizr/dsl/StructurizrDSLLexer.java b/src/main/gen/nl/dirkgroot/structurizr/dsl/StructurizrDSLLexer.java new file mode 100644 index 0000000..c654fed --- /dev/null +++ b/src/main/gen/nl/dirkgroot/structurizr/dsl/StructurizrDSLLexer.java @@ -0,0 +1,618 @@ +/* The following code was generated by JFlex 1.7.0-1 tweaked for IntelliJ platform */ + +package nl.dirkgroot.structurizr.dsl; + +import com.intellij.lexer.FlexLexer; +import com.intellij.psi.tree.IElementType; +import static com.intellij.psi.TokenType.BAD_CHARACTER; +import static com.intellij.psi.TokenType.WHITE_SPACE; +import static nl.dirkgroot.structurizr.dsl.psi.SDTypes.*; + + +/** + * This class is a scanner generated by + * JFlex 1.7.0-1 + * from the specification file /Users/dirgroot/stuff/structurizr-dsl-plugin-test/src/main/grammar/StructurizrDSL.flex + */ +public class StructurizrDSLLexer implements FlexLexer { + + /** This character denotes the end of file */ + public static final int YYEOF = -1; + + /** initial size of the lookahead buffer */ + private static final int ZZ_BUFFERSIZE = 16384; + + /** lexical states */ + public static final int YYINITIAL = 0; + public static final int ARGUMENTS = 2; + + /** + * ZZ_LEXSTATE[l] is the state in the DFA for the lexical state l + * ZZ_LEXSTATE[l+1] is the state in the DFA for the lexical state l + * at the beginning of a line + * l is of the form l = 2*k, k a non negative integer + */ + private static final int ZZ_LEXSTATE[] = { + 0, 1, 2, 2 + }; + + /** + * Translates characters to character classes + * Chosen bits are [7, 7, 7] + * Total runtime size is 1928 bytes + */ + public static int ZZ_CMAP(int ch) { + return ZZ_CMAP_A[(ZZ_CMAP_Y[ZZ_CMAP_Z[ch>>14]|((ch>>7)&0x7f)]<<7)|(ch&0x7f)]; + } + + /* The ZZ_CMAP_Z table has 68 entries */ + static final char ZZ_CMAP_Z[] = zzUnpackCMap( + "\1\0\103\200"); + + /* The ZZ_CMAP_Y table has 256 entries */ + static final char ZZ_CMAP_Y[] = zzUnpackCMap( + "\1\0\1\1\53\2\1\3\22\2\1\4\37\2\1\3\237\2"); + + /* The ZZ_CMAP_A table has 640 entries */ + static final char ZZ_CMAP_A[] = zzUnpackCMap( + "\11\0\1\3\1\2\2\3\1\1\22\0\1\3\1\0\1\4\7\0\1\7\4\0\1\6\43\0\1\30\15\0\1\20"+ + "\1\0\1\21\1\24\1\22\1\26\2\0\1\33\1\0\1\15\1\25\1\23\1\0\1\13\1\17\1\0\1\14"+ + "\1\16\1\27\1\0\1\32\1\12\1\0\1\31\1\0\1\10\1\0\1\11\7\0\1\5\32\0\1\5\337\0"+ + "\1\5\177\0\13\5\35\0\2\5\5\0\1\5\57\0\1\5\40\0"); + + /** + * Translates DFA states to action switch labels. + */ + private static final int [] ZZ_ACTION = zzUnpackAction(); + + private static final String ZZ_ACTION_PACKED_0 = + "\3\0\1\1\2\2\1\3\1\1\1\4\1\5\4\1"+ + "\3\3\1\6\2\7\1\1\1\6\1\4\1\10\6\0"+ + "\1\11\1\6\2\10\5\0\1\6\5\0\1\6\1\12"+ + "\2\0\1\13\1\14\3\12\6\0\1\15\5\0\1\16"; + + private static int [] zzUnpackAction() { + int [] result = new int[67]; + int offset = 0; + offset = zzUnpackAction(ZZ_ACTION_PACKED_0, offset, result); + return result; + } + + private static int zzUnpackAction(String packed, int offset, int [] result) { + int i = 0; /* index in packed string */ + int j = offset; /* index in unpacked array */ + int l = packed.length(); + while (i < l) { + int count = packed.charAt(i++); + int value = packed.charAt(i++); + do result[j++] = value; while (--count > 0); + } + return j; + } + + + /** + * Translates a state to a row index in the transition table + */ + private static final int [] ZZ_ROWMAP = zzUnpackRowMap(); + + private static final String ZZ_ROWMAP_PACKED_0 = + "\0\0\0\34\0\70\0\124\0\160\0\124\0\214\0\250"+ + "\0\124\0\124\0\304\0\340\0\374\0\u0118\0\u0134\0\124"+ + "\0\u0150\0\u016c\0\u0188\0\124\0\u01a4\0\u01c0\0\u016c\0\u01dc"+ + "\0\u01f8\0\u0214\0\u0230\0\u024c\0\u0268\0\u01a4\0\124\0\u0284"+ + "\0\u02a0\0\124\0\u02bc\0\u02d8\0\u02f4\0\u0310\0\u032c\0\u0348"+ + "\0\u0364\0\u0380\0\u039c\0\u03b8\0\u03d4\0\u03f0\0\u040c\0\u0428"+ + "\0\u0444\0\124\0\124\0\u0460\0\u047c\0\124\0\u0498\0\u04b4"+ + "\0\u04d0\0\u04ec\0\u0508\0\u0524\0\124\0\u0540\0\u055c\0\u0578"+ + "\0\u0594\0\u05b0\0\124"; + + private static int [] zzUnpackRowMap() { + int [] result = new int[67]; + int offset = 0; + offset = zzUnpackRowMap(ZZ_ROWMAP_PACKED_0, offset, result); + return result; + } + + private static int zzUnpackRowMap(String packed, int offset, int [] result) { + int i = 0; /* index in packed string */ + int j = offset; /* index in unpacked array */ + int l = packed.length(); + while (i < l) { + int high = packed.charAt(i++) << 16; + result[j++] = high | packed.charAt(i++); + } + return j; + } + + /** + * The transition table of the DFA + */ + private static final int [] ZZ_TRANS = zzUnpackTrans(); + + private static final String ZZ_TRANS_PACKED_0 = + "\1\4\1\5\1\6\1\7\2\4\1\10\1\4\1\11"+ + "\1\12\1\13\3\4\1\14\4\4\1\15\6\4\1\16"+ + "\2\4\1\17\1\20\1\21\2\4\1\10\1\4\1\11"+ + "\1\12\1\13\3\4\1\14\4\4\1\15\6\4\1\16"+ + "\1\4\1\22\1\23\1\24\1\7\1\25\1\4\1\26"+ + "\1\22\1\27\23\22\36\0\1\6\34\0\1\7\36\0"+ + "\1\30\1\31\37\0\1\32\33\0\1\33\33\0\1\34"+ + "\53\0\1\35\2\0\1\20\32\0\1\17\1\20\1\21"+ + "\30\0\1\22\5\0\26\22\2\0\1\24\31\0\4\36"+ + "\1\37\27\36\1\22\5\0\1\30\1\40\24\22\1\30"+ + "\1\41\1\42\31\30\7\43\1\0\24\43\14\0\1\44"+ + "\45\0\1\45\31\0\1\46\31\0\1\47\11\0\1\50"+ + "\5\43\1\50\1\22\24\50\2\0\1\42\31\0\7\43"+ + "\1\51\24\43\15\0\1\52\45\0\1\53\26\0\1\54"+ + "\23\0\1\55\21\0\1\50\5\43\1\50\1\56\24\50"+ + "\6\43\1\57\1\51\24\43\16\0\1\60\27\0\1\61"+ + "\46\0\1\62\24\0\1\63\15\0\1\50\5\43\1\64"+ + "\1\56\24\50\1\0\1\65\1\66\50\0\1\67\34\0"+ + "\1\70\13\0\1\22\1\65\1\66\3\0\26\22\2\0"+ + "\1\66\51\0\1\71\27\0\1\72\40\0\1\73\34\0"+ + "\1\74\33\0\1\75\41\0\1\76\34\0\1\77\20\0"+ + "\1\100\44\0\1\101\26\0\1\102\34\0\1\103\10\0"; + + private static int [] zzUnpackTrans() { + int [] result = new int[1484]; + int offset = 0; + offset = zzUnpackTrans(ZZ_TRANS_PACKED_0, offset, result); + return result; + } + + private static int zzUnpackTrans(String packed, int offset, int [] result) { + int i = 0; /* index in packed string */ + int j = offset; /* index in unpacked array */ + int l = packed.length(); + while (i < l) { + int count = packed.charAt(i++); + int value = packed.charAt(i++); + value--; + do result[j++] = value; while (--count > 0); + } + return j; + } + + + /* error codes */ + private static final int ZZ_UNKNOWN_ERROR = 0; + private static final int ZZ_NO_MATCH = 1; + private static final int ZZ_PUSHBACK_2BIG = 2; + + /* error messages for the codes above */ + private static final String[] ZZ_ERROR_MSG = { + "Unknown internal scanner error", + "Error: could not match input", + "Error: pushback value was too large" + }; + + /** + * ZZ_ATTRIBUTE[aState] contains the attributes of state aState + */ + private static final int [] ZZ_ATTRIBUTE = zzUnpackAttribute(); + + private static final String ZZ_ATTRIBUTE_PACKED_0 = + "\3\0\1\11\1\1\1\11\2\1\2\11\5\1\1\11"+ + "\3\1\1\11\4\1\6\0\1\11\2\1\1\11\5\0"+ + "\1\1\5\0\2\1\2\0\2\11\2\1\1\11\6\0"+ + "\1\11\5\0\1\11"; + + private static int [] zzUnpackAttribute() { + int [] result = new int[67]; + int offset = 0; + offset = zzUnpackAttribute(ZZ_ATTRIBUTE_PACKED_0, offset, result); + return result; + } + + private static int zzUnpackAttribute(String packed, int offset, int [] result) { + int i = 0; /* index in packed string */ + int j = offset; /* index in unpacked array */ + int l = packed.length(); + while (i < l) { + int count = packed.charAt(i++); + int value = packed.charAt(i++); + do result[j++] = value; while (--count > 0); + } + return j; + } + + /** the input device */ + private java.io.Reader zzReader; + + /** the current state of the DFA */ + private int zzState; + + /** the current lexical state */ + private int zzLexicalState = YYINITIAL; + + /** this buffer contains the current text to be matched and is + the source of the yytext() string */ + private CharSequence zzBuffer = ""; + + /** the textposition at the last accepting state */ + private int zzMarkedPos; + + /** the current text position in the buffer */ + private int zzCurrentPos; + + /** startRead marks the beginning of the yytext() string in the buffer */ + private int zzStartRead; + + /** endRead marks the last character in the buffer, that has been read + from input */ + private int zzEndRead; + + /** + * zzAtBOL == true <=> the scanner is currently at the beginning of a line + */ + private boolean zzAtBOL = true; + + /** zzAtEOF == true <=> the scanner is at the EOF */ + private boolean zzAtEOF; + + /** denotes if the user-EOF-code has already been executed */ + private boolean zzEOFDone; + + /* user code: */ + public StructurizrDSLLexer() { + this(null); + } + + + /** + * Creates a new scanner + * + * @param in the java.io.Reader to read input from. + */ + public StructurizrDSLLexer(java.io.Reader in) { + this.zzReader = in; + } + + + /** + * Unpacks the compressed character translation table. + * + * @param packed the packed character translation table + * @return the unpacked character translation table + */ + private static char [] zzUnpackCMap(String packed) { + int size = 0; + for (int i = 0, length = packed.length(); i < length; i += 2) { + size += packed.charAt(i); + } + char[] map = new char[size]; + int i = 0; /* index in packed string */ + int j = 0; /* index in unpacked array */ + while (i < packed.length()) { + int count = packed.charAt(i++); + char value = packed.charAt(i++); + do map[j++] = value; while (--count > 0); + } + return map; + } + + public final int getTokenStart() { + return zzStartRead; + } + + public final int getTokenEnd() { + return getTokenStart() + yylength(); + } + + public void reset(CharSequence buffer, int start, int end, int initialState) { + zzBuffer = buffer; + zzCurrentPos = zzMarkedPos = zzStartRead = start; + zzAtEOF = false; + zzAtBOL = true; + zzEndRead = end; + yybegin(initialState); + } + + /** + * Refills the input buffer. + * + * @return false, iff there was new input. + * + * @exception java.io.IOException if any I/O-Error occurs + */ + private boolean zzRefill() throws java.io.IOException { + return true; + } + + + /** + * Returns the current lexical state. + */ + public final int yystate() { + return zzLexicalState; + } + + + /** + * Enters a new lexical state + * + * @param newState the new lexical state + */ + public final void yybegin(int newState) { + zzLexicalState = newState; + } + + + /** + * Returns the text matched by the current regular expression. + */ + public final CharSequence yytext() { + return zzBuffer.subSequence(zzStartRead, zzMarkedPos); + } + + + /** + * Returns the character at position pos from the + * matched text. + * + * It is equivalent to yytext().charAt(pos), but faster + * + * @param pos the position of the character to fetch. + * A value from 0 to yylength()-1. + * + * @return the character at position pos + */ + public final char yycharat(int pos) { + return zzBuffer.charAt(zzStartRead+pos); + } + + + /** + * Returns the length of the matched text region. + */ + public final int yylength() { + return zzMarkedPos-zzStartRead; + } + + + /** + * Reports an error that occured while scanning. + * + * In a wellformed scanner (no or only correct usage of + * yypushback(int) and a match-all fallback rule) this method + * will only be called with things that "Can't Possibly Happen". + * If this method is called, something is seriously wrong + * (e.g. a JFlex bug producing a faulty scanner etc.). + * + * Usual syntax/scanner level error handling should be done + * in error fallback rules. + * + * @param errorCode the code of the errormessage to display + */ + private void zzScanError(int errorCode) { + String message; + try { + message = ZZ_ERROR_MSG[errorCode]; + } + catch (ArrayIndexOutOfBoundsException e) { + message = ZZ_ERROR_MSG[ZZ_UNKNOWN_ERROR]; + } + + throw new Error(message); + } + + + /** + * Pushes the specified amount of characters back into the input stream. + * + * They will be read again by then next call of the scanning method + * + * @param number the number of characters to be read again. + * This number must not be greater than yylength()! + */ + public void yypushback(int number) { + if ( number > yylength() ) + zzScanError(ZZ_PUSHBACK_2BIG); + + zzMarkedPos -= number; + } + + + /** + * Resumes scanning until the next regular expression is matched, + * the end of input is encountered or an I/O-Error occurs. + * + * @return the next token + * @exception java.io.IOException if any I/O-Error occurs + */ + public IElementType advance() throws java.io.IOException { + int zzInput; + int zzAction; + + // cached fields: + int zzCurrentPosL; + int zzMarkedPosL; + int zzEndReadL = zzEndRead; + CharSequence zzBufferL = zzBuffer; + + int [] zzTransL = ZZ_TRANS; + int [] zzRowMapL = ZZ_ROWMAP; + int [] zzAttrL = ZZ_ATTRIBUTE; + + while (true) { + zzMarkedPosL = zzMarkedPos; + + if (zzMarkedPosL > zzStartRead) { + switch (zzBufferL.charAt(zzMarkedPosL-1)) { + case '\n': + case '\u000B': // fall though + case '\u000C': // fall though + case '\u0085': // fall though + case '\u2028': // fall though + case '\u2029': // fall though + zzAtBOL = true; + break; + case '\r': + if (zzMarkedPosL < zzEndReadL) + zzAtBOL = zzBufferL.charAt(zzMarkedPosL) != '\n'; + else if (zzAtEOF) + zzAtBOL = false; + else { + boolean eof = zzRefill(); + zzMarkedPosL = zzMarkedPos; + zzEndReadL = zzEndRead; + zzBufferL = zzBuffer; + if (eof) + zzAtBOL = false; + else + zzAtBOL = zzBufferL.charAt(zzMarkedPosL) != '\n'; + } + break; + default: + zzAtBOL = false; + } + } + zzAction = -1; + + zzCurrentPosL = zzCurrentPos = zzStartRead = zzMarkedPosL; + + if (zzAtBOL) + zzState = ZZ_LEXSTATE[zzLexicalState+1]; + else + zzState = ZZ_LEXSTATE[zzLexicalState]; + + // set up zzAction for empty match case: + int zzAttributes = zzAttrL[zzState]; + if ( (zzAttributes & 1) == 1 ) { + zzAction = zzState; + } + + + zzForAction: { + while (true) { + + if (zzCurrentPosL < zzEndReadL) { + zzInput = Character.codePointAt(zzBufferL, zzCurrentPosL/*, zzEndReadL*/); + zzCurrentPosL += Character.charCount(zzInput); + } + else if (zzAtEOF) { + zzInput = YYEOF; + break zzForAction; + } + else { + // store back cached positions + zzCurrentPos = zzCurrentPosL; + zzMarkedPos = zzMarkedPosL; + boolean eof = zzRefill(); + // get translated positions and possibly new buffer + zzCurrentPosL = zzCurrentPos; + zzMarkedPosL = zzMarkedPos; + zzBufferL = zzBuffer; + zzEndReadL = zzEndRead; + if (eof) { + zzInput = YYEOF; + break zzForAction; + } + else { + zzInput = Character.codePointAt(zzBufferL, zzCurrentPosL/*, zzEndReadL*/); + zzCurrentPosL += Character.charCount(zzInput); + } + } + int zzNext = zzTransL[ zzRowMapL[zzState] + ZZ_CMAP(zzInput) ]; + if (zzNext == -1) break zzForAction; + zzState = zzNext; + + zzAttributes = zzAttrL[zzState]; + if ( (zzAttributes & 1) == 1 ) { + zzAction = zzState; + zzMarkedPosL = zzCurrentPosL; + if ( (zzAttributes & 8) == 8 ) break zzForAction; + } + + } + } + + // store back cached position + zzMarkedPos = zzMarkedPosL; + + if (zzInput == YYEOF && zzStartRead == zzCurrentPos) { + zzAtEOF = true; + return null; + } + else { + switch (zzAction < 0 ? zzAction : ZZ_ACTION[zzAction]) { + case 1: + { return BAD_CHARACTER; + } + // fall through + case 15: break; + case 2: + { return LINE_TERMINATOR; + } + // fall through + case 16: break; + case 3: + { return WHITE_SPACE; + } + // fall through + case 17: break; + case 4: + { return BRACE1; + } + // fall through + case 18: break; + case 5: + { return BRACE2; + } + // fall through + case 19: break; + case 6: + { return UNQUOTED_TEXT; + } + // fall through + case 20: break; + case 7: + { yybegin(YYINITIAL); return LINE_TERMINATOR; + } + // fall through + case 21: break; + case 8: + { return LINE_COMMENT; + } + // fall through + case 22: break; + case 9: + { return QUOTED_TEXT; + } + // fall through + case 23: break; + case 10: + { return BLOCK_COMMENT; + } + // fall through + case 24: break; + case 11: + { return MODEL_KEYWORD; + } + // fall through + case 25: break; + case 12: + { return VIEWS_KEYWORD; + } + // fall through + case 26: break; + case 13: + { yybegin(ARGUMENTS); return WORKSPACE_KEYWORD; + } + // fall through + case 27: break; + case 14: + { yybegin(ARGUMENTS); return SOFTWARE_SYSTEM_KEYWORD; + } + // fall through + case 28: break; + default: + zzScanError(ZZ_NO_MATCH); + } + } + } + } + + +} diff --git a/src/main/gen/nl/dirkgroot/structurizr/dsl/StructurizrDSLParser.java b/src/main/gen/nl/dirkgroot/structurizr/dsl/StructurizrDSLParser.java new file mode 100644 index 0000000..57de329 --- /dev/null +++ b/src/main/gen/nl/dirkgroot/structurizr/dsl/StructurizrDSLParser.java @@ -0,0 +1,340 @@ +// This is a generated file. Not intended for manual editing. +package nl.dirkgroot.structurizr.dsl; + +import com.intellij.lang.PsiBuilder; +import com.intellij.lang.PsiBuilder.Marker; +import static nl.dirkgroot.structurizr.dsl.psi.SDTypes.*; +import static com.intellij.lang.parser.GeneratedParserUtilBase.*; +import com.intellij.psi.tree.IElementType; +import com.intellij.lang.ASTNode; +import com.intellij.psi.tree.TokenSet; +import com.intellij.lang.PsiParser; +import com.intellij.lang.LightPsiParser; + +@SuppressWarnings({"SimplifiableIfStatement", "UnusedAssignment"}) +public class StructurizrDSLParser implements PsiParser, LightPsiParser { + + public ASTNode parse(IElementType t, PsiBuilder b) { + parseLight(t, b); + return b.getTreeBuilt(); + } + + public void parseLight(IElementType t, PsiBuilder b) { + boolean r; + b = adapt_builder_(t, b, this, null); + Marker m = enter_section_(b, 0, _COLLAPSE_, null); + r = parse_root_(t, b); + exit_section_(b, 0, m, t, r, true, TRUE_CONDITION); + } + + protected boolean parse_root_(IElementType t, PsiBuilder b) { + return parse_root_(t, b, 0); + } + + static boolean parse_root_(IElementType t, PsiBuilder b, int l) { + return structurizrDSLFile(b, l + 1); + } + + /* ********************************************************** */ + // quotedArgument | unquotedArgument + static boolean argument(PsiBuilder b, int l) { + if (!recursion_guard_(b, l, "argument")) return false; + if (!nextTokenIs(b, "", QUOTED_TEXT, UNQUOTED_TEXT)) return false; + boolean r; + r = quotedArgument(b, l + 1); + if (!r) r = unquotedArgument(b, l + 1); + return r; + } + + /* ********************************************************** */ + // argument + public static boolean descriptionArgument(PsiBuilder b, int l) { + if (!recursion_guard_(b, l, "descriptionArgument")) return false; + if (!nextTokenIs(b, "", QUOTED_TEXT, UNQUOTED_TEXT)) return false; + boolean r; + Marker m = enter_section_(b, l, _NONE_, DESCRIPTION_ARGUMENT, ""); + r = argument(b, l + 1); + exit_section_(b, l, m, r, false, null); + return r; + } + + /* ********************************************************** */ + // LINE_TERMINATOR | <> + static boolean eol(PsiBuilder b, int l) { + if (!recursion_guard_(b, l, "eol")) return false; + boolean r; + Marker m = enter_section_(b); + r = consumeToken(b, LINE_TERMINATOR); + if (!r) r = eof(b, l + 1); + exit_section_(b, m, null, r); + return r; + } + + /* ********************************************************** */ + // MODEL_KEYWORD (BRACE1 eol modelSectionElements BRACE2)? eol + public static boolean modelSection(PsiBuilder b, int l) { + if (!recursion_guard_(b, l, "modelSection")) return false; + if (!nextTokenIs(b, MODEL_KEYWORD)) return false; + boolean r; + Marker m = enter_section_(b); + r = consumeToken(b, MODEL_KEYWORD); + r = r && modelSection_1(b, l + 1); + r = r && eol(b, l + 1); + exit_section_(b, m, MODEL_SECTION, r); + return r; + } + + // (BRACE1 eol modelSectionElements BRACE2)? + private static boolean modelSection_1(PsiBuilder b, int l) { + if (!recursion_guard_(b, l, "modelSection_1")) return false; + modelSection_1_0(b, l + 1); + return true; + } + + // BRACE1 eol modelSectionElements BRACE2 + private static boolean modelSection_1_0(PsiBuilder b, int l) { + if (!recursion_guard_(b, l, "modelSection_1_0")) return false; + boolean r; + Marker m = enter_section_(b); + r = consumeToken(b, BRACE1); + r = r && eol(b, l + 1); + r = r && modelSectionElements(b, l + 1); + r = r && consumeToken(b, BRACE2); + exit_section_(b, m, null, r); + return r; + } + + /* ********************************************************** */ + // softwareSystem* + static boolean modelSectionElements(PsiBuilder b, int l) { + if (!recursion_guard_(b, l, "modelSectionElements")) return false; + while (true) { + int c = current_position_(b); + if (!softwareSystem(b, l + 1)) break; + if (!empty_element_parsed_guard_(b, "modelSectionElements", c)) break; + } + return true; + } + + /* ********************************************************** */ + // argument + public static boolean nameArgument(PsiBuilder b, int l) { + if (!recursion_guard_(b, l, "nameArgument")) return false; + if (!nextTokenIs(b, "", QUOTED_TEXT, UNQUOTED_TEXT)) return false; + boolean r; + Marker m = enter_section_(b, l, _NONE_, NAME_ARGUMENT, ""); + r = argument(b, l + 1); + exit_section_(b, l, m, r, false, null); + return r; + } + + /* ********************************************************** */ + // QUOTED_TEXT + static boolean quotedArgument(PsiBuilder b, int l) { + return consumeToken(b, QUOTED_TEXT); + } + + /* ********************************************************** */ + // SOFTWARE_SYSTEM_KEYWORD nameArgument descriptionArgument? tagsArgument? eol + public static boolean softwareSystem(PsiBuilder b, int l) { + if (!recursion_guard_(b, l, "softwareSystem")) return false; + if (!nextTokenIs(b, SOFTWARE_SYSTEM_KEYWORD)) return false; + boolean r; + Marker m = enter_section_(b); + r = consumeToken(b, SOFTWARE_SYSTEM_KEYWORD); + r = r && nameArgument(b, l + 1); + r = r && softwareSystem_2(b, l + 1); + r = r && softwareSystem_3(b, l + 1); + r = r && eol(b, l + 1); + exit_section_(b, m, SOFTWARE_SYSTEM, r); + return r; + } + + // descriptionArgument? + private static boolean softwareSystem_2(PsiBuilder b, int l) { + if (!recursion_guard_(b, l, "softwareSystem_2")) return false; + descriptionArgument(b, l + 1); + return true; + } + + // tagsArgument? + private static boolean softwareSystem_3(PsiBuilder b, int l) { + if (!recursion_guard_(b, l, "softwareSystem_3")) return false; + tagsArgument(b, l + 1); + return true; + } + + /* ********************************************************** */ + // workspace | workspaceSection | modelSectionElements + static boolean structurizrDSLFile(PsiBuilder b, int l) { + if (!recursion_guard_(b, l, "structurizrDSLFile")) return false; + boolean r; + r = workspace(b, l + 1); + if (!r) r = workspaceSection(b, l + 1); + if (!r) r = modelSectionElements(b, l + 1); + return r; + } + + /* ********************************************************** */ + // argument + public static boolean tagsArgument(PsiBuilder b, int l) { + if (!recursion_guard_(b, l, "tagsArgument")) return false; + if (!nextTokenIs(b, "", QUOTED_TEXT, UNQUOTED_TEXT)) return false; + boolean r; + Marker m = enter_section_(b, l, _NONE_, TAGS_ARGUMENT, ""); + r = argument(b, l + 1); + exit_section_(b, l, m, r, false, null); + return r; + } + + /* ********************************************************** */ + // UNQUOTED_TEXT + static boolean unquotedArgument(PsiBuilder b, int l) { + return consumeToken(b, UNQUOTED_TEXT); + } + + /* ********************************************************** */ + // VIEWS_KEYWORD BRACE1 eol BRACE2 eol + public static boolean viewsSection(PsiBuilder b, int l) { + if (!recursion_guard_(b, l, "viewsSection")) return false; + if (!nextTokenIs(b, VIEWS_KEYWORD)) return false; + boolean r; + Marker m = enter_section_(b); + r = consumeTokens(b, 0, VIEWS_KEYWORD, BRACE1); + r = r && eol(b, l + 1); + r = r && consumeToken(b, BRACE2); + r = r && eol(b, l + 1); + exit_section_(b, m, VIEWS_SECTION, r); + return r; + } + + /* ********************************************************** */ + // workspaceDefinition (BRACE1 eol workspaceElements? BRACE2)? eol + public static boolean workspace(PsiBuilder b, int l) { + if (!recursion_guard_(b, l, "workspace")) return false; + if (!nextTokenIs(b, WORKSPACE_KEYWORD)) return false; + boolean r; + Marker m = enter_section_(b); + r = workspaceDefinition(b, l + 1); + r = r && workspace_1(b, l + 1); + r = r && eol(b, l + 1); + exit_section_(b, m, WORKSPACE, r); + return r; + } + + // (BRACE1 eol workspaceElements? BRACE2)? + private static boolean workspace_1(PsiBuilder b, int l) { + if (!recursion_guard_(b, l, "workspace_1")) return false; + workspace_1_0(b, l + 1); + return true; + } + + // BRACE1 eol workspaceElements? BRACE2 + private static boolean workspace_1_0(PsiBuilder b, int l) { + if (!recursion_guard_(b, l, "workspace_1_0")) return false; + boolean r; + Marker m = enter_section_(b); + r = consumeToken(b, BRACE1); + r = r && eol(b, l + 1); + r = r && workspace_1_0_2(b, l + 1); + r = r && consumeToken(b, BRACE2); + exit_section_(b, m, null, r); + return r; + } + + // workspaceElements? + private static boolean workspace_1_0_2(PsiBuilder b, int l) { + if (!recursion_guard_(b, l, "workspace_1_0_2")) return false; + workspaceElements(b, l + 1); + return true; + } + + /* ********************************************************** */ + // WORKSPACE_KEYWORD nameArgument? descriptionArgument? + static boolean workspaceDefinition(PsiBuilder b, int l) { + if (!recursion_guard_(b, l, "workspaceDefinition")) return false; + if (!nextTokenIs(b, WORKSPACE_KEYWORD)) return false; + boolean r; + Marker m = enter_section_(b); + r = consumeToken(b, WORKSPACE_KEYWORD); + r = r && workspaceDefinition_1(b, l + 1); + r = r && workspaceDefinition_2(b, l + 1); + exit_section_(b, m, null, r); + return r; + } + + // nameArgument? + private static boolean workspaceDefinition_1(PsiBuilder b, int l) { + if (!recursion_guard_(b, l, "workspaceDefinition_1")) return false; + nameArgument(b, l + 1); + return true; + } + + // descriptionArgument? + private static boolean workspaceDefinition_2(PsiBuilder b, int l) { + if (!recursion_guard_(b, l, "workspaceDefinition_2")) return false; + descriptionArgument(b, l + 1); + return true; + } + + /* ********************************************************** */ + // (modelSection viewsSection?) | (viewsSection modelSection?) + static boolean workspaceElements(PsiBuilder b, int l) { + if (!recursion_guard_(b, l, "workspaceElements")) return false; + if (!nextTokenIs(b, "", MODEL_KEYWORD, VIEWS_KEYWORD)) return false; + boolean r; + Marker m = enter_section_(b); + r = workspaceElements_0(b, l + 1); + if (!r) r = workspaceElements_1(b, l + 1); + exit_section_(b, m, null, r); + return r; + } + + // modelSection viewsSection? + private static boolean workspaceElements_0(PsiBuilder b, int l) { + if (!recursion_guard_(b, l, "workspaceElements_0")) return false; + boolean r; + Marker m = enter_section_(b); + r = modelSection(b, l + 1); + r = r && workspaceElements_0_1(b, l + 1); + exit_section_(b, m, null, r); + return r; + } + + // viewsSection? + private static boolean workspaceElements_0_1(PsiBuilder b, int l) { + if (!recursion_guard_(b, l, "workspaceElements_0_1")) return false; + viewsSection(b, l + 1); + return true; + } + + // viewsSection modelSection? + private static boolean workspaceElements_1(PsiBuilder b, int l) { + if (!recursion_guard_(b, l, "workspaceElements_1")) return false; + boolean r; + Marker m = enter_section_(b); + r = viewsSection(b, l + 1); + r = r && workspaceElements_1_1(b, l + 1); + exit_section_(b, m, null, r); + return r; + } + + // modelSection? + private static boolean workspaceElements_1_1(PsiBuilder b, int l) { + if (!recursion_guard_(b, l, "workspaceElements_1_1")) return false; + modelSection(b, l + 1); + return true; + } + + /* ********************************************************** */ + // modelSection | viewsSection + static boolean workspaceSection(PsiBuilder b, int l) { + if (!recursion_guard_(b, l, "workspaceSection")) return false; + if (!nextTokenIs(b, "", MODEL_KEYWORD, VIEWS_KEYWORD)) return false; + boolean r; + r = modelSection(b, l + 1); + if (!r) r = viewsSection(b, l + 1); + return r; + } + +} diff --git a/src/main/gen/nl/dirkgroot/structurizr/dsl/psi/SDDescriptionArgument.java b/src/main/gen/nl/dirkgroot/structurizr/dsl/psi/SDDescriptionArgument.java new file mode 100644 index 0000000..0680d6c --- /dev/null +++ b/src/main/gen/nl/dirkgroot/structurizr/dsl/psi/SDDescriptionArgument.java @@ -0,0 +1,10 @@ +// This is a generated file. Not intended for manual editing. +package nl.dirkgroot.structurizr.dsl.psi; + +import java.util.List; +import org.jetbrains.annotations.*; +import com.intellij.psi.PsiElement; + +public interface SDDescriptionArgument extends PsiElement { + +} diff --git a/src/main/gen/nl/dirkgroot/structurizr/dsl/psi/SDModelSection.java b/src/main/gen/nl/dirkgroot/structurizr/dsl/psi/SDModelSection.java new file mode 100644 index 0000000..92a2a59 --- /dev/null +++ b/src/main/gen/nl/dirkgroot/structurizr/dsl/psi/SDModelSection.java @@ -0,0 +1,13 @@ +// This is a generated file. Not intended for manual editing. +package nl.dirkgroot.structurizr.dsl.psi; + +import java.util.List; +import org.jetbrains.annotations.*; +import com.intellij.psi.PsiElement; + +public interface SDModelSection extends PsiElement { + + @NotNull + List getSoftwareSystemList(); + +} diff --git a/src/main/gen/nl/dirkgroot/structurizr/dsl/psi/SDNameArgument.java b/src/main/gen/nl/dirkgroot/structurizr/dsl/psi/SDNameArgument.java new file mode 100644 index 0000000..ca3d896 --- /dev/null +++ b/src/main/gen/nl/dirkgroot/structurizr/dsl/psi/SDNameArgument.java @@ -0,0 +1,10 @@ +// This is a generated file. Not intended for manual editing. +package nl.dirkgroot.structurizr.dsl.psi; + +import java.util.List; +import org.jetbrains.annotations.*; +import com.intellij.psi.PsiElement; + +public interface SDNameArgument extends PsiElement { + +} diff --git a/src/main/gen/nl/dirkgroot/structurizr/dsl/psi/SDSoftwareSystem.java b/src/main/gen/nl/dirkgroot/structurizr/dsl/psi/SDSoftwareSystem.java new file mode 100644 index 0000000..de8b8bb --- /dev/null +++ b/src/main/gen/nl/dirkgroot/structurizr/dsl/psi/SDSoftwareSystem.java @@ -0,0 +1,29 @@ +// This is a generated file. Not intended for manual editing. +package nl.dirkgroot.structurizr.dsl.psi; + +import java.util.List; +import org.jetbrains.annotations.*; +import com.intellij.psi.PsiElement; +import java.util.Set; + +public interface SDSoftwareSystem extends SDElementWithName, SDElementWithDescription, SDElementWithTags { + + @Nullable + SDDescriptionArgument getDescriptionArgument(); + + @NotNull + SDNameArgument getNameArgument(); + + @Nullable + SDTagsArgument getTagsArgument(); + + @NotNull + String getElementName(); + + @Nullable + String getElementDescription(); + + @NotNull + Set getElementTags(); + +} diff --git a/src/main/gen/nl/dirkgroot/structurizr/dsl/psi/SDTagsArgument.java b/src/main/gen/nl/dirkgroot/structurizr/dsl/psi/SDTagsArgument.java new file mode 100644 index 0000000..9683145 --- /dev/null +++ b/src/main/gen/nl/dirkgroot/structurizr/dsl/psi/SDTagsArgument.java @@ -0,0 +1,10 @@ +// This is a generated file. Not intended for manual editing. +package nl.dirkgroot.structurizr.dsl.psi; + +import java.util.List; +import org.jetbrains.annotations.*; +import com.intellij.psi.PsiElement; + +public interface SDTagsArgument extends PsiElement { + +} diff --git a/src/main/gen/nl/dirkgroot/structurizr/dsl/psi/SDTypes.java b/src/main/gen/nl/dirkgroot/structurizr/dsl/psi/SDTypes.java new file mode 100644 index 0000000..f043122 --- /dev/null +++ b/src/main/gen/nl/dirkgroot/structurizr/dsl/psi/SDTypes.java @@ -0,0 +1,58 @@ +// This is a generated file. Not intended for manual editing. +package nl.dirkgroot.structurizr.dsl.psi; + +import com.intellij.psi.tree.IElementType; +import com.intellij.psi.PsiElement; +import com.intellij.lang.ASTNode; +import nl.dirkgroot.structurizr.dsl.psi.impl.*; + +public interface SDTypes { + + IElementType DESCRIPTION_ARGUMENT = new SDElement("DESCRIPTION_ARGUMENT"); + IElementType MODEL_SECTION = new SDElement("MODEL_SECTION"); + IElementType NAME_ARGUMENT = new SDElement("NAME_ARGUMENT"); + IElementType SOFTWARE_SYSTEM = new SDElement("SOFTWARE_SYSTEM"); + IElementType TAGS_ARGUMENT = new SDElement("TAGS_ARGUMENT"); + IElementType VIEWS_SECTION = new SDElement("VIEWS_SECTION"); + IElementType WORKSPACE = new SDElement("WORKSPACE"); + + IElementType BLOCK_COMMENT = new SDToken("block_comment"); + IElementType BRACE1 = new SDToken("BRACE1"); + IElementType BRACE2 = new SDToken("BRACE2"); + IElementType LINE_COMMENT = new SDToken("line_comment"); + IElementType LINE_TERMINATOR = new SDToken("LINE_TERMINATOR"); + IElementType MODEL_KEYWORD = new SDToken("MODEL_KEYWORD"); + IElementType QUOTED_TEXT = new SDToken("QUOTED_TEXT"); + IElementType SOFTWARE_SYSTEM_KEYWORD = new SDToken("SOFTWARE_SYSTEM_KEYWORD"); + IElementType UNQUOTED_TEXT = new SDToken("UNQUOTED_TEXT"); + IElementType VIEWS_KEYWORD = new SDToken("VIEWS_KEYWORD"); + IElementType WORKSPACE_KEYWORD = new SDToken("WORKSPACE_KEYWORD"); + + class Factory { + public static PsiElement createElement(ASTNode node) { + IElementType type = node.getElementType(); + if (type == DESCRIPTION_ARGUMENT) { + return new SDDescriptionArgumentImpl(node); + } + else if (type == MODEL_SECTION) { + return new SDModelSectionImpl(node); + } + else if (type == NAME_ARGUMENT) { + return new SDNameArgumentImpl(node); + } + else if (type == SOFTWARE_SYSTEM) { + return new SDSoftwareSystemImpl(node); + } + else if (type == TAGS_ARGUMENT) { + return new SDTagsArgumentImpl(node); + } + else if (type == VIEWS_SECTION) { + return new SDViewsSectionImpl(node); + } + else if (type == WORKSPACE) { + return new SDWorkspaceImpl(node); + } + throw new AssertionError("Unknown element type: " + type); + } + } +} diff --git a/src/main/gen/nl/dirkgroot/structurizr/dsl/psi/SDViewsSection.java b/src/main/gen/nl/dirkgroot/structurizr/dsl/psi/SDViewsSection.java new file mode 100644 index 0000000..2ba8975 --- /dev/null +++ b/src/main/gen/nl/dirkgroot/structurizr/dsl/psi/SDViewsSection.java @@ -0,0 +1,10 @@ +// This is a generated file. Not intended for manual editing. +package nl.dirkgroot.structurizr.dsl.psi; + +import java.util.List; +import org.jetbrains.annotations.*; +import com.intellij.psi.PsiElement; + +public interface SDViewsSection extends PsiElement { + +} diff --git a/src/main/gen/nl/dirkgroot/structurizr/dsl/psi/SDVisitor.java b/src/main/gen/nl/dirkgroot/structurizr/dsl/psi/SDVisitor.java new file mode 100644 index 0000000..74adb35 --- /dev/null +++ b/src/main/gen/nl/dirkgroot/structurizr/dsl/psi/SDVisitor.java @@ -0,0 +1,49 @@ +// This is a generated file. Not intended for manual editing. +package nl.dirkgroot.structurizr.dsl.psi; + +import org.jetbrains.annotations.*; +import com.intellij.psi.PsiElementVisitor; +import com.intellij.psi.PsiElement; + +public class SDVisitor extends PsiElementVisitor { + + public void visitDescriptionArgument(@NotNull SDDescriptionArgument o) { + visitPsiElement(o); + } + + public void visitModelSection(@NotNull SDModelSection o) { + visitPsiElement(o); + } + + public void visitNameArgument(@NotNull SDNameArgument o) { + visitPsiElement(o); + } + + public void visitSoftwareSystem(@NotNull SDSoftwareSystem o) { + visitElementWithName(o); + // visitElementWithDescription(o); + // visitElementWithTags(o); + } + + public void visitTagsArgument(@NotNull SDTagsArgument o) { + visitPsiElement(o); + } + + public void visitViewsSection(@NotNull SDViewsSection o) { + visitPsiElement(o); + } + + public void visitWorkspace(@NotNull SDWorkspace o) { + visitElementWithName(o); + // visitElementWithDescription(o); + } + + public void visitElementWithName(@NotNull SDElementWithName o) { + visitPsiElement(o); + } + + public void visitPsiElement(@NotNull PsiElement o) { + visitElement(o); + } + +} diff --git a/src/main/gen/nl/dirkgroot/structurizr/dsl/psi/SDWorkspace.java b/src/main/gen/nl/dirkgroot/structurizr/dsl/psi/SDWorkspace.java new file mode 100644 index 0000000..3a928e1 --- /dev/null +++ b/src/main/gen/nl/dirkgroot/structurizr/dsl/psi/SDWorkspace.java @@ -0,0 +1,28 @@ +// This is a generated file. Not intended for manual editing. +package nl.dirkgroot.structurizr.dsl.psi; + +import java.util.List; +import org.jetbrains.annotations.*; +import com.intellij.psi.PsiElement; + +public interface SDWorkspace extends SDElementWithName, SDElementWithDescription { + + @Nullable + SDDescriptionArgument getDescriptionArgument(); + + @Nullable + SDModelSection getModelSection(); + + @Nullable + SDNameArgument getNameArgument(); + + @Nullable + SDViewsSection getViewsSection(); + + @NotNull + String getElementName(); + + @Nullable + String getElementDescription(); + +} diff --git a/src/main/gen/nl/dirkgroot/structurizr/dsl/psi/impl/SDDescriptionArgumentImpl.java b/src/main/gen/nl/dirkgroot/structurizr/dsl/psi/impl/SDDescriptionArgumentImpl.java new file mode 100644 index 0000000..5b42564 --- /dev/null +++ b/src/main/gen/nl/dirkgroot/structurizr/dsl/psi/impl/SDDescriptionArgumentImpl.java @@ -0,0 +1,30 @@ +// This is a generated file. Not intended for manual editing. +package nl.dirkgroot.structurizr.dsl.psi.impl; + +import java.util.List; +import org.jetbrains.annotations.*; +import com.intellij.lang.ASTNode; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiElementVisitor; +import com.intellij.psi.util.PsiTreeUtil; +import static nl.dirkgroot.structurizr.dsl.psi.SDTypes.*; +import com.intellij.extapi.psi.ASTWrapperPsiElement; +import nl.dirkgroot.structurizr.dsl.psi.*; + +public class SDDescriptionArgumentImpl extends ASTWrapperPsiElement implements SDDescriptionArgument { + + public SDDescriptionArgumentImpl(@NotNull ASTNode node) { + super(node); + } + + public void accept(@NotNull SDVisitor visitor) { + visitor.visitDescriptionArgument(this); + } + + @Override + public void accept(@NotNull PsiElementVisitor visitor) { + if (visitor instanceof SDVisitor) accept((SDVisitor)visitor); + else super.accept(visitor); + } + +} diff --git a/src/main/gen/nl/dirkgroot/structurizr/dsl/psi/impl/SDModelSectionImpl.java b/src/main/gen/nl/dirkgroot/structurizr/dsl/psi/impl/SDModelSectionImpl.java new file mode 100644 index 0000000..8a1c653 --- /dev/null +++ b/src/main/gen/nl/dirkgroot/structurizr/dsl/psi/impl/SDModelSectionImpl.java @@ -0,0 +1,36 @@ +// This is a generated file. Not intended for manual editing. +package nl.dirkgroot.structurizr.dsl.psi.impl; + +import java.util.List; +import org.jetbrains.annotations.*; +import com.intellij.lang.ASTNode; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiElementVisitor; +import com.intellij.psi.util.PsiTreeUtil; +import static nl.dirkgroot.structurizr.dsl.psi.SDTypes.*; +import com.intellij.extapi.psi.ASTWrapperPsiElement; +import nl.dirkgroot.structurizr.dsl.psi.*; + +public class SDModelSectionImpl extends ASTWrapperPsiElement implements SDModelSection { + + public SDModelSectionImpl(@NotNull ASTNode node) { + super(node); + } + + public void accept(@NotNull SDVisitor visitor) { + visitor.visitModelSection(this); + } + + @Override + public void accept(@NotNull PsiElementVisitor visitor) { + if (visitor instanceof SDVisitor) accept((SDVisitor)visitor); + else super.accept(visitor); + } + + @Override + @NotNull + public List getSoftwareSystemList() { + return PsiTreeUtil.getChildrenOfTypeAsList(this, SDSoftwareSystem.class); + } + +} diff --git a/src/main/gen/nl/dirkgroot/structurizr/dsl/psi/impl/SDNameArgumentImpl.java b/src/main/gen/nl/dirkgroot/structurizr/dsl/psi/impl/SDNameArgumentImpl.java new file mode 100644 index 0000000..d8d21d7 --- /dev/null +++ b/src/main/gen/nl/dirkgroot/structurizr/dsl/psi/impl/SDNameArgumentImpl.java @@ -0,0 +1,30 @@ +// This is a generated file. Not intended for manual editing. +package nl.dirkgroot.structurizr.dsl.psi.impl; + +import java.util.List; +import org.jetbrains.annotations.*; +import com.intellij.lang.ASTNode; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiElementVisitor; +import com.intellij.psi.util.PsiTreeUtil; +import static nl.dirkgroot.structurizr.dsl.psi.SDTypes.*; +import com.intellij.extapi.psi.ASTWrapperPsiElement; +import nl.dirkgroot.structurizr.dsl.psi.*; + +public class SDNameArgumentImpl extends ASTWrapperPsiElement implements SDNameArgument { + + public SDNameArgumentImpl(@NotNull ASTNode node) { + super(node); + } + + public void accept(@NotNull SDVisitor visitor) { + visitor.visitNameArgument(this); + } + + @Override + public void accept(@NotNull PsiElementVisitor visitor) { + if (visitor instanceof SDVisitor) accept((SDVisitor)visitor); + else super.accept(visitor); + } + +} diff --git a/src/main/gen/nl/dirkgroot/structurizr/dsl/psi/impl/SDSoftwareSystemImpl.java b/src/main/gen/nl/dirkgroot/structurizr/dsl/psi/impl/SDSoftwareSystemImpl.java new file mode 100644 index 0000000..0e6d137 --- /dev/null +++ b/src/main/gen/nl/dirkgroot/structurizr/dsl/psi/impl/SDSoftwareSystemImpl.java @@ -0,0 +1,67 @@ +// This is a generated file. Not intended for manual editing. +package nl.dirkgroot.structurizr.dsl.psi.impl; + +import java.util.List; +import org.jetbrains.annotations.*; +import com.intellij.lang.ASTNode; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiElementVisitor; +import com.intellij.psi.util.PsiTreeUtil; +import static nl.dirkgroot.structurizr.dsl.psi.SDTypes.*; +import com.intellij.extapi.psi.ASTWrapperPsiElement; +import nl.dirkgroot.structurizr.dsl.psi.*; +import java.util.Set; + +public class SDSoftwareSystemImpl extends ASTWrapperPsiElement implements SDSoftwareSystem { + + public SDSoftwareSystemImpl(@NotNull ASTNode node) { + super(node); + } + + public void accept(@NotNull SDVisitor visitor) { + visitor.visitSoftwareSystem(this); + } + + @Override + public void accept(@NotNull PsiElementVisitor visitor) { + if (visitor instanceof SDVisitor) accept((SDVisitor)visitor); + else super.accept(visitor); + } + + @Override + @Nullable + public SDDescriptionArgument getDescriptionArgument() { + return findChildByClass(SDDescriptionArgument.class); + } + + @Override + @NotNull + public SDNameArgument getNameArgument() { + return findNotNullChildByClass(SDNameArgument.class); + } + + @Override + @Nullable + public SDTagsArgument getTagsArgument() { + return findChildByClass(SDTagsArgument.class); + } + + @Override + @NotNull + public String getElementName() { + return SDPsiImplUtil.getElementName(this); + } + + @Override + @Nullable + public String getElementDescription() { + return SDPsiImplUtil.getElementDescription(this); + } + + @Override + @NotNull + public Set getElementTags() { + return SDPsiImplUtil.getElementTags(this); + } + +} diff --git a/src/main/gen/nl/dirkgroot/structurizr/dsl/psi/impl/SDTagsArgumentImpl.java b/src/main/gen/nl/dirkgroot/structurizr/dsl/psi/impl/SDTagsArgumentImpl.java new file mode 100644 index 0000000..7ef64b5 --- /dev/null +++ b/src/main/gen/nl/dirkgroot/structurizr/dsl/psi/impl/SDTagsArgumentImpl.java @@ -0,0 +1,30 @@ +// This is a generated file. Not intended for manual editing. +package nl.dirkgroot.structurizr.dsl.psi.impl; + +import java.util.List; +import org.jetbrains.annotations.*; +import com.intellij.lang.ASTNode; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiElementVisitor; +import com.intellij.psi.util.PsiTreeUtil; +import static nl.dirkgroot.structurizr.dsl.psi.SDTypes.*; +import com.intellij.extapi.psi.ASTWrapperPsiElement; +import nl.dirkgroot.structurizr.dsl.psi.*; + +public class SDTagsArgumentImpl extends ASTWrapperPsiElement implements SDTagsArgument { + + public SDTagsArgumentImpl(@NotNull ASTNode node) { + super(node); + } + + public void accept(@NotNull SDVisitor visitor) { + visitor.visitTagsArgument(this); + } + + @Override + public void accept(@NotNull PsiElementVisitor visitor) { + if (visitor instanceof SDVisitor) accept((SDVisitor)visitor); + else super.accept(visitor); + } + +} diff --git a/src/main/gen/nl/dirkgroot/structurizr/dsl/psi/impl/SDViewsSectionImpl.java b/src/main/gen/nl/dirkgroot/structurizr/dsl/psi/impl/SDViewsSectionImpl.java new file mode 100644 index 0000000..c894229 --- /dev/null +++ b/src/main/gen/nl/dirkgroot/structurizr/dsl/psi/impl/SDViewsSectionImpl.java @@ -0,0 +1,30 @@ +// This is a generated file. Not intended for manual editing. +package nl.dirkgroot.structurizr.dsl.psi.impl; + +import java.util.List; +import org.jetbrains.annotations.*; +import com.intellij.lang.ASTNode; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiElementVisitor; +import com.intellij.psi.util.PsiTreeUtil; +import static nl.dirkgroot.structurizr.dsl.psi.SDTypes.*; +import com.intellij.extapi.psi.ASTWrapperPsiElement; +import nl.dirkgroot.structurizr.dsl.psi.*; + +public class SDViewsSectionImpl extends ASTWrapperPsiElement implements SDViewsSection { + + public SDViewsSectionImpl(@NotNull ASTNode node) { + super(node); + } + + public void accept(@NotNull SDVisitor visitor) { + visitor.visitViewsSection(this); + } + + @Override + public void accept(@NotNull PsiElementVisitor visitor) { + if (visitor instanceof SDVisitor) accept((SDVisitor)visitor); + else super.accept(visitor); + } + +} diff --git a/src/main/gen/nl/dirkgroot/structurizr/dsl/psi/impl/SDWorkspaceImpl.java b/src/main/gen/nl/dirkgroot/structurizr/dsl/psi/impl/SDWorkspaceImpl.java new file mode 100644 index 0000000..713fab4 --- /dev/null +++ b/src/main/gen/nl/dirkgroot/structurizr/dsl/psi/impl/SDWorkspaceImpl.java @@ -0,0 +1,66 @@ +// This is a generated file. Not intended for manual editing. +package nl.dirkgroot.structurizr.dsl.psi.impl; + +import java.util.List; +import org.jetbrains.annotations.*; +import com.intellij.lang.ASTNode; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiElementVisitor; +import com.intellij.psi.util.PsiTreeUtil; +import static nl.dirkgroot.structurizr.dsl.psi.SDTypes.*; +import com.intellij.extapi.psi.ASTWrapperPsiElement; +import nl.dirkgroot.structurizr.dsl.psi.*; + +public class SDWorkspaceImpl extends ASTWrapperPsiElement implements SDWorkspace { + + public SDWorkspaceImpl(@NotNull ASTNode node) { + super(node); + } + + public void accept(@NotNull SDVisitor visitor) { + visitor.visitWorkspace(this); + } + + @Override + public void accept(@NotNull PsiElementVisitor visitor) { + if (visitor instanceof SDVisitor) accept((SDVisitor)visitor); + else super.accept(visitor); + } + + @Override + @Nullable + public SDDescriptionArgument getDescriptionArgument() { + return findChildByClass(SDDescriptionArgument.class); + } + + @Override + @Nullable + public SDModelSection getModelSection() { + return findChildByClass(SDModelSection.class); + } + + @Override + @Nullable + public SDNameArgument getNameArgument() { + return findChildByClass(SDNameArgument.class); + } + + @Override + @Nullable + public SDViewsSection getViewsSection() { + return findChildByClass(SDViewsSection.class); + } + + @Override + @NotNull + public String getElementName() { + return SDPsiImplUtil.getElementName(this); + } + + @Override + @Nullable + public String getElementDescription() { + return SDPsiImplUtil.getElementDescription(this); + } + +} diff --git a/src/main/grammar/StructurizrDSL.bnf b/src/main/grammar/StructurizrDSL.bnf new file mode 100644 index 0000000..baae770 --- /dev/null +++ b/src/main/grammar/StructurizrDSL.bnf @@ -0,0 +1,77 @@ +{ + parserClass="nl.dirkgroot.structurizr.dsl.StructurizrDSLParser" + + extends="com.intellij.extapi.psi.ASTWrapperPsiElement" + + psiClassPrefix="SD" + psiImplClassSuffix="Impl" + psiPackage="nl.dirkgroot.structurizr.dsl.psi" + psiImplPackage="nl.dirkgroot.structurizr.dsl.psi.impl" + psiImplUtilClass="nl.dirkgroot.structurizr.dsl.psi.impl.SDPsiImplUtil" + + elementTypeHolderClass="nl.dirkgroot.structurizr.dsl.psi.SDTypes" + elementTypeClass="nl.dirkgroot.structurizr.dsl.psi.SDElement" + tokenTypeClass="nl.dirkgroot.structurizr.dsl.psi.SDToken" + + tokens=[ + line_comment='regexp://[^\r\n]*(\r|\n|\r\n)?' + block_comment='regexp:/\*(.|\n)*\*/' + ] +} + +// +// OVERALL FILE STRUCTURE +// + +structurizrDSLFile ::= workspace | workspaceSection | modelSectionElements +private workspaceSection ::= modelSection | viewsSection + +// +// WORKSPACE +// + +workspace ::= workspaceDefinition (BRACE1 eol workspaceElements? BRACE2)? eol { + methods = [getElementName getElementDescription] + implements = ["SDElementWithName" "SDElementWithDescription"] +} +private workspaceDefinition ::= WORKSPACE_KEYWORD nameArgument? descriptionArgument? +private workspaceElements ::= (modelSection viewsSection?) | (viewsSection modelSection?) + +// +// MODEL SECTION +// + +modelSection ::= MODEL_KEYWORD (BRACE1 eol modelSectionElements BRACE2)? eol +private modelSectionElements ::= softwareSystem* + +// +// SOFTWARE SYSTEM ELEMENT +// + +softwareSystem ::= SOFTWARE_SYSTEM_KEYWORD nameArgument descriptionArgument? tagsArgument? eol { + methods = [getElementName getElementDescription getElementTags] + implements = ["SDElementWithName" "SDElementWithDescription" "SDElementWithTags"] +} + +// +// VIEWS SECTION +// + +viewsSection ::= VIEWS_KEYWORD BRACE1 eol BRACE2 eol + +// +// ARGUMENT MATCHERS +// + +nameArgument ::= argument +descriptionArgument ::= argument +tagsArgument ::= argument +private argument ::= quotedArgument | unquotedArgument +private quotedArgument ::= QUOTED_TEXT +private unquotedArgument ::= UNQUOTED_TEXT + +// +// UTILITIES +// + +private eol ::= LINE_TERMINATOR | <> diff --git a/src/main/grammar/StructurizrDSL.flex b/src/main/grammar/StructurizrDSL.flex new file mode 100644 index 0000000..48865de --- /dev/null +++ b/src/main/grammar/StructurizrDSL.flex @@ -0,0 +1,66 @@ +package nl.dirkgroot.structurizr.dsl; + +import com.intellij.lexer.FlexLexer; +import com.intellij.psi.tree.IElementType; +import static com.intellij.psi.TokenType.BAD_CHARACTER; +import static com.intellij.psi.TokenType.WHITE_SPACE; +import static nl.dirkgroot.structurizr.dsl.psi.SDTypes.*; + +%% + +%{ + public StructurizrDSLLexer() { + this(null); + } +%} + +%public +%class StructurizrDSLLexer +%implements FlexLexer +%function advance +%type IElementType +%unicode + +%state ARGUMENTS + +LINE_TERMINATOR=\r|\n|\r\n +WHITE_SPACE=[ \t\x0B\f]+ +EMPTY_LINE={WHITE_SPACE}* {LINE_TERMINATOR} + +//IDENTIFIER=[a-zA-Z0-9\-_\.]+ + +QUOTED_TEXT=\"[^\"]*\" +UNQUOTED_TEXT=[^\s\"]+ + +LINE_COMMENT="//" [^\r\n]* {LINE_TERMINATOR}? +BLOCK_COMMENT="/*" [^*] ~"*/" {LINE_TERMINATOR}? + +%% + +{LINE_COMMENT} { return LINE_COMMENT; } +{BLOCK_COMMENT} { return BLOCK_COMMENT; } +{WHITE_SPACE} { return WHITE_SPACE; } + + { + ^{EMPTY_LINE} { return WHITE_SPACE; } + {LINE_TERMINATOR} { return LINE_TERMINATOR; } + + "{" { return BRACE1; } + "}" { return BRACE2; } + + "workspace" { yybegin(ARGUMENTS); return WORKSPACE_KEYWORD; } + + "model" { return MODEL_KEYWORD; } + "softwareSystem" { yybegin(ARGUMENTS); return SOFTWARE_SYSTEM_KEYWORD; } + + "views" { return VIEWS_KEYWORD; } +} + + { + {LINE_TERMINATOR} { yybegin(YYINITIAL); return LINE_TERMINATOR; } + "{" { return BRACE1; } + {QUOTED_TEXT} { return QUOTED_TEXT; } + {UNQUOTED_TEXT} { return UNQUOTED_TEXT; } +} + +[^] { return BAD_CHARACTER; } diff --git a/src/main/kotlin/nl/dirkgroot/structurizr/dsl/StructurizrDSLFileType.kt b/src/main/kotlin/nl/dirkgroot/structurizr/dsl/StructurizrDSLFileType.kt new file mode 100644 index 0000000..73a46a5 --- /dev/null +++ b/src/main/kotlin/nl/dirkgroot/structurizr/dsl/StructurizrDSLFileType.kt @@ -0,0 +1,13 @@ +package nl.dirkgroot.structurizr.dsl + +import com.intellij.openapi.fileTypes.LanguageFileType + +object StructurizrDSLFileType : LanguageFileType(StructurizrDSLLanguage) { + override fun getName() = "StructurizrDSL File" + + override fun getDescription() = "StructurizrDSL language file" + + override fun getDefaultExtension() = "dsl" + + override fun getIcon() = StructurizrDSLIcon.icon +} diff --git a/src/main/kotlin/nl/dirkgroot/structurizr/dsl/StructurizrDSLIcon.kt b/src/main/kotlin/nl/dirkgroot/structurizr/dsl/StructurizrDSLIcon.kt new file mode 100644 index 0000000..739a96f --- /dev/null +++ b/src/main/kotlin/nl/dirkgroot/structurizr/dsl/StructurizrDSLIcon.kt @@ -0,0 +1,7 @@ +package nl.dirkgroot.structurizr.dsl + +import com.intellij.openapi.util.IconLoader + +object StructurizrDSLIcon { + val icon = IconLoader.getIcon("/icons/structurizr.png", StructurizrDSLIcon::class.java) +} diff --git a/src/main/kotlin/nl/dirkgroot/structurizr/dsl/StructurizrDSLLanguage.kt b/src/main/kotlin/nl/dirkgroot/structurizr/dsl/StructurizrDSLLanguage.kt new file mode 100644 index 0000000..a478f98 --- /dev/null +++ b/src/main/kotlin/nl/dirkgroot/structurizr/dsl/StructurizrDSLLanguage.kt @@ -0,0 +1,5 @@ +package nl.dirkgroot.structurizr.dsl + +import com.intellij.lang.Language + +object StructurizrDSLLanguage : Language("StructurizrDSL") diff --git a/src/main/kotlin/nl/dirkgroot/structurizr/dsl/lang/SDLexerAdapter.kt b/src/main/kotlin/nl/dirkgroot/structurizr/dsl/lang/SDLexerAdapter.kt new file mode 100644 index 0000000..a6036e9 --- /dev/null +++ b/src/main/kotlin/nl/dirkgroot/structurizr/dsl/lang/SDLexerAdapter.kt @@ -0,0 +1,6 @@ +package nl.dirkgroot.structurizr.dsl.lang + +import com.intellij.lexer.FlexAdapter +import nl.dirkgroot.structurizr.dsl.StructurizrDSLLexer + +class SDLexerAdapter : FlexAdapter(StructurizrDSLLexer()) diff --git a/src/main/kotlin/nl/dirkgroot/structurizr/dsl/lang/StructurizrDSLAnnotator.kt b/src/main/kotlin/nl/dirkgroot/structurizr/dsl/lang/StructurizrDSLAnnotator.kt new file mode 100644 index 0000000..4c5a50b --- /dev/null +++ b/src/main/kotlin/nl/dirkgroot/structurizr/dsl/lang/StructurizrDSLAnnotator.kt @@ -0,0 +1,24 @@ +package nl.dirkgroot.structurizr.dsl.lang + +import com.intellij.lang.annotation.AnnotationHolder +import com.intellij.lang.annotation.Annotator +import com.intellij.psi.PsiElement + +class StructurizrDSLAnnotator : Annotator { + override fun annotate(element: PsiElement, holder: AnnotationHolder) { +// when (element) { +// is SDSoftwareSystemName -> +// holder.createTextAttribute(element, StructurizrDSLSyntaxHighlighter.SOFTWARE_SYSTEM_NAME) +// +// is SDSoftwareSystemIdentifier -> +// holder.createTextAttribute(element, StructurizrDSLSyntaxHighlighter.IDENTIFIER) +// } + } + +// private fun AnnotationHolder.createTextAttribute(element: PsiElement, textAttributesKey: TextAttributesKey) { +// newSilentAnnotation(HighlightSeverity.INFORMATION) +// .range(element) +// .textAttributes(textAttributesKey) +// .create() +// } +} diff --git a/src/main/kotlin/nl/dirkgroot/structurizr/dsl/lang/StructurizrDSLParserDefinition.kt b/src/main/kotlin/nl/dirkgroot/structurizr/dsl/lang/StructurizrDSLParserDefinition.kt new file mode 100644 index 0000000..4048b35 --- /dev/null +++ b/src/main/kotlin/nl/dirkgroot/structurizr/dsl/lang/StructurizrDSLParserDefinition.kt @@ -0,0 +1,42 @@ +package nl.dirkgroot.structurizr.dsl.lang + +import com.intellij.lang.ASTNode +import com.intellij.lang.ParserDefinition +import com.intellij.openapi.project.Project +import com.intellij.psi.FileViewProvider +import com.intellij.psi.PsiElement +import com.intellij.psi.TokenType +import com.intellij.psi.tree.IFileElementType +import com.intellij.psi.tree.TokenSet +import nl.dirkgroot.structurizr.dsl.StructurizrDSLLanguage +import nl.dirkgroot.structurizr.dsl.StructurizrDSLParser +import nl.dirkgroot.structurizr.dsl.psi.SDFile +import nl.dirkgroot.structurizr.dsl.psi.SDTypes + +class StructurizrDSLParserDefinition : ParserDefinition { + companion object { + val WHITE_SPACES = TokenSet.create(TokenType.WHITE_SPACE) + val COMMENTS = TokenSet.create(SDTypes.LINE_COMMENT, SDTypes.BLOCK_COMMENT) + + val FILE = IFileElementType(StructurizrDSLLanguage) + } + + override fun createLexer(project: Project) = SDLexerAdapter() + + override fun getWhitespaceTokens() = WHITE_SPACES + + override fun getCommentTokens() = COMMENTS + + override fun getStringLiteralElements(): TokenSet = TokenSet.EMPTY + + override fun createParser(project: Project?) = StructurizrDSLParser() + + override fun getFileNodeType() = FILE + + override fun createFile(viewProvider: FileViewProvider) = SDFile(viewProvider) + + override fun spaceExistenceTypeBetweenTokens(left: ASTNode?, right: ASTNode?) = + ParserDefinition.SpaceRequirements.MAY + + override fun createElement(node: ASTNode?): PsiElement = SDTypes.Factory.createElement(node) +} diff --git a/src/main/kotlin/nl/dirkgroot/structurizr/dsl/psi/SDElement.kt b/src/main/kotlin/nl/dirkgroot/structurizr/dsl/psi/SDElement.kt new file mode 100644 index 0000000..f2f9791 --- /dev/null +++ b/src/main/kotlin/nl/dirkgroot/structurizr/dsl/psi/SDElement.kt @@ -0,0 +1,6 @@ +package nl.dirkgroot.structurizr.dsl.psi + +import com.intellij.psi.tree.IElementType +import nl.dirkgroot.structurizr.dsl.StructurizrDSLLanguage + +class SDElement(debugName: String) : IElementType(debugName, StructurizrDSLLanguage) diff --git a/src/main/kotlin/nl/dirkgroot/structurizr/dsl/psi/SDElementWithDescription.kt b/src/main/kotlin/nl/dirkgroot/structurizr/dsl/psi/SDElementWithDescription.kt new file mode 100644 index 0000000..01761ac --- /dev/null +++ b/src/main/kotlin/nl/dirkgroot/structurizr/dsl/psi/SDElementWithDescription.kt @@ -0,0 +1,7 @@ +package nl.dirkgroot.structurizr.dsl.psi + +import com.intellij.psi.PsiElement + +interface SDElementWithDescription : PsiElement { + val elementDescription: String +} diff --git a/src/main/kotlin/nl/dirkgroot/structurizr/dsl/psi/SDElementWithName.kt b/src/main/kotlin/nl/dirkgroot/structurizr/dsl/psi/SDElementWithName.kt new file mode 100644 index 0000000..597cb45 --- /dev/null +++ b/src/main/kotlin/nl/dirkgroot/structurizr/dsl/psi/SDElementWithName.kt @@ -0,0 +1,7 @@ +package nl.dirkgroot.structurizr.dsl.psi + +import com.intellij.psi.PsiElement + +interface SDElementWithName : PsiElement { + val elementName: String +} diff --git a/src/main/kotlin/nl/dirkgroot/structurizr/dsl/psi/SDElementWithTags.kt b/src/main/kotlin/nl/dirkgroot/structurizr/dsl/psi/SDElementWithTags.kt new file mode 100644 index 0000000..88e074f --- /dev/null +++ b/src/main/kotlin/nl/dirkgroot/structurizr/dsl/psi/SDElementWithTags.kt @@ -0,0 +1,7 @@ +package nl.dirkgroot.structurizr.dsl.psi + +import com.intellij.psi.PsiElement + +interface SDElementWithTags : PsiElement { + val elementTags: Set +} diff --git a/src/main/kotlin/nl/dirkgroot/structurizr/dsl/psi/SDFile.kt b/src/main/kotlin/nl/dirkgroot/structurizr/dsl/psi/SDFile.kt new file mode 100644 index 0000000..fbd790f --- /dev/null +++ b/src/main/kotlin/nl/dirkgroot/structurizr/dsl/psi/SDFile.kt @@ -0,0 +1,12 @@ +package nl.dirkgroot.structurizr.dsl.psi + +import com.intellij.extapi.psi.PsiFileBase +import com.intellij.psi.FileViewProvider +import nl.dirkgroot.structurizr.dsl.StructurizrDSLFileType +import nl.dirkgroot.structurizr.dsl.StructurizrDSLLanguage + +class SDFile(viewProvider: FileViewProvider) : PsiFileBase(viewProvider, StructurizrDSLLanguage) { + override fun getFileType() = StructurizrDSLFileType + + override fun toString() = "StructurizrDSL File" +} diff --git a/src/main/kotlin/nl/dirkgroot/structurizr/dsl/psi/SDToken.kt b/src/main/kotlin/nl/dirkgroot/structurizr/dsl/psi/SDToken.kt new file mode 100644 index 0000000..9e17468 --- /dev/null +++ b/src/main/kotlin/nl/dirkgroot/structurizr/dsl/psi/SDToken.kt @@ -0,0 +1,8 @@ +package nl.dirkgroot.structurizr.dsl.psi + +import com.intellij.psi.tree.IElementType +import nl.dirkgroot.structurizr.dsl.StructurizrDSLLanguage + +class SDToken(debugName: String) : IElementType(debugName, StructurizrDSLLanguage) { + override fun toString() = "SDToken.${super.toString()}" +} diff --git a/src/main/kotlin/nl/dirkgroot/structurizr/dsl/psi/impl/SDPsiImplUtil.kt b/src/main/kotlin/nl/dirkgroot/structurizr/dsl/psi/impl/SDPsiImplUtil.kt new file mode 100644 index 0000000..4fec736 --- /dev/null +++ b/src/main/kotlin/nl/dirkgroot/structurizr/dsl/psi/impl/SDPsiImplUtil.kt @@ -0,0 +1,30 @@ +package nl.dirkgroot.structurizr.dsl.psi.impl + +import com.intellij.psi.util.childrenOfType +import nl.dirkgroot.structurizr.dsl.psi.* + +class SDPsiImplUtil { + companion object { + @JvmStatic + fun getElementName(element: SDElementWithName): String = + element.childrenOfType() + .first() + .text.trim('"') + + @JvmStatic + fun getElementDescription(element: SDElementWithDescription): String? = + element.childrenOfType() + .firstOrNull() + ?.text?.trim('"') + + @JvmStatic + fun getElementTags(element: SDElementWithTags): Set = + element.childrenOfType().firstOrNull() + ?.text + ?.trim('"') + ?.split(',') + ?.map { it.trim() } + ?.toSet() + ?: emptySet() + } +} diff --git a/src/main/kotlin/nl/dirkgroot/structurizr/dsl/syntax/StructurizrDSLSyntaxHighlighter.kt b/src/main/kotlin/nl/dirkgroot/structurizr/dsl/syntax/StructurizrDSLSyntaxHighlighter.kt new file mode 100644 index 0000000..012f8f8 --- /dev/null +++ b/src/main/kotlin/nl/dirkgroot/structurizr/dsl/syntax/StructurizrDSLSyntaxHighlighter.kt @@ -0,0 +1,52 @@ +package nl.dirkgroot.structurizr.dsl.syntax + +import com.intellij.openapi.editor.DefaultLanguageHighlighterColors +import com.intellij.openapi.editor.colors.TextAttributesKey +import com.intellij.openapi.fileTypes.SyntaxHighlighterBase +import com.intellij.psi.tree.IElementType +import nl.dirkgroot.structurizr.dsl.lang.SDLexerAdapter +import nl.dirkgroot.structurizr.dsl.psi.SDTypes + +class StructurizrDSLSyntaxHighlighter : SyntaxHighlighterBase() { + override fun getHighlightingLexer() = SDLexerAdapter() + + override fun getTokenHighlights(tokenType: IElementType?): Array { + return when (tokenType) { + SDTypes.LINE_COMMENT -> LINE_COMMENT + SDTypes.BLOCK_COMMENT -> BLOCK_COMMENT + + SDTypes.QUOTED_TEXT, + SDTypes.UNQUOTED_TEXT -> STRING + + SDTypes.WORKSPACE_KEYWORD, + SDTypes.MODEL_KEYWORD, + SDTypes.VIEWS_KEYWORD, + SDTypes.SOFTWARE_SYSTEM_KEYWORD -> KEYWORD + + else -> emptyArray() + } + } + + companion object { + private val LINE_COMMENT = arrayOf( + TextAttributesKey.createTextAttributesKey( + "STRUCTURIZR_DSL_LINE_COMMENT", DefaultLanguageHighlighterColors.LINE_COMMENT + ) + ) + private val BLOCK_COMMENT = arrayOf( + TextAttributesKey.createTextAttributesKey( + "STRUCTURIZR_DSL_BLOCK_COMMENT", DefaultLanguageHighlighterColors.BLOCK_COMMENT + ) + ) + private val KEYWORD = arrayOf( + TextAttributesKey.createTextAttributesKey( + "STRUCTURIZR_DSL_KEYWORD", DefaultLanguageHighlighterColors.KEYWORD + ) + ) + private val STRING = arrayOf( + TextAttributesKey.createTextAttributesKey( + "STRUCTURIZR_DSL_STRING", DefaultLanguageHighlighterColors.STRING + ) + ) + } +} diff --git a/src/main/kotlin/nl/dirkgroot/structurizr/dsl/syntax/StructurizrDSLSyntaxHighlighterFactory.kt b/src/main/kotlin/nl/dirkgroot/structurizr/dsl/syntax/StructurizrDSLSyntaxHighlighterFactory.kt new file mode 100644 index 0000000..87d8771 --- /dev/null +++ b/src/main/kotlin/nl/dirkgroot/structurizr/dsl/syntax/StructurizrDSLSyntaxHighlighterFactory.kt @@ -0,0 +1,12 @@ +package nl.dirkgroot.structurizr.dsl.syntax + +import com.intellij.openapi.fileTypes.SyntaxHighlighter +import com.intellij.openapi.fileTypes.SyntaxHighlighterFactory +import com.intellij.openapi.project.Project +import com.intellij.openapi.vfs.VirtualFile + +class StructurizrDSLSyntaxHighlighterFactory : SyntaxHighlighterFactory() { + override fun getSyntaxHighlighter(project: Project?, virtualFile: VirtualFile?): SyntaxHighlighter { + return StructurizrDSLSyntaxHighlighter() + } +} diff --git a/src/main/resources/META-INF/plugin.xml b/src/main/resources/META-INF/plugin.xml new file mode 100644 index 0000000..a595ca4 --- /dev/null +++ b/src/main/resources/META-INF/plugin.xml @@ -0,0 +1,26 @@ + + nl.dirkgroot.structurizr-dsl-plugin + Structurizr DSL Language Support + Dirk Groot + + Adds Structurizr DSL language support to IntelliJ. + + com.intellij.modules.platform + + + + + + + + + + + diff --git a/src/main/resources/icons/structurizr.ico b/src/main/resources/icons/structurizr.ico new file mode 100644 index 0000000..9324ae8 Binary files /dev/null and b/src/main/resources/icons/structurizr.ico differ diff --git a/src/main/resources/icons/structurizr.png b/src/main/resources/icons/structurizr.png new file mode 100644 index 0000000..db051ab Binary files /dev/null and b/src/main/resources/icons/structurizr.png differ diff --git a/src/test/kotlin/nl/dirkgroot/structurizr/dsl/ParseModelSectionTest.kt b/src/test/kotlin/nl/dirkgroot/structurizr/dsl/ParseModelSectionTest.kt new file mode 100644 index 0000000..6442443 --- /dev/null +++ b/src/test/kotlin/nl/dirkgroot/structurizr/dsl/ParseModelSectionTest.kt @@ -0,0 +1,42 @@ +package nl.dirkgroot.structurizr.dsl + +import org.junit.Test + +class ParseModelSectionTest : StructurizrDSLParserTest() { + @Test + fun `plain model keyword`() { + assertParseSucceeds( + "model" + ) + } + + @Test + fun `empty model section`() { + assertParseSucceeds( + """ + model { + } + """.trimIndent() + ) + } + + @Test + fun `model section can have one or more child elements`() { + assertParseSucceeds( + """ + model { + softwareSystem system + } + """.trimIndent() + ) + assertParseSucceeds( + """ + model { + softwareSystem system1 + softwareSystem system2 + softwareSystem system3 + } + """.trimIndent() + ) + } +} diff --git a/src/test/kotlin/nl/dirkgroot/structurizr/dsl/ParseSoftwareSystemTest.kt b/src/test/kotlin/nl/dirkgroot/structurizr/dsl/ParseSoftwareSystemTest.kt new file mode 100644 index 0000000..ca3359f --- /dev/null +++ b/src/test/kotlin/nl/dirkgroot/structurizr/dsl/ParseSoftwareSystemTest.kt @@ -0,0 +1,67 @@ +package nl.dirkgroot.structurizr.dsl + +import assertk.assertThat +import assertk.assertions.containsAll +import assertk.assertions.isEqualTo +import nl.dirkgroot.structurizr.dsl.psi.SDElementWithDescription +import nl.dirkgroot.structurizr.dsl.psi.SDElementWithName +import nl.dirkgroot.structurizr.dsl.psi.SDSoftwareSystem +import org.junit.Test + +class ParseSoftwareSystemTest : StructurizrDSLParserTest() { + @Test + fun `software system with a name`() { + listOf( + "\"Quoted name\"", + "unquoted/name/but/no/identifier", + "unquoted_name_which_qualifies_as_an_identifier", + ).forEach { name -> + val file = assertParseSucceeds( + """ + softwareSystem $name + """.trimIndent() + ) + val softwareSystemElement = file.children[0] as SDElementWithName + assertThat(softwareSystemElement.elementName).isEqualTo(name.trim('"')) + } + } + + @Test + fun `software system with a name and description`() { + listOf( + "\"Quoted description\"", + "unquoted/description/but/no/identifier", + "unquoted_description_which_qualifies_as_an_identifier", + ).forEach { description -> + val file = assertParseSucceeds( + """ + softwareSystem "System name" $description + """.trimIndent() + ) + val softwareSystemElement = file.children[0] as SDElementWithDescription + assertThat(softwareSystemElement.elementDescription).isEqualTo(description.trim('"')) + } + } + + @Test + fun `software system with a name and description and tags`() { + val file = assertParseSucceeds( + """ + softwareSystem "System name" "System description" "quoted tag" + softwareSystem "System name" "System description" "quoted_tag" + softwareSystem "System name" "System description" "quoted_tag1,quoted tag2" + softwareSystem "System name" "System description" "quoted_tag1, quoted tag2" + softwareSystem "System name" "System description" unquoted_tag + softwareSystem "System name" "System description" unquoted_tag1,unquoted_tag2 + """.trimIndent() + ) + val softwareSystems = file.children.filterIsInstance() + + assertThat(softwareSystems[0].elementTags).containsAll("quoted tag") + assertThat(softwareSystems[1].elementTags).containsAll("quoted_tag") + assertThat(softwareSystems[2].elementTags).containsAll("quoted_tag1", "quoted tag2") + assertThat(softwareSystems[3].elementTags).containsAll("quoted_tag1", "quoted tag2") + assertThat(softwareSystems[4].elementTags).containsAll("unquoted_tag") + assertThat(softwareSystems[5].elementTags).containsAll("unquoted_tag1", "unquoted_tag2") + } +} diff --git a/src/test/kotlin/nl/dirkgroot/structurizr/dsl/ParseWorkspaceTest.kt b/src/test/kotlin/nl/dirkgroot/structurizr/dsl/ParseWorkspaceTest.kt new file mode 100644 index 0000000..101ba78 --- /dev/null +++ b/src/test/kotlin/nl/dirkgroot/structurizr/dsl/ParseWorkspaceTest.kt @@ -0,0 +1,137 @@ +package nl.dirkgroot.structurizr.dsl + +import assertk.assertThat +import assertk.assertions.isEqualTo +import nl.dirkgroot.structurizr.dsl.psi.SDWorkspace +import org.junit.Test + +class ParseWorkspaceTest : StructurizrDSLParserTest() { + @Test + fun `plain workspace keyword`() { + assertParseSucceeds( + "workspace" + ) + } + + @Test + fun `empty workspace`() { + assertParseSucceeds( + """ + workspace { + } + """.trimIndent() + ) + } + + @Test + fun `workspace with name`() { + val file = assertParseSucceeds( + """ + workspace "Workspace name" { + } + """.trimIndent() + ) + val workspace = file.children.filterIsInstance().single() + assertThat(workspace.elementName).isEqualTo("Workspace name") + } + + @Test + fun `workspace with name and description`() { + val file = assertParseSucceeds( + """ + workspace "Workspace name" "Workspace description" { + } + """.trimIndent() + ) + val workspace = file.children.filterIsInstance().single() + assertThat(workspace.elementDescription).isEqualTo("Workspace description") + } + + @Test + fun `workspace with model section`() { + assertParseSucceeds( + """ + workspace { + model { + } + } + """.trimIndent() + ) + } + + @Test + fun `workspace with model and views section`() { + assertParseSucceeds( + """ + workspace { + model { + } + views { + } + } + """.trimIndent() + ) + assertParseSucceeds( + """ + workspace { + views { + } + model { + } + } + """.trimIndent() + ) + } + + @Test + fun `workspace with views section`() { + assertParseSucceeds( + """ + workspace { + views { + } + } + """.trimIndent() + ) + } + + @Test + fun `allow max 1 workspace`() { + assertParseFails( + """ + workspace { + } + workspace { + } + """.trimIndent() + ) + } + + @Test + fun `max 1 model section`() { + assertParseFails( + """ + workspace { + model { + } + model { + } + } + """.trimIndent() + ) + } + + @Test + fun `max 1 views section`() { + assertParseFails( + """ + workspace { + views { + } + views { + } + } + """.trimIndent() + ) + } +} diff --git a/src/test/kotlin/nl/dirkgroot/structurizr/dsl/StructurizrDSLParserTest.kt b/src/test/kotlin/nl/dirkgroot/structurizr/dsl/StructurizrDSLParserTest.kt new file mode 100644 index 0000000..26e10ff --- /dev/null +++ b/src/test/kotlin/nl/dirkgroot/structurizr/dsl/StructurizrDSLParserTest.kt @@ -0,0 +1,51 @@ +package nl.dirkgroot.structurizr.dsl + +import assertk.assertThat +import assertk.assertions.isEmpty +import assertk.assertions.isFailure +import assertk.assertions.isNotEmpty +import com.intellij.psi.PsiErrorElement +import com.intellij.psi.tree.TokenSet +import com.intellij.testFramework.ParsingTestCase +import nl.dirkgroot.structurizr.dsl.lang.StructurizrDSLParserDefinition +import nl.dirkgroot.structurizr.dsl.psi.SDFile +import org.junit.runner.RunWith +import org.junit.runners.JUnit4 + +@RunWith(JUnit4::class) +abstract class StructurizrDSLParserTest : ParsingTestCase("parser", "dsl", StructurizrDSLParserDefinition()) { + protected fun assertParseSucceeds(source: String): SDFile { + val psiFile = parseFile("test.dsl", source) + val root = psiFile.viewProvider.allFiles.first() + + assertThat( + root.node.getChildren(TokenSet.ANY) + .filterIsInstance() + ).isEmpty() + + return root as SDFile + } + + protected fun assertParseFails(source: String) { + val psiFile = parseFile("test.dsl", source) + + val root = psiFile.viewProvider.allFiles.first() + + assertThat( + root.node.getChildren(TokenSet.ANY) + .filterIsInstance() + ).isNotEmpty() + } + + override fun getTestDataPath(): String { + return "src/test/testData" + } + + override fun skipSpaces(): Boolean { + return false + } + + override fun includeRanges(): Boolean { + return true + } +}