From e0a61095d38c3210c618ea72383a009575c146d3 Mon Sep 17 00:00:00 2001 From: Olga Bachishe <52888340+bachish@users.noreply.github.com> Date: Thu, 30 May 2024 13:11:59 +0300 Subject: [PATCH] Benchmarks base (#29) * improve grammar DSL (add initialization in constructor) * replace intersection logic into other objects (intersection engine) to separate input and recovery * replace Java7 sources in examples subproject * update bench_run.sh script for independent generation and running --- .github/workflows/build.yml | 10 +- .gitignore | 8 +- benchmarks/README.md | 19 + benchmarks/build.gradle.kts | 82 ++- benchmarks/generate_antlr_classes.sh | 7 - benchmarks/generate_lexers.sh | 10 - benchmarks/gradle.properties | 3 + .../gradle/wrapper/gradle-wrapper.properties | 5 + benchmarks/gradlew | 234 ++++++++ benchmarks/gradlew.bat | 89 +++ benchmarks/src/jmh/kotlin/JmhBenchmark.kt | 87 --- .../src/jmh/kotlin/grammars/JavaGrammar.kt | 546 ------------------ .../antlr4 => main/java/org/antlr}/Java8.g4 | 2 +- benchmarks/src/main/kotlin/org/Antlr.kt | 25 + benchmarks/src/main/kotlin/org/BaseBench.kt | 17 + benchmarks/src/main/kotlin/org/Benchmarks.kt | 58 ++ benchmarks/src/main/kotlin/org/OfflineGll.kt | 16 + benchmarks/src/main/kotlin/org/OnlineGll.kt | 29 + .../src/main/kotlin/org/RecoveryOfflineGll.kt | 15 + .../src/main/kotlin/org/RecoveryOnlineGll.kt | 29 + examples/build.gradle.kts | 22 + .../src/main/java/java7}/Java.x | 4 +- examples/src/main/kotlin/dyck/DyckGrammar.kt | 19 + examples/src/main/kotlin/java7/Generator.kt | 28 + examples/src/main/kotlin/java7/Java7.kt | 543 +++++++++++++++++ .../src/main/kotlin/java7}/JavaToken.kt | 2 +- .../kotlin/org/ucfs/IGeneratorFromGrammar.kt | 3 - .../main/kotlin/org/ucfs/ast/AstExtractor.kt | 2 + .../src/main/kotlin/org/ucfs/ast/DotWriter.kt | 7 +- .../src/main/kotlin/org/ucfs/ast/Node.kt | 1 + .../org/ucfs/ast/NodeClassesGenerator.kt | 2 +- .../org/ucfs/examples/dyck/DyckGrammar.kt | 14 +- .../org/ucfs/examples/golang/SimpleGolang.kt | 18 +- ...enerator.kt => AbstractParserGenerator.kt} | 153 +++-- .../kotlin/org/ucfs/parser/GeneratedParser.kt | 49 +- .../kotlin/org/ucfs/parser/ParserGenerator.kt | 22 +- .../ucfs/parser/RecoveryParserGenerator.kt | 41 ++ .../ucfs/parser/ScanerlessParserGenerator.kt | 32 +- gradle/wrapper/gradle-wrapper.jar | Bin 60756 -> 43453 bytes gradle/wrapper/gradle-wrapper.properties | 6 +- gradlew | 41 +- gradlew.bat | 35 +- scripts/generate_all.sh | 30 + scripts/run_bench.sh | 14 + settings.gradle.kts | 1 + .../kotlin/org/ucfs/descriptors/Descriptor.kt | 4 + .../org/ucfs/grammar/combinator/Grammar.kt | 11 +- .../combinator/regexp/DerivedSymbol.kt | 1 + .../ucfs/grammar/combinator/regexp/Many.kt | 2 +- .../org/ucfs/grammar/combinator/regexp/Nt.kt | 38 +- .../ucfs/grammar/combinator/regexp/Regexp.kt | 3 - .../src/main/kotlin/org/ucfs/gss/GssNode.kt | 4 +- .../main/kotlin/org/ucfs/input/IInputGraph.kt | 59 +- .../org/ucfs/input/RecoveryLinearInput.kt | 27 - .../ucfs/intersection/IIntersectionEngine.kt | 14 + .../ucfs/intersection/IntersectionEngine.kt | 44 ++ .../RecoveryIntersection.kt} | 98 +--- solver/src/main/kotlin/org/ucfs/parser/Gll.kt | 29 +- .../src/main/kotlin/org/ucfs/parser/IGll.kt | 41 +- .../kotlin/org/ucfs/parser/context/Context.kt | 3 +- .../org/ucfs/parser/context/IContext.kt | 5 +- .../ucfs/parser/context/RecoveryContext.kt | 5 +- .../src/main/kotlin/org/ucfs/rsm/RsmState.kt | 12 +- .../kotlin/org/ucfs/rsm/symbol/Nonterminal.kt | 9 +- .../kotlin/rsm/api/TerminalsEqualsTest.kt | 12 +- .../src/test/kotlin/rsm/builder/AStarTest.kt | 9 +- .../parser/generated/RuntimeCompiler.kt | 24 +- .../grammars/a/ScanerlessGrammarDsl.kt | 7 +- .../grammars/aBStar/ScanerlessGrammarDsl.kt | 8 +- .../grammars/aStar/ScanerlessGrammarDsl.kt | 7 +- .../grammars/ab/ScanerlessGrammarDsl.kt | 9 +- .../grammars/abc/ScanerlessGrammarDsl.kt | 13 +- .../ambiguous/ScanerlessGrammarDsl.kt | 5 +- .../bracket_star_x/ScanerlessGrammarDsl.kt | 8 +- .../cAPlusBStar/ScanerlessGrammarDsl.kt | 13 +- .../c_a_star_b_star/ScanerlessGrammarDsl.kt | 11 +- .../grammars/dyck/ScanerlessGrammarDsl.kt | 5 +- .../grammars/g1/ScanerlessGrammarDsl.kt | 11 +- .../grammars/g2/ScanerlessGrammarDsl.kt | 9 +- .../grammars/geo/ScanerlessGrammarDsl.kt | 10 +- .../multi_dyck/ScanerlessGrammarDsl.kt | 14 +- .../simple_golang/ScanerlessGrammarDsl.kt | 22 +- 82 files changed, 1753 insertions(+), 1233 deletions(-) create mode 100644 benchmarks/README.md delete mode 100755 benchmarks/generate_antlr_classes.sh delete mode 100755 benchmarks/generate_lexers.sh create mode 100644 benchmarks/gradle.properties create mode 100644 benchmarks/gradle/wrapper/gradle-wrapper.properties create mode 100755 benchmarks/gradlew create mode 100644 benchmarks/gradlew.bat delete mode 100644 benchmarks/src/jmh/kotlin/JmhBenchmark.kt delete mode 100644 benchmarks/src/jmh/kotlin/grammars/JavaGrammar.kt rename benchmarks/src/{jmh/kotlin/antlr4 => main/java/org/antlr}/Java8.g4 (99%) create mode 100644 benchmarks/src/main/kotlin/org/Antlr.kt create mode 100644 benchmarks/src/main/kotlin/org/BaseBench.kt create mode 100644 benchmarks/src/main/kotlin/org/Benchmarks.kt create mode 100644 benchmarks/src/main/kotlin/org/OfflineGll.kt create mode 100644 benchmarks/src/main/kotlin/org/OnlineGll.kt create mode 100644 benchmarks/src/main/kotlin/org/RecoveryOfflineGll.kt create mode 100644 benchmarks/src/main/kotlin/org/RecoveryOnlineGll.kt create mode 100644 examples/build.gradle.kts rename {benchmarks/src/jmh/kotlin/lexers => examples/src/main/java/java7}/Java.x (98%) create mode 100644 examples/src/main/kotlin/dyck/DyckGrammar.kt create mode 100644 examples/src/main/kotlin/java7/Generator.kt create mode 100644 examples/src/main/kotlin/java7/Java7.kt rename {benchmarks/src/jmh/kotlin/lexers => examples/src/main/kotlin/java7}/JavaToken.kt (99%) rename generator/src/main/kotlin/org/ucfs/parser/{IParserGenerator.kt => AbstractParserGenerator.kt} (64%) create mode 100644 generator/src/main/kotlin/org/ucfs/parser/RecoveryParserGenerator.kt create mode 100755 scripts/generate_all.sh create mode 100755 scripts/run_bench.sh delete mode 100644 solver/src/main/kotlin/org/ucfs/input/RecoveryLinearInput.kt create mode 100644 solver/src/main/kotlin/org/ucfs/intersection/IIntersectionEngine.kt create mode 100644 solver/src/main/kotlin/org/ucfs/intersection/IntersectionEngine.kt rename solver/src/main/kotlin/org/ucfs/{input/IRecoveryInputGraph.kt => intersection/RecoveryIntersection.kt} (58%) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 9e3393391..8e5abc7e0 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -18,15 +18,17 @@ jobs: java-version: '11' distribution: 'temurin' - - name: Generate JFlex files + - name: Install JFlex run: | sudo apt-get install -y jflex - ./benchmarks/generate_lexers.sh - - name: Generate ANTLR4 files + - name: Install ANTLR4 files run: | sudo apt-get install antlr4 - ./benchmarks/generate_antlr_classes.sh + + - name: Generate files + run: | + ./scripts/generate_all.sh - name: Build with Gradle uses: gradle/gradle-build-action@bd5760595778326ba7f1441bcf7e88b49de61a25 # v2.6.0 diff --git a/.gitignore b/.gitignore index 54882ea3f..60a20ab27 100644 --- a/.gitignore +++ b/.gitignore @@ -52,8 +52,6 @@ out/ hs_err_pid* .gradle -build/ -out/ !gradle/wrapper/gradle-wrapper.jar !**/src/main/**/build/ !**/src/test/**/build/ @@ -88,3 +86,9 @@ bin/ ### Generated files ### /gen/ +/benchmarks/src/main/java/org/antlr/* +!/benchmarks/src/main/java/org/antlr/Java8.g4 +/benchmarks/src/main/kotlin/org/ucfs/* +/benchmarks/src/main/java/org/ucfs/* +/benchmarks/logs/ +/examples/src/main/java/java7/JavaLexer.java diff --git a/benchmarks/README.md b/benchmarks/README.md new file mode 100644 index 000000000..834bee591 --- /dev/null +++ b/benchmarks/README.md @@ -0,0 +1,19 @@ +# UCFSBenchmarks + +## Prerequisites + +```text +(1) Gradle (version >= 7.2) +(2) Antlr V4 +(3) Jflex +``` +## Generate files +Run `/scripts/generate_all.sh` +## Run benchmarks +Set data-set folder and parser mode in script `/scripts/run_bench.sh` and run it + +## Logging + +Logs are stored in `logs` + +Results are stored in `build/reports/benchmarks` diff --git a/benchmarks/build.gradle.kts b/benchmarks/build.gradle.kts index 656654148..d67bc4335 100644 --- a/benchmarks/build.gradle.kts +++ b/benchmarks/build.gradle.kts @@ -1,7 +1,7 @@ plugins { java kotlin("jvm") version "1.9.20" - id("me.champeau.jmh") version "0.7.2" + id("org.jetbrains.kotlinx.benchmark") version "0.4.10" kotlin("plugin.allopen") version "1.9.20" } @@ -11,42 +11,64 @@ repositories { } dependencies { + //benchmarks tool + testImplementation("org.jetbrains.kotlin:kotlin-test") + implementation("org.jetbrains.kotlinx:kotlinx-benchmark-runtime:0.4.10") + //compared projects + // 1. for ucfs implementation(project(":solver")) + implementation(project(":generator")) + implementation(project(":examples")) + // 2. for java_cup (?) implementation("java_cup:java_cup:0.9e") + // 3. for antlr implementation("org.antlr:antlr4:4.13.1") - jmhImplementation("org.openjdk.jmh:jmh-core:1.36") - jmhImplementation("org.openjdk.jmh:jmh-generator-annprocess:1.36") - jmhImplementation("org.openjdk.jmh:jmh-generator-bytecode:1.36") + // 4. for iguana + implementation("io.usethesource:capsule:0.6.3") + implementation("info.picocli:picocli:4.7.0") + implementation("com.google.guava:guava-testlib:23.0") + implementation("com.fasterxml.jackson.core:jackson-core:2.14.0") + implementation("com.fasterxml.jackson.core:jackson-databind:2.14.0") } -kotlin { jvmToolchain(11) } -configure { - named("jmh") { - kotlin.srcDir("benchmarks/src/jmh/kotlin") - resources.srcDir("benchmarks/src/jmh/resources") +fun getArgs(strFolder: String): Array { + val resourcesDir = File(strFolder) + val files = resourcesDir.listFiles()!! + return files.map { it.toString() }.sorted().toTypedArray() +} + +benchmark { + configurations { + named("main") { + val dataset = "dataset" + if (!hasProperty(dataset)) { + println("BENCHMARKS FAILED! Set dataset folder by property '$dataset'") + } + else{ + param("fileName", *getArgs(property(dataset).toString())) + } + this.reportFormat = "csv" + iterations = 15 + iterationTime = 1000 + iterationTimeUnit = "ms" + warmups = 5 + outputTimeUnit = "ms" + mode = "avgt" + val tools = "toolName" + if (hasProperty(tools)) { + println("Run benchmarks for: .*${property(tools)}.*") + include(".*${property(tools)}.*") + } + + } + } + targets { + register("main") } } -jmh { - duplicateClassesStrategy = DuplicatesStrategy.EXCLUDE - zip64 = true - warmupForks = 0 - warmupBatchSize = 1 - warmupIterations = 5 - warmup = "0s" - timeOnIteration = "0s" - fork = 1 - batchSize = 1 - iterations = 15 - verbosity = "EXTRA" - jmhTimeout = "300s" - benchmarkMode.addAll("ss") - failOnError = false - forceGC = true - resultFormat = "CSV" - jvmArgs.addAll("-Xmx4096m", "-Xss4m", "-XX:+UseG1GC") +allOpen { + annotation("org.openjdk.jmh.annotations.State") } -tasks.processJmhResources { - duplicatesStrategy = DuplicatesStrategy.EXCLUDE -} \ No newline at end of file +kotlin { jvmToolchain(11) } \ No newline at end of file diff --git a/benchmarks/generate_antlr_classes.sh b/benchmarks/generate_antlr_classes.sh deleted file mode 100755 index 34637013a..000000000 --- a/benchmarks/generate_antlr_classes.sh +++ /dev/null @@ -1,7 +0,0 @@ -#!/bin/bash - -shopt -s nullglob #ingore failed patterns - -cd ./benchmarks/src/jmh/kotlin/antlr4 - -antlr4 Java8.g4 \ No newline at end of file diff --git a/benchmarks/generate_lexers.sh b/benchmarks/generate_lexers.sh deleted file mode 100755 index e6f390362..000000000 --- a/benchmarks/generate_lexers.sh +++ /dev/null @@ -1,10 +0,0 @@ -#!/bin/bash - -shopt -s nullglob #ingore failed patterns - -cd ./benchmarks/src/jmh/kotlin/lexers - -for lexer_name in *.jflex *.jlex *.lex *.flex *.x -do - jflex $lexer_name -done \ No newline at end of file diff --git a/benchmarks/gradle.properties b/benchmarks/gradle.properties new file mode 100644 index 000000000..2de43ab72 --- /dev/null +++ b/benchmarks/gradle.properties @@ -0,0 +1,3 @@ +kotlin.code.style=official +org.gradle.daemon=true +org.gradle.jvmargs=-Xmx4096m -Xss4m -XX:+UseG1GC \ No newline at end of file diff --git a/benchmarks/gradle/wrapper/gradle-wrapper.properties b/benchmarks/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 000000000..06febab41 --- /dev/null +++ b/benchmarks/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,5 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-8.2-bin.zip +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists \ No newline at end of file diff --git a/benchmarks/gradlew b/benchmarks/gradlew new file mode 100755 index 000000000..1b6c78733 --- /dev/null +++ b/benchmarks/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/benchmarks/gradlew.bat b/benchmarks/gradlew.bat new file mode 100644 index 000000000..107acd32c --- /dev/null +++ b/benchmarks/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/benchmarks/src/jmh/kotlin/JmhBenchmark.kt b/benchmarks/src/jmh/kotlin/JmhBenchmark.kt deleted file mode 100644 index 94c49e50f..000000000 --- a/benchmarks/src/jmh/kotlin/JmhBenchmark.kt +++ /dev/null @@ -1,87 +0,0 @@ -package jmh.kotlin - - -import antlr4.Java8Parser -import antlr4.Java8Lexer -import lexers.JavaLexer -import lexers.JavaToken -import grammars.JavaGrammar -import org.antlr.v4.runtime.CharStreams -import org.antlr.v4.runtime.CommonTokenStream -import org.ucfs.parser.Gll -import org.openjdk.jmh.annotations.* -import org.openjdk.jmh.infra.Blackhole -import org.ucfs.input.LinearInputLabel -import org.ucfs.input.RecoveryLinearInput -import org.ucfs.rsm.symbol.Term -import java.io.File -import java.io.StringReader -import java.util.concurrent.TimeUnit - -val pathToInput = "benchmarks/src/jmh/resources/srcFiles/" - -fun getTokenStream(input: String): RecoveryLinearInput { - val inputGraph = RecoveryLinearInput() - val lexer = JavaLexer(StringReader(input)) - var vertexId = 0 - var token: JavaToken - - inputGraph.addStartVertex(vertexId) - inputGraph.addVertex(vertexId) - - while (true) { - token = lexer.yylex() as JavaToken - if (token == JavaToken.EOF) break - println(token.name) - inputGraph.addEdge(vertexId, LinearInputLabel(Term(token)), ++vertexId) - inputGraph.addVertex(vertexId) - } - - return inputGraph -} - -@State(Scope.Benchmark) -@BenchmarkMode(Mode.SingleShotTime) -open class AntlrBenchmark { - - @Param("OneTestCase_processed.java","NotPublicTestCase_processed.java","NoTestsRemainException_processed.java","OldTests_processed.java","TestRule_processed.java","JUnit4ClassRunner_processed.java","CategoryFilterFactoryTest_processed.java","TestClassTest_processed.java","ObjectContractTest_processed.java","LoggingStatement_processed.java","ThrowableMessageMatcher_processed.java","SortingRequest_processed.java","InheritedTestTest_processed.java","SerializableValueDescription_processed.java","JUnit3Builder_processed.java","FrameworkField_processed.java","JavadocTest_processed.java","SynchronizedRunListenerTest_processed.java","Ordering_processed.java","ClassRulesTest_processed.java","ComparisonCriteria_processed.java","TestDescriptionMethodNameTest_processed.java","JUnit4TestAdapterCache_processed.java","RuleContainer_processed.java","InvalidTestClassError_processed.java","JUnit4TestCaseFacade_processed.java","StubbedTheoriesTest_processed.java","FailedConstructionTest_processed.java","ReflectiveThreadMXBean_processed.java","Theory_processed.java","DataPoint_processed.java","Ignore_processed.java","ExpectedExceptionMatcherBuilder_processed.java","BlockJUnit4ClassRunnerWithParameters_processed.java","TestSystem_processed.java","TestWithParametersTest_processed.java","MultiCategoryTest_processed.java","AllMembersSupplier_processed.java","AnnotationsValidator_processed.java","ActiveTestSuite_processed.java","AssertTest_processed.java","RunListener_processed.java","Assume_processed.java","DataPoints_processed.java","TheoryTestUtils_processed.java","AllDefaultPossibilitiesBuilder_processed.java","TestRuleTest_processed.java","AllAssertionTests_processed.java","InvalidOrderingException_processed.java","ResultPrinter_processed.java","AllManipulationTests_processed.java","TextListenerTest_processed.java","Sortable_processed.java","ParameterizedNamesTest_processed.java","ParameterSignature_processed.java","RunnerBuilderStub_processed.java","ValidationTest_processed.java","StubbedTheories_processed.java","SuiteMethodBuilder_processed.java","AllRunnersTests_processed.java","PotentialAssignment_processed.java","StacktracePrintingMatcher_processed.java","Filterable_processed.java","SystemExitTest_processed.java","Filter_processed.java","MainRunner_processed.java","Result_processed.java","TemporaryFolderUsageTest_processed.java","AllTestsTest_processed.java","MultipleFailureException_processed.java","AssertionFailedError_processed.java","ParallelComputer_processed.java","AfterClass_processed.java","UseSuiteAsASuperclassTest_processed.java","ClassLevelMethodsWithIgnoredTestsTest_processed.java","MethodRulesTest_processed.java","Correspondent_processed.java","TypeMatchingBetweenMultiDataPointsMethod_processed.java","ActiveTestTest_processed.java","TestWatchman_processed.java","BadlyFormedClassesTest_processed.java","TestSuite_processed.java","MaxHistory_processed.java","AllParallelTests_processed.java","ComparisonCompactor_processed.java","ParameterSupplier_processed.java","AllClassesTests_processed.java","BlockJUnit4ClassRunnerWithParametersFactory_processed.java","AnnotatedBuilderTest_processed.java","AllExperimentalTests_processed.java","OverrideTestCase_processed.java","TempFolderRuleTest_processed.java","ComparisonFailureTest_processed.java","Parameterized_processed.java","ExpectExceptionTest_processed.java","PrintableResult_processed.java","ReflectiveRuntimeMXBean_processed.java","AllCoreTests_processed.java","ComparisonFailure_processed.java","RunAfters_processed.java","AlphanumericOrdering_processed.java","TestImplementorTest_processed.java","WithParameterSupplier_processed.java","WasRun_processed.java","MultipleFailureExceptionTest_processed.java","RuleChainTest_processed.java","TestListener_processed.java","Statement_processed.java","RepeatedTestTest_processed.java","BlockJUnit4ClassRunner_processed.java","FilterOptionIntegrationTest_processed.java","TestCaseTest_processed.java","ExpectedTest_processed.java","TextRunnerTest_processed.java","EnclosedTest_processed.java","InexactComparisonCriteria_processed.java","OrderWith_processed.java","IMoney_processed.java","UnsuccessfulWithDataPointFields_processed.java","Theories_processed.java","OrderableTest_processed.java","Protectable_processed.java","StacktracePrintingMatcherTest_processed.java","Description_processed.java","BlockJUnit4ClassRunnerTest_processed.java","ParentRunnerTest_processed.java","SuiteTest_processed.java","WithAutoGeneratedDataPoints_processed.java","ExpectException_processed.java","BaseTestRunnerTest_processed.java","TestDescriptionTest_processed.java","SynchronizedRunListener_processed.java","AllParameterizedTests_processed.java","AllModelTests_processed.java","Comparators_processed.java","ThreeTestCases_processed.java","RuleChain_processed.java","Computer_processed.java","TestClass_processed.java","SuiteDescriptionTest_processed.java","MaxCore_processed.java","CustomBlockJUnit4ClassRunnerTest_processed.java","MemoizingRequest_processed.java","ErrorReportingRunnerTest_processed.java","JUnit38ClassRunner_processed.java","TextListener_processed.java","FakeRuntimeMXBean_processed.java","PublicClassValidatorTest_processed.java","Timeout_processed.java","StopwatchTest_processed.java","ConcurrentRunNotifierTest_processed.java","TestCouldNotBeSkippedException_processed.java","Success_processed.java","LoggingMethodRule_processed.java","FilterFactoryParams_processed.java","AssumptionTest_processed.java","WithExtendedParameterSources_processed.java","FilterableTest_processed.java","AllDescriptionTests_processed.java","JUnit4_processed.java","AllRunnerTests_processed.java","SuiteMethodTest_processed.java","SingleMethodTest_processed.java","Describable_processed.java","JUnit4Builder_processed.java","FrameworkFieldTest_processed.java","IgnoreClassTest_processed.java","JUnitCommandLineParseResultTest_processed.java","MatcherTest_processed.java","ThrowableCauseMatcherTest_processed.java","AssumptionViolatedException_processed.java","CategoryValidatorTest_processed.java","ParentRunnerFilteringTest_processed.java","Orderable_processed.java","TestMethodTest_processed.java","ExternalResource_processed.java","ValidateWith_processed.java","AllCategoriesTests_processed.java","ExcludeCategories_processed.java","StoppedByUserException_processed.java","ParameterizedTestMethodTest_processed.java","FilterFactoriesTest_processed.java","RunBefores_processed.java","AllResultsTests_processed.java","ComparisonCompactorTest_processed.java","PrintableResultTest_processed.java","SampleJUnit3Tests_processed.java","ResultTest_processed.java","WithOnlyTestAnnotations_processed.java","Super_processed.java","TestedOn_processed.java","NullBuilder_processed.java","NoTestCases_processed.java","TestMethod_processed.java","Annotatable_processed.java","AssumptionViolatedExceptionTest_processed.java","NoArgTestCaseTest_processed.java","ErrorCollector_processed.java","AllSamplesTests_processed.java","RealSystem_processed.java","MethodSorterTest_processed.java","ForwardCompatibilityPrintingTest_processed.java","Guesser_processed.java","RepeatedTest_processed.java","TestSetup_processed.java","FilterFactory_processed.java","RuleContainerTest_processed.java","CouldNotReadCoreException_processed.java","ErrorReportingRunner_processed.java","FakeThreadMXBean_processed.java","VerifierRuleTest_processed.java","OrderWithValidator_processed.java","SpecificDataPointsSupplierTest_processed.java","WithDataPointMethod_processed.java","MethodValidator_processed.java","MemberValueConsumer_processed.java","ParentRunnerClassLoaderTest_processed.java","AllMethodsTests_processed.java","AllMembersSupplierTest_processed.java","RunRules_processed.java","ListenerTest_processed.java","RequestTest_processed.java","IgnoredBuilder_processed.java","IgnoredClassRunner_processed.java","SuiteMethod_processed.java","JUnitCoreTest_processed.java","TestResult_processed.java","NoGenericTypeParametersValidator_processed.java","RuleMemberValidator_processed.java","InitializationError_processed.java","Failure_processed.java","FilterTest_processed.java","ForwardCompatibilityTest_processed.java","RunnerBuilder_processed.java","AllTheoriesInternalTests_processed.java","IncludeCategories_processed.java","SuccessfulWithDataPointFields_processed.java","MaxStarterTest_processed.java","PublicClassValidator_processed.java","TypeSafeMatcher_processed.java","RuleMemberValidatorTest_processed.java","Stopwatch_processed.java","JUnitCommandLineParseResult_processed.java","RunWithTest_processed.java","TestWithParameters_processed.java","Categories_processed.java","MoneyBag_processed.java","JUnitMatchers_processed.java","FilterRequest_processed.java","ReguessableValue_processed.java","Stub_processed.java","OrderingRequest_processed.java","TimeoutRuleTest_processed.java","EnumSupplier_processed.java","JUnit38SortingTest_processed.java","AllInternalTests_processed.java","FailureList_processed.java","EventCollector_processed.java","MethodRule_processed.java","RunnerScheduler_processed.java","ErrorCollectorTest_processed.java","ArrayComparisonFailureTest_processed.java","InheritedTestCase_processed.java","ManagementFactory_processed.java","FailOnTimeout_processed.java","MethodSorters_processed.java","Category_processed.java","Checks_processed.java","AllJUnit3CompatibilityTests_processed.java","EachTestNotifier_processed.java","CategoryValidator_processed.java","ReflectiveCallable_processed.java","WithUnresolvedGenericTypeVariablesOnTheoryParms_processed.java","ParallelMethodTest_processed.java","TestWatcher_processed.java","TheoriesPerformanceTest_processed.java","TestListenerTest_processed.java","TestWithClassRule_processed.java","Fail_processed.java","ThrowableCauseMatcher_processed.java","DisableOnDebug_processed.java","AnnotationValidatorFactory_processed.java","RunnerSpy_processed.java","ParallelClassTest_processed.java","ParameterSignatureTest_processed.java","FrameworkMember_processed.java","TimeoutTest_processed.java","MethodRoadie_processed.java","OrderWithValidatorTest_processed.java","TemporaryFolder_processed.java","JUnit4TestAdapterTest_processed.java","NameRulesTest_processed.java","ListTest_processed.java","FailOnTimeoutTest_processed.java","ParameterizedAssertionError_processed.java","TestedOnSupplierTest_processed.java","TestName_processed.java","ParametersSuppliedBy_processed.java","Sub_processed.java","AllMaxTests_processed.java","Sorter_processed.java","ExternalResourceRuleTest_processed.java","ThreadsTest_processed.java","Version_processed.java","BaseTestRunner_processed.java","LoggingTestWatcher_processed.java","ExactComparisonCriteria_processed.java","Suite_processed.java","Before_processed.java","FailedBefore_processed.java","MoneyTest_processed.java","ExpectedException_processed.java","ExtensionTest_processed.java","RunNotifierTest_processed.java","OldTestClassAdaptingListenerTest_processed.java","Test_processed.java","AllNotificationTests_processed.java","ResultMatchersTest_processed.java","SampleJUnit4Tests_processed.java","ParentRunner_processed.java","AnnotationTest_processed.java","ThreadMXBean_processed.java","TestCase_processed.java","AnnotationValidator_processed.java","Money_processed.java","Assert_processed.java","DescriptionTest_processed.java","JUnit4TestAdapter_processed.java","WhenNoParametersMatch_processed.java","TestedOnSupplier_processed.java","ParameterizedTestTest_processed.java","FromDataPoints_processed.java","InvokeMethod_processed.java","ParameterizedAssertionErrorTest_processed.java","ClassRequest_processed.java","FilterFactories_processed.java","AllTests_processed.java","StackFilterTest_processed.java","RunWith_processed.java","UserStopTest_processed.java","TestWatchmanTest_processed.java","AllValidationTests_processed.java","Rule_processed.java","PotentialAssignmentTest_processed.java","Runner_processed.java","MethodSorter_processed.java","SortableTest_processed.java","AllTheoriesRunnerTests_processed.java","ValidationError_processed.java","ReverseAlphanumericSorter_processed.java","FailingDataPointMethods_processed.java","Enclosed_processed.java","FixMethodOrder_processed.java","AnnotationValidatorFactoryTest_processed.java","AnnotationsValidatorTest_processed.java","NoTestCaseClass_processed.java","TestWatcherTest_processed.java","NotVoidTestCase_processed.java","TestClassValidator_processed.java","SerializableMatcherDescription_processed.java","JUnit38ClassRunnerTest_processed.java","StringableObject_processed.java","AssertionFailedErrorTest_processed.java","LoggingTestRule_processed.java","package-info_processed.java","AnnotatedDescriptionTest_processed.java","DisableOnDebugTest_processed.java","RunnerTest_processed.java","GuesserQueue_processed.java","ArrayComparisonFailure_processed.java","Classes_processed.java","CategoryTest_processed.java","After_processed.java","OrderWithTest_processed.java","AnnotatedBuilder_processed.java","AllRunningTests_processed.java","WithNamedDataPoints_processed.java","JUnitSystem_processed.java","CommandLineTest_processed.java","CategoryFilterFactory_processed.java","ComparatorBasedOrdering_processed.java","Assignments_processed.java","BeforeClass_processed.java","CategoriesAndParameterizedTest_processed.java","TestTimedOutException_processed.java","TestDecorator_processed.java","TestRunListener_processed.java","InitializationErrorForwardCompatibilityTest_processed.java","AllDeprecatedTests_processed.java","BlockJUnit4ClassRunnerOverrideTest_processed.java","FrameworkMethod_processed.java","JUnitCore_processed.java","AllListeningTests_processed.java","TextFeedbackTest_processed.java","AllValidatorTests_processed.java","JUnitCoreReturnsCorrectExitCodeTest_processed.java","BlockJUnit4ClassRunnerWithParametersTest_processed.java","RunNotifier_processed.java","ThrowingRunnable_processed.java","RuntimeMXBean_processed.java","SpecificDataPointsSupplier_processed.java","TextRunnerSingleMethodTest_processed.java","AllRulesTests_processed.java","Alphanumeric_processed.java","StackTracesTest_processed.java","ClassRule_processed.java","AssumingInTheoriesTest_processed.java","TestFailure_processed.java","InvalidTestClassErrorTest_processed.java","BooleanSupplier_processed.java","ParametersRunnerFactory_processed.java","JUnit4ClassRunnerTest_processed.java","ResultMatchers_processed.java","ClassRequestTest_processed.java","Orderer_processed.java","TemporaryFolderRuleAssuredDeletionTest_processed.java","AllTheoriesTests_processed.java","MethodCall_processed.java","FrameworkMethodTest_processed.java","Request_processed.java","ExpectedExceptionTest_processed.java","TestRunner_processed.java","Verifier_processed.java","ReverseAlphanumericOrdering_processed.java","ClassRoadie_processed.java",) - var filename: String = "" - - lateinit var fileContents: String - - @Setup(Level.Trial) - fun prepare() { - fileContents = File(pathToInput + filename).readText() - } - - @Benchmark - @OutputTimeUnit(TimeUnit.NANOSECONDS) - fun measureAntlr(blackhole: Blackhole) { - val antlrParser = Java8Parser(CommonTokenStream(Java8Lexer(CharStreams.fromString(fileContents)))) - blackhole.consume(antlrParser.compilationUnit()) - } -} - -@State(Scope.Benchmark) -open class GllBenchmark { - @Param("OneTestCase_processed.java","NotPublicTestCase_processed.java","NoTestsRemainException_processed.java","OldTests_processed.java","TestRule_processed.java","JUnit4ClassRunner_processed.java","CategoryFilterFactoryTest_processed.java","TestClassTest_processed.java","ObjectContractTest_processed.java","LoggingStatement_processed.java","ThrowableMessageMatcher_processed.java","SortingRequest_processed.java","InheritedTestTest_processed.java","SerializableValueDescription_processed.java","JUnit3Builder_processed.java","FrameworkField_processed.java","JavadocTest_processed.java","SynchronizedRunListenerTest_processed.java","Ordering_processed.java","ClassRulesTest_processed.java","ComparisonCriteria_processed.java","TestDescriptionMethodNameTest_processed.java","JUnit4TestAdapterCache_processed.java","RuleContainer_processed.java","InvalidTestClassError_processed.java","JUnit4TestCaseFacade_processed.java","StubbedTheoriesTest_processed.java","FailedConstructionTest_processed.java","ReflectiveThreadMXBean_processed.java","Theory_processed.java","DataPoint_processed.java","Ignore_processed.java","ExpectedExceptionMatcherBuilder_processed.java","BlockJUnit4ClassRunnerWithParameters_processed.java","TestSystem_processed.java","TestWithParametersTest_processed.java","MultiCategoryTest_processed.java","AllMembersSupplier_processed.java","AnnotationsValidator_processed.java","ActiveTestSuite_processed.java","AssertTest_processed.java","RunListener_processed.java","Assume_processed.java","DataPoints_processed.java","TheoryTestUtils_processed.java","AllDefaultPossibilitiesBuilder_processed.java","TestRuleTest_processed.java","AllAssertionTests_processed.java","InvalidOrderingException_processed.java","ResultPrinter_processed.java","AllManipulationTests_processed.java","TextListenerTest_processed.java","Sortable_processed.java","ParameterizedNamesTest_processed.java","ParameterSignature_processed.java","RunnerBuilderStub_processed.java","ValidationTest_processed.java","StubbedTheories_processed.java","SuiteMethodBuilder_processed.java","AllRunnersTests_processed.java","PotentialAssignment_processed.java","StacktracePrintingMatcher_processed.java","Filterable_processed.java","SystemExitTest_processed.java","Filter_processed.java","MainRunner_processed.java","Result_processed.java","TemporaryFolderUsageTest_processed.java","AllTestsTest_processed.java","MultipleFailureException_processed.java","AssertionFailedError_processed.java","ParallelComputer_processed.java","AfterClass_processed.java","UseSuiteAsASuperclassTest_processed.java","ClassLevelMethodsWithIgnoredTestsTest_processed.java","MethodRulesTest_processed.java","Correspondent_processed.java","TypeMatchingBetweenMultiDataPointsMethod_processed.java","ActiveTestTest_processed.java","TestWatchman_processed.java","BadlyFormedClassesTest_processed.java","TestSuite_processed.java","MaxHistory_processed.java","AllParallelTests_processed.java","ComparisonCompactor_processed.java","ParameterSupplier_processed.java","AllClassesTests_processed.java","BlockJUnit4ClassRunnerWithParametersFactory_processed.java","AnnotatedBuilderTest_processed.java","AllExperimentalTests_processed.java","OverrideTestCase_processed.java","TempFolderRuleTest_processed.java","ComparisonFailureTest_processed.java","Parameterized_processed.java","ExpectExceptionTest_processed.java","PrintableResult_processed.java","ReflectiveRuntimeMXBean_processed.java","AllCoreTests_processed.java","ComparisonFailure_processed.java","RunAfters_processed.java","AlphanumericOrdering_processed.java","TestImplementorTest_processed.java","WithParameterSupplier_processed.java","WasRun_processed.java","MultipleFailureExceptionTest_processed.java","RuleChainTest_processed.java","TestListener_processed.java","Statement_processed.java","RepeatedTestTest_processed.java","BlockJUnit4ClassRunner_processed.java","FilterOptionIntegrationTest_processed.java","TestCaseTest_processed.java","ExpectedTest_processed.java","TextRunnerTest_processed.java","EnclosedTest_processed.java","InexactComparisonCriteria_processed.java","OrderWith_processed.java","IMoney_processed.java","UnsuccessfulWithDataPointFields_processed.java","Theories_processed.java","OrderableTest_processed.java","Protectable_processed.java","StacktracePrintingMatcherTest_processed.java","Description_processed.java","BlockJUnit4ClassRunnerTest_processed.java","ParentRunnerTest_processed.java","SuiteTest_processed.java","WithAutoGeneratedDataPoints_processed.java","ExpectException_processed.java","BaseTestRunnerTest_processed.java","TestDescriptionTest_processed.java","SynchronizedRunListener_processed.java","AllParameterizedTests_processed.java","AllModelTests_processed.java","Comparators_processed.java","ThreeTestCases_processed.java","RuleChain_processed.java","Computer_processed.java","TestClass_processed.java","SuiteDescriptionTest_processed.java","MaxCore_processed.java","CustomBlockJUnit4ClassRunnerTest_processed.java","MemoizingRequest_processed.java","ErrorReportingRunnerTest_processed.java","JUnit38ClassRunner_processed.java","TextListener_processed.java","FakeRuntimeMXBean_processed.java","PublicClassValidatorTest_processed.java","Timeout_processed.java","StopwatchTest_processed.java","ConcurrentRunNotifierTest_processed.java","TestCouldNotBeSkippedException_processed.java","Success_processed.java","LoggingMethodRule_processed.java","FilterFactoryParams_processed.java","AssumptionTest_processed.java","WithExtendedParameterSources_processed.java","FilterableTest_processed.java","AllDescriptionTests_processed.java","JUnit4_processed.java","AllRunnerTests_processed.java","SuiteMethodTest_processed.java","SingleMethodTest_processed.java","Describable_processed.java","JUnit4Builder_processed.java","FrameworkFieldTest_processed.java","IgnoreClassTest_processed.java","JUnitCommandLineParseResultTest_processed.java","MatcherTest_processed.java","ThrowableCauseMatcherTest_processed.java","AssumptionViolatedException_processed.java","CategoryValidatorTest_processed.java","ParentRunnerFilteringTest_processed.java","Orderable_processed.java","TestMethodTest_processed.java","ExternalResource_processed.java","ValidateWith_processed.java","AllCategoriesTests_processed.java","ExcludeCategories_processed.java","StoppedByUserException_processed.java","ParameterizedTestMethodTest_processed.java","FilterFactoriesTest_processed.java","RunBefores_processed.java","AllResultsTests_processed.java","ComparisonCompactorTest_processed.java","PrintableResultTest_processed.java","SampleJUnit3Tests_processed.java","ResultTest_processed.java","WithOnlyTestAnnotations_processed.java","Super_processed.java","TestedOn_processed.java","NullBuilder_processed.java","NoTestCases_processed.java","TestMethod_processed.java","Annotatable_processed.java","AssumptionViolatedExceptionTest_processed.java","NoArgTestCaseTest_processed.java","ErrorCollector_processed.java","AllSamplesTests_processed.java","RealSystem_processed.java","MethodSorterTest_processed.java","ForwardCompatibilityPrintingTest_processed.java","Guesser_processed.java","RepeatedTest_processed.java","TestSetup_processed.java","FilterFactory_processed.java","RuleContainerTest_processed.java","CouldNotReadCoreException_processed.java","ErrorReportingRunner_processed.java","FakeThreadMXBean_processed.java","VerifierRuleTest_processed.java","OrderWithValidator_processed.java","SpecificDataPointsSupplierTest_processed.java","WithDataPointMethod_processed.java","MethodValidator_processed.java","MemberValueConsumer_processed.java","ParentRunnerClassLoaderTest_processed.java","AllMethodsTests_processed.java","AllMembersSupplierTest_processed.java","RunRules_processed.java","ListenerTest_processed.java","RequestTest_processed.java","IgnoredBuilder_processed.java","IgnoredClassRunner_processed.java","SuiteMethod_processed.java","JUnitCoreTest_processed.java","TestResult_processed.java","NoGenericTypeParametersValidator_processed.java","RuleMemberValidator_processed.java","InitializationError_processed.java","Failure_processed.java","FilterTest_processed.java","ForwardCompatibilityTest_processed.java","RunnerBuilder_processed.java","AllTheoriesInternalTests_processed.java","IncludeCategories_processed.java","SuccessfulWithDataPointFields_processed.java","MaxStarterTest_processed.java","PublicClassValidator_processed.java","TypeSafeMatcher_processed.java","RuleMemberValidatorTest_processed.java","Stopwatch_processed.java","JUnitCommandLineParseResult_processed.java","RunWithTest_processed.java","TestWithParameters_processed.java","Categories_processed.java","MoneyBag_processed.java","JUnitMatchers_processed.java","FilterRequest_processed.java","ReguessableValue_processed.java","Stub_processed.java","OrderingRequest_processed.java","TimeoutRuleTest_processed.java","EnumSupplier_processed.java","JUnit38SortingTest_processed.java","AllInternalTests_processed.java","FailureList_processed.java","EventCollector_processed.java","MethodRule_processed.java","RunnerScheduler_processed.java","ErrorCollectorTest_processed.java","ArrayComparisonFailureTest_processed.java","InheritedTestCase_processed.java","ManagementFactory_processed.java","FailOnTimeout_processed.java","MethodSorters_processed.java","Category_processed.java","Checks_processed.java","AllJUnit3CompatibilityTests_processed.java","EachTestNotifier_processed.java","CategoryValidator_processed.java","ReflectiveCallable_processed.java","WithUnresolvedGenericTypeVariablesOnTheoryParms_processed.java","ParallelMethodTest_processed.java","TestWatcher_processed.java","TheoriesPerformanceTest_processed.java","TestListenerTest_processed.java","TestWithClassRule_processed.java","Fail_processed.java","ThrowableCauseMatcher_processed.java","DisableOnDebug_processed.java","AnnotationValidatorFactory_processed.java","RunnerSpy_processed.java","ParallelClassTest_processed.java","ParameterSignatureTest_processed.java","FrameworkMember_processed.java","TimeoutTest_processed.java","MethodRoadie_processed.java","OrderWithValidatorTest_processed.java","TemporaryFolder_processed.java","JUnit4TestAdapterTest_processed.java","NameRulesTest_processed.java","ListTest_processed.java","FailOnTimeoutTest_processed.java","ParameterizedAssertionError_processed.java","TestedOnSupplierTest_processed.java","TestName_processed.java","ParametersSuppliedBy_processed.java","Sub_processed.java","AllMaxTests_processed.java","Sorter_processed.java","ExternalResourceRuleTest_processed.java","ThreadsTest_processed.java","Version_processed.java","BaseTestRunner_processed.java","LoggingTestWatcher_processed.java","ExactComparisonCriteria_processed.java","Suite_processed.java","Before_processed.java","FailedBefore_processed.java","MoneyTest_processed.java","ExpectedException_processed.java","ExtensionTest_processed.java","RunNotifierTest_processed.java","OldTestClassAdaptingListenerTest_processed.java","Test_processed.java","AllNotificationTests_processed.java","ResultMatchersTest_processed.java","SampleJUnit4Tests_processed.java","ParentRunner_processed.java","AnnotationTest_processed.java","ThreadMXBean_processed.java","TestCase_processed.java","AnnotationValidator_processed.java","Money_processed.java","Assert_processed.java","DescriptionTest_processed.java","JUnit4TestAdapter_processed.java","WhenNoParametersMatch_processed.java","TestedOnSupplier_processed.java","ParameterizedTestTest_processed.java","FromDataPoints_processed.java","InvokeMethod_processed.java","ParameterizedAssertionErrorTest_processed.java","ClassRequest_processed.java","FilterFactories_processed.java","AllTests_processed.java","StackFilterTest_processed.java","RunWith_processed.java","UserStopTest_processed.java","TestWatchmanTest_processed.java","AllValidationTests_processed.java","Rule_processed.java","PotentialAssignmentTest_processed.java","Runner_processed.java","MethodSorter_processed.java","SortableTest_processed.java","AllTheoriesRunnerTests_processed.java","ValidationError_processed.java","ReverseAlphanumericSorter_processed.java","FailingDataPointMethods_processed.java","Enclosed_processed.java","FixMethodOrder_processed.java","AnnotationValidatorFactoryTest_processed.java","AnnotationsValidatorTest_processed.java","NoTestCaseClass_processed.java","TestWatcherTest_processed.java","NotVoidTestCase_processed.java","TestClassValidator_processed.java","SerializableMatcherDescription_processed.java","JUnit38ClassRunnerTest_processed.java","StringableObject_processed.java","AssertionFailedErrorTest_processed.java","LoggingTestRule_processed.java","package-info_processed.java","AnnotatedDescriptionTest_processed.java","DisableOnDebugTest_processed.java","RunnerTest_processed.java","GuesserQueue_processed.java","ArrayComparisonFailure_processed.java","Classes_processed.java","CategoryTest_processed.java","After_processed.java","OrderWithTest_processed.java","AnnotatedBuilder_processed.java","AllRunningTests_processed.java","WithNamedDataPoints_processed.java","JUnitSystem_processed.java","CommandLineTest_processed.java","CategoryFilterFactory_processed.java","ComparatorBasedOrdering_processed.java","Assignments_processed.java","BeforeClass_processed.java","CategoriesAndParameterizedTest_processed.java","TestTimedOutException_processed.java","TestDecorator_processed.java","TestRunListener_processed.java","InitializationErrorForwardCompatibilityTest_processed.java","AllDeprecatedTests_processed.java","BlockJUnit4ClassRunnerOverrideTest_processed.java","FrameworkMethod_processed.java","JUnitCore_processed.java","AllListeningTests_processed.java","TextFeedbackTest_processed.java","AllValidatorTests_processed.java","JUnitCoreReturnsCorrectExitCodeTest_processed.java","BlockJUnit4ClassRunnerWithParametersTest_processed.java","RunNotifier_processed.java","ThrowingRunnable_processed.java","RuntimeMXBean_processed.java","SpecificDataPointsSupplier_processed.java","TextRunnerSingleMethodTest_processed.java","AllRulesTests_processed.java","Alphanumeric_processed.java","StackTracesTest_processed.java","ClassRule_processed.java","AssumingInTheoriesTest_processed.java","TestFailure_processed.java","InvalidTestClassErrorTest_processed.java","BooleanSupplier_processed.java","ParametersRunnerFactory_processed.java","JUnit4ClassRunnerTest_processed.java","ResultMatchers_processed.java","ClassRequestTest_processed.java","Orderer_processed.java","TemporaryFolderRuleAssuredDeletionTest_processed.java","AllTheoriesTests_processed.java","MethodCall_processed.java","FrameworkMethodTest_processed.java","Request_processed.java","ExpectedExceptionTest_processed.java","TestRunner_processed.java","Verifier_processed.java","ReverseAlphanumericOrdering_processed.java","ClassRoadie_processed.java",) - var filename: String = "" - - val startState = JavaGrammar().rsm - - lateinit var fileContents: String - - @Setup(Level.Trial) - fun prepare() { - fileContents = File(pathToInput + filename).readText() - } - - @Benchmark - @OutputTimeUnit(TimeUnit.NANOSECONDS) - fun measureGll(blackhole: Blackhole) { - val inputGraph = getTokenStream(fileContents) - val gll = Gll.recoveryGll(startState, inputGraph) - - blackhole.consume(gll.parse()) - } -} diff --git a/benchmarks/src/jmh/kotlin/grammars/JavaGrammar.kt b/benchmarks/src/jmh/kotlin/grammars/JavaGrammar.kt deleted file mode 100644 index 36eeb9118..000000000 --- a/benchmarks/src/jmh/kotlin/grammars/JavaGrammar.kt +++ /dev/null @@ -1,546 +0,0 @@ -package grammars -import lexers.JavaToken -import org.ucfs.grammar.combinator.Grammar -import org.ucfs.grammar.combinator.regexp.* - -class JavaGrammar : Grammar() { - var CompilationUnit by Nt() - var Identifier by Nt() - var Literal by Nt() - var Type by Nt() - var PrimitiveType by Nt() - var ReferenceType by Nt() - var Annotation by Nt() - var NumericType by Nt() - var IntegralType by Nt() - var FloatingPointType by Nt() - var ClassOrInterfaceType by Nt() - var TypeVariable by Nt() - var ArrayType by Nt() - var ClassType by Nt() - var InterfaceType by Nt() - var TypeArguments by Nt() - var Dims by Nt() - var TypeParameter by Nt() - var TypeParameterModifier by Nt() - var TypeBound by Nt() - var AdditionalBound by Nt() - var TypeArgumentList by Nt() - var TypeArgument by Nt() - var Wildcard by Nt() - var WildcardBounds by Nt() - var TypeName by Nt() - var PackageOrTypeName by Nt() - var ExpressionName by Nt() - var AmbiguousName by Nt() - var MethodName by Nt() - var PackageName by Nt() - var Result by Nt() - var PackageDeclaration by Nt() - var ImportDeclaration by Nt() - var TypeDeclaration by Nt() - var PackageModifier by Nt() - var SingleTypeImportDeclaration by Nt() - var TypeImportOnDemandDeclaration by Nt() - var SingleStaticImportDeclaration by Nt() - var StaticImportOnDemandDeclaration by Nt() - var ClassDeclaration by Nt() - var InterfaceDeclaration by Nt() - var Throws by Nt() - var NormalClassDeclaration by Nt() - var EnumDeclaration by Nt() - var ClassModifier by Nt() - var TypeParameters by Nt() - var Superclass by Nt() - var Superinterfaces by Nt() - var ClassBody by Nt() - var TypeParameterList by Nt() - var InterfaceTypeList by Nt() - var ClassBodyDeclaration by Nt() - var ClassMemberDeclaration by Nt() - var InstanceInitializer by Nt() - var StaticInitializer by Nt() - var ConstructorDeclaration by Nt() - var FieldDeclaration by Nt() - var MethodDeclaration by Nt() - var FieldModifier by Nt() - var UnannType by Nt() - var VariableDeclaratorList by Nt() - var VariableDeclarator by Nt() - var VariableDeclaratorId by Nt() - var VariableInitializer by Nt() - var Expression by Nt() - var ArrayInitializer by Nt() - var UnannPrimitiveType by Nt() - var UnannReferenceType by Nt() - var UnannClassOrInterfaceType by Nt() - var UnannTypeVariable by Nt() - var UnannArrayType by Nt() - var UnannClassType by Nt() - var UnannInterfaceType by Nt() - var MethodModifier by Nt() - var MethodHeader by Nt() - var MethodBody by Nt() - var MethodDeclarator by Nt() - var FormalParameterList by Nt() - var ReceiverParameter by Nt() - var FormalParameters by Nt() - var LastFormalParameter by Nt() - var FormalParameter by Nt() - var VariableModifier by Nt() - var ExceptionTypeList by Nt() - var ExceptionType by Nt() - var Block by Nt() - var ConstructorModifier by Nt() - var ConstructorDeclarator by Nt() - var ConstructorBody by Nt() - var SimpleTypeName by Nt() - var ExplicitConstructorInvocation by Nt() - var EnumBody by Nt() - var EnumConstantList by Nt() - var EnumConstant by Nt() - var EnumConstantModifier by Nt() - var EnumBodyDeclarations by Nt() - var BlockStatements by Nt() - var ArgumentList by Nt() - var Primary by Nt() - var NormalInterfaceDeclaration by Nt() - var InterfaceModifier by Nt() - var ExtendsInterfaces by Nt() - var InterfaceBody by Nt() - var InterfaceMemberDeclaration by Nt() - var ConstantDeclaration by Nt() - var ConstantModifier by Nt() - var AnnotationTypeDeclaration by Nt() - var AnnotationTypeBody by Nt() - var AnnotationTypeMemberDeclaration by Nt() - var AnnotationTypeElementDeclaration by Nt() - var DefaultValue by Nt() - var NormalAnnotation by Nt() - var ElementValuePairList by Nt() - var ElementValuePair by Nt() - var ElementValue by Nt() - var ElementValueArrayInitializer by Nt() - var ElementValueList by Nt() - var MarkerAnnotation by Nt() - var SingleElementAnnotation by Nt() - var InterfaceMethodDeclaration by Nt() - var AnnotationTypeElementModifier by Nt() - var ConditionalExpression by Nt() - var VariableInitializerList by Nt() - var BlockStatement by Nt() - var LocalVariableDeclarationStatement by Nt() - var LocalVariableDeclaration by Nt() - var Statement by Nt() - var StatementNoShortIf by Nt() - var StatementWithoutTrailingSubstatement by Nt() - var EmptyStatement by Nt() - var LabeledStatement by Nt() - var LabeledStatementNoShortIf by Nt() - var ExpressionStatement by Nt() - var StatementExpression by Nt() - var IfThenStatement by Nt() - var IfThenElseStatement by Nt() - var IfThenElseStatementNoShortIf by Nt() - var AssertStatement by Nt() - var SwitchStatement by Nt() - var SwitchBlock by Nt() - var SwitchBlockStatementGroup by Nt() - var SwitchLabels by Nt() - var SwitchLabel by Nt() - var EnumConstantName by Nt() - var WhileStatement by Nt() - var WhileStatementNoShortIf by Nt() - var DoStatement by Nt() - var InterfaceMethodModifier by Nt() - var ForStatement by Nt() - var ForStatementNoShortIf by Nt() - var BasicForStatement by Nt() - var BasicForStatementNoShortIf by Nt() - var ForInit by Nt() - var ForUpdate by Nt() - var StatementExpressionList by Nt() - var EnhancedForStatement by Nt() - var EnhancedForStatementNoShortIf by Nt() - var BreakStatement by Nt() - var ContinueStatement by Nt() - var ReturnStatement by Nt() - var ThrowStatement by Nt() - var SynchronizedStatement by Nt() - var TryStatement by Nt() - var Catches by Nt() - var CatchClause by Nt() - var CatchFormalParameter by Nt() - var CatchType by Nt() - var Finally by Nt() - var TryWithResourcesStatement by Nt() - var ResourceSpecification by Nt() - var ResourceList by Nt() - var Resource by Nt() - var PrimaryNoNewArray by Nt() - var ClassLiteral by Nt() - var classOrInterfaceTypeToInstantiate by Nt() - var UnqualifiedClassInstanceCreationExpression by Nt() - var ClassInstanceCreationExpression by Nt() - var FieldAccess by Nt() - var TypeArgumentsOrDiamond by Nt() - var ArrayAccess by Nt() - var MethodInvocation by Nt() - var MethodReference by Nt() - var ArrayCreationExpression by Nt() - var DimExprs by Nt() - var DimExpr by Nt() - var LambdaExpression by Nt() - var LambdaParameters by Nt() - var InferredFormalParameterList by Nt() - var LambdaBody by Nt() - var AssignmentExpression by Nt() - var Assignment by Nt() - var LeftHandSide by Nt() - var AssignmentOperator by Nt() - var ConditionalOrExpression by Nt() - var ConditionalAndExpression by Nt() - var InclusiveOrExpression by Nt() - var ExclusiveOrExpression by Nt() - var AndExpression by Nt() - var EqualityExpression by Nt() - var RelationalExpression by Nt() - var ShiftExpression by Nt() - var AdditiveExpression by Nt() - var MultiplicativeExpression by Nt() - var PreIncrementExpression by Nt() - var PreDecrementExpression by Nt() - var UnaryExpressionNotPlusMinus by Nt() - var UnaryExpression by Nt() - var PostfixExpression by Nt() - var PostIncrementExpression by Nt() - var PostDecrementExpression by Nt() - var CastExpression by Nt() - var ConstantExpression by Nt() - - init { - Identifier = JavaToken.ID - - Literal = JavaToken.INTEGERLIT or JavaToken.FLOATINGLIT or JavaToken.BOOLEANLIT or - JavaToken.CHARLIT or JavaToken.STRINGLIT or JavaToken.NULLLIT - - /** - * Productions from §4 (Types, Values, and Variables) - */ - Type = PrimitiveType or ReferenceType - PrimitiveType = Many(Annotation) * NumericType or Many(Annotation) * JavaToken.BOOLEAN - NumericType = IntegralType or FloatingPointType - IntegralType = JavaToken.BYTE or JavaToken.SHORT or JavaToken.INT or JavaToken.LONG or JavaToken.CHAR - FloatingPointType = JavaToken.FLOAT or JavaToken.DOUBLE - ReferenceType = ClassOrInterfaceType or TypeVariable or ArrayType - ClassOrInterfaceType = ClassType or InterfaceType - ClassType = Many(Annotation) * Identifier * Option(TypeArguments) or - ClassOrInterfaceType * JavaToken.DOT * Many(Annotation) * Identifier * Option(TypeArguments) - InterfaceType = ClassType - TypeVariable = Many(Annotation) * Identifier - ArrayType = PrimitiveType * Dims or ClassOrInterfaceType * Dims or TypeVariable * Dims - Dims = Some(Many(Annotation) * JavaToken.BRACKETLEFT * JavaToken.BRACKETRIGHT) - TypeParameter = Many(TypeParameterModifier) * Identifier * Option(TypeBound) - TypeParameterModifier = Annotation - TypeBound = JavaToken.EXTENDS * TypeVariable or JavaToken.EXTENDS * ClassOrInterfaceType * Many(AdditionalBound) - AdditionalBound = JavaToken.ANDBIT * InterfaceType - TypeArguments = JavaToken.LT * TypeArgumentList * JavaToken.GT - TypeArgumentList = TypeArgument * Many(JavaToken.COMMA * TypeArgument) - TypeArgument = ReferenceType or Wildcard - Wildcard = Many(Annotation) * JavaToken.QUESTIONMARK * Option(WildcardBounds) - WildcardBounds = JavaToken.EXTENDS * ReferenceType or JavaToken.SUPER * ReferenceType - - /** - * Productions from §6 (Names) - */ - - TypeName = Identifier or PackageOrTypeName * JavaToken.DOT * Identifier - PackageOrTypeName = Identifier or PackageOrTypeName * JavaToken.DOT * Identifier - ExpressionName = Identifier or AmbiguousName * JavaToken.DOT * Identifier - MethodName = Identifier - PackageName = Identifier or PackageName * JavaToken.DOT * Identifier - AmbiguousName = Identifier or AmbiguousName * JavaToken.DOT * Identifier - - /** - * Productions from §7 (Packages) - */ - - CompilationUnit = Option(PackageDeclaration) * Many(ImportDeclaration) * Many(TypeDeclaration) - PackageDeclaration = Many(PackageModifier) * JavaToken.PACKAGE * Identifier * Many(JavaToken.DOT * Identifier) * JavaToken.SEMICOLON - PackageModifier = Annotation - ImportDeclaration = SingleTypeImportDeclaration or TypeImportOnDemandDeclaration or - SingleStaticImportDeclaration or StaticImportOnDemandDeclaration - SingleTypeImportDeclaration = JavaToken.IMPORT * TypeName * JavaToken.SEMICOLON - TypeImportOnDemandDeclaration = JavaToken.IMPORT * PackageOrTypeName * JavaToken.DOT * JavaToken.STAR * JavaToken.SEMICOLON - SingleStaticImportDeclaration = JavaToken.IMPORT * JavaToken.STATIC * TypeName * JavaToken.DOT * Identifier * JavaToken.SEMICOLON - StaticImportOnDemandDeclaration = JavaToken.IMPORT * JavaToken.STATIC * TypeName * JavaToken.DOT * JavaToken.STAR * JavaToken.SEMICOLON - TypeDeclaration = ClassDeclaration or InterfaceDeclaration or JavaToken.SEMICOLON - - /** - * Productions from §8 (Classes) - */ - - ClassDeclaration = NormalClassDeclaration or EnumDeclaration - NormalClassDeclaration = Many(ClassModifier) * JavaToken.CLASS * Identifier * - Option(TypeParameters) * Option(Superclass) * Option(Superinterfaces) * ClassBody - ClassModifier = Annotation or JavaToken.PUBLIC or JavaToken.PROTECTED or JavaToken.PRIVATE or - JavaToken.ABSTRACT or JavaToken.STATIC or JavaToken.FINAL or JavaToken.STRICTFP - TypeParameters = JavaToken.LT * TypeParameterList * JavaToken.GT - TypeParameterList = TypeParameter * Many(JavaToken.COMMA * TypeParameter) - Superclass = JavaToken.EXTENDS * ClassType - Superinterfaces = JavaToken.IMPLEMENTS * InterfaceTypeList - InterfaceTypeList = InterfaceType * Many(JavaToken.COMMA * InterfaceType) - ClassBody = JavaToken.CURLYLEFT * Many(ClassBodyDeclaration) * JavaToken.CURLYRIGHT - ClassBodyDeclaration = ClassMemberDeclaration or InstanceInitializer or StaticInitializer or ConstructorDeclaration - ClassMemberDeclaration = FieldDeclaration or MethodDeclaration or ClassDeclaration or InterfaceDeclaration or JavaToken.SEMICOLON - FieldDeclaration = Many(FieldModifier) * UnannType * VariableDeclaratorList * JavaToken.SEMICOLON - FieldModifier = Annotation or JavaToken.PUBLIC or JavaToken.PROTECTED or JavaToken.PRIVATE or JavaToken.STATIC or - JavaToken.FINAL or JavaToken.TRANSIENT or JavaToken.VOLATILE - VariableDeclaratorList = VariableDeclarator * Many(JavaToken.COMMA * VariableDeclarator) - VariableDeclarator = VariableDeclaratorId * Option(JavaToken.ASSIGN * VariableInitializer) - VariableDeclaratorId = Identifier * Option(Dims) - VariableInitializer = Expression or ArrayInitializer - UnannType = UnannPrimitiveType or UnannReferenceType - UnannPrimitiveType = NumericType or JavaToken.BOOLEAN - UnannReferenceType = UnannClassOrInterfaceType or UnannTypeVariable or UnannArrayType - UnannClassOrInterfaceType = UnannClassType or UnannInterfaceType - UnannClassType = Identifier * Option(TypeArguments) or - UnannClassOrInterfaceType * JavaToken.DOT * Many(Annotation) * Identifier * Option(TypeArguments) - UnannInterfaceType = UnannClassType - UnannTypeVariable = Identifier - UnannArrayType = UnannPrimitiveType * Dims or UnannClassOrInterfaceType * Dims or UnannTypeVariable * Dims - MethodDeclaration = Many(MethodModifier) * MethodHeader * MethodBody - MethodModifier = Annotation or JavaToken.PUBLIC or JavaToken.PROTECTED or JavaToken.PRIVATE or JavaToken.ABSTRACT or - JavaToken.STATIC or JavaToken.FINAL or JavaToken.SYNCHRONIZED or JavaToken.NATIVE or JavaToken.STRICTFP - MethodHeader = Result * MethodDeclarator * Option(Throws) or - TypeParameters * Many(Annotation) * Result * MethodDeclarator * Option(Throws) - Result = UnannType or JavaToken.VOID - MethodDeclarator = Identifier * JavaToken.PARENTHLEFT * Option(FormalParameterList) * JavaToken.PARENTHRIGHT * Option(Dims) - FormalParameterList = ReceiverParameter or FormalParameters * JavaToken.COMMA * LastFormalParameter or - LastFormalParameter - FormalParameters = FormalParameter * Many(JavaToken.COMMA * FormalParameter) or - ReceiverParameter * Many(JavaToken.COMMA * FormalParameter) - FormalParameter = Many(VariableModifier) * UnannType * VariableDeclaratorId - VariableModifier = Annotation or JavaToken.FINAL - LastFormalParameter = Many(VariableModifier) * UnannType * Many(Annotation) * JavaToken.ELLIPSIS * VariableDeclaratorId or FormalParameter - ReceiverParameter = Many(Annotation) * UnannType * Option(Identifier * JavaToken.DOT) * JavaToken.THIS - Throws = JavaToken.THROWS * ExceptionTypeList - ExceptionTypeList = ExceptionType * Many(JavaToken.COMMA * ExceptionType) - ExceptionType = ClassType or TypeVariable - MethodBody = Block or JavaToken.SEMICOLON - InstanceInitializer = Block - StaticInitializer = JavaToken.STATIC * Block - ConstructorDeclaration = Many(ConstructorModifier) * ConstructorDeclarator * Option(Throws) * ConstructorBody - ConstructorModifier = Annotation or JavaToken.PUBLIC or JavaToken.PROTECTED or JavaToken.PRIVATE - ConstructorDeclarator = Option(TypeParameters) * SimpleTypeName * JavaToken.PARENTHLEFT * Option(FormalParameterList) * JavaToken.PARENTHRIGHT - SimpleTypeName = Identifier - ConstructorBody = JavaToken.CURLYLEFT * Option(ExplicitConstructorInvocation) * Option(BlockStatements) * JavaToken.CURLYRIGHT - ExplicitConstructorInvocation = Option(TypeArguments) * JavaToken.THIS * JavaToken.PARENTHLEFT * Option(ArgumentList) * JavaToken.PARENTHRIGHT * JavaToken.SEMICOLON or - Option(TypeArguments) * JavaToken.SUPER * JavaToken.PARENTHLEFT * Option(ArgumentList) * JavaToken.PARENTHRIGHT * JavaToken.SEMICOLON or - ExpressionName * JavaToken.DOT * Option(TypeArguments) * JavaToken.SUPER * JavaToken.PARENTHLEFT * Option(ArgumentList) * JavaToken.PARENTHRIGHT * JavaToken.SEMICOLON or - Primary * JavaToken.DOT * Option(TypeArguments) * JavaToken.SUPER * JavaToken.PARENTHLEFT * Option(ArgumentList) * JavaToken.PARENTHRIGHT * JavaToken.SEMICOLON - EnumDeclaration = Many(ClassModifier) * JavaToken.ENUM * Identifier * Option(Superinterfaces) * EnumBody - EnumBody = JavaToken.CURLYLEFT * Option(EnumConstantList) * Option(JavaToken.COMMA) * Option(EnumBodyDeclarations) * JavaToken.CURLYRIGHT - EnumConstantList = EnumConstant * Many(JavaToken.COMMA * EnumConstant) - EnumConstant = Many(EnumConstantModifier) * Identifier * Option(JavaToken.PARENTHLEFT * Option(ArgumentList) * JavaToken.PARENTHRIGHT * Option(ClassBody)) - EnumConstantModifier = Annotation - EnumBodyDeclarations = JavaToken.SEMICOLON * Many(ClassBodyDeclaration) - - /** - * Productions from §9 (Interfaces) - */ - - InterfaceDeclaration = NormalInterfaceDeclaration or AnnotationTypeDeclaration - NormalInterfaceDeclaration = - Many(InterfaceModifier) * JavaToken.INTERFACE * Identifier * Option(TypeParameters) * Option(ExtendsInterfaces) * InterfaceBody - InterfaceModifier = Annotation or JavaToken.PUBLIC or JavaToken.PROTECTED or JavaToken.PRIVATE or - JavaToken.ABSTRACT or JavaToken.STATIC or JavaToken.STRICTFP - ExtendsInterfaces = JavaToken.EXTENDS * InterfaceTypeList - InterfaceBody = JavaToken.CURLYLEFT * Many(InterfaceMemberDeclaration) * JavaToken.CURLYRIGHT - InterfaceMemberDeclaration = ConstantDeclaration or InterfaceMethodDeclaration or ClassDeclaration or InterfaceDeclaration or JavaToken.SEMICOLON - ConstantDeclaration = Many(ConstantModifier) * UnannType * VariableDeclaratorList * JavaToken.SEMICOLON - ConstantModifier = Annotation or JavaToken.PUBLIC or JavaToken.STATIC or JavaToken.FINAL - InterfaceMethodDeclaration = Many(InterfaceMethodModifier) * MethodHeader * MethodBody - InterfaceMethodModifier = Annotation or JavaToken.PUBLIC or JavaToken.ABSTRACT or JavaToken.DEFAULT or JavaToken.STATIC or JavaToken.STRICTFP - AnnotationTypeDeclaration = Many(InterfaceModifier) * JavaToken.AT * JavaToken.INTERFACE * Identifier * AnnotationTypeBody - AnnotationTypeBody = JavaToken.CURLYLEFT * Many(AnnotationTypeMemberDeclaration) * JavaToken.CURLYRIGHT - AnnotationTypeMemberDeclaration = AnnotationTypeElementDeclaration or ConstantDeclaration or ClassDeclaration or InterfaceDeclaration or JavaToken.SEMICOLON - AnnotationTypeElementDeclaration = - Many(AnnotationTypeElementModifier) * UnannType * Identifier * JavaToken.PARENTHLEFT * JavaToken.PARENTHRIGHT * Option(Dims) * Option(DefaultValue) * JavaToken.SEMICOLON - AnnotationTypeElementModifier = Annotation or JavaToken.PUBLIC or JavaToken.ABSTRACT - DefaultValue = JavaToken.DEFAULT * ElementValue - Annotation = NormalAnnotation or MarkerAnnotation or SingleElementAnnotation - NormalAnnotation = JavaToken.AT * TypeName * JavaToken.PARENTHLEFT * Option(ElementValuePairList) * JavaToken.PARENTHRIGHT - ElementValuePairList = ElementValuePair * Many(JavaToken.COMMA * ElementValuePair) - ElementValuePair = Identifier * JavaToken.ASSIGN * ElementValue - ElementValue = ConditionalExpression or ElementValueArrayInitializer or Annotation - ElementValueArrayInitializer = JavaToken.CURLYLEFT * Option(ElementValueList) * Option(JavaToken.COMMA) * JavaToken.CURLYRIGHT - ElementValueList = ElementValue * Many(JavaToken.COMMA * ElementValue) - MarkerAnnotation = JavaToken.AT * TypeName - SingleElementAnnotation = JavaToken.AT * TypeName * JavaToken.PARENTHLEFT * ElementValue * JavaToken.PARENTHRIGHT - - /** - * Productions from §10 (Arrays) - */ - - ArrayInitializer = JavaToken.CURLYLEFT * Option(VariableInitializerList) * Option(JavaToken.COMMA) * JavaToken.CURLYRIGHT - VariableInitializerList = VariableInitializer * Many(JavaToken.COMMA * VariableInitializer) - - /** - * Productions from §14 (Blocks and Statements) - */ - - Block = JavaToken.CURLYLEFT * Option(BlockStatements) * JavaToken.CURLYRIGHT - BlockStatements = BlockStatement * Many(BlockStatement) - BlockStatement = LocalVariableDeclarationStatement or ClassDeclaration or Statement - LocalVariableDeclarationStatement = LocalVariableDeclaration * JavaToken.SEMICOLON - LocalVariableDeclaration = Many(VariableModifier) * UnannType * VariableDeclaratorList - Statement = StatementWithoutTrailingSubstatement or LabeledStatement or IfThenStatement or IfThenElseStatement or - WhileStatement or ForStatement - StatementNoShortIf = StatementWithoutTrailingSubstatement or LabeledStatementNoShortIf or IfThenElseStatementNoShortIf or - WhileStatementNoShortIf or ForStatementNoShortIf - StatementWithoutTrailingSubstatement = Block or EmptyStatement or ExpressionStatement or AssertStatement or - SwitchStatement or DoStatement or BreakStatement or ContinueStatement or ReturnStatement or SynchronizedStatement or - ThrowStatement or TryStatement - EmptyStatement = JavaToken.SEMICOLON - LabeledStatement = Identifier * JavaToken.COLON * Statement - LabeledStatementNoShortIf = Identifier * JavaToken.COLON * StatementNoShortIf - ExpressionStatement = StatementExpression * JavaToken.SEMICOLON - StatementExpression = Assignment or PreIncrementExpression or PreDecrementExpression or PostIncrementExpression or - PostDecrementExpression or MethodInvocation or ClassInstanceCreationExpression - IfThenStatement = JavaToken.IF * JavaToken.PARENTHLEFT * Expression * JavaToken.PARENTHRIGHT * Statement - IfThenElseStatement = JavaToken.IF * JavaToken.PARENTHLEFT * Expression * JavaToken.PARENTHRIGHT * StatementNoShortIf * JavaToken.ELSE * Statement - IfThenElseStatementNoShortIf = - JavaToken.IF * JavaToken.PARENTHLEFT * Expression * JavaToken.PARENTHRIGHT * StatementNoShortIf * JavaToken.ELSE * StatementNoShortIf - AssertStatement = JavaToken.ASSERT * Expression * JavaToken.SEMICOLON or - JavaToken.ASSERT * Expression * JavaToken.COLON * Expression * JavaToken.SEMICOLON - SwitchStatement = JavaToken.SWITCH * JavaToken.PARENTHLEFT * Expression * JavaToken.PARENTHRIGHT * SwitchBlock - SwitchBlock = JavaToken.CURLYLEFT * Many(SwitchBlockStatementGroup) * Many(SwitchLabel) * JavaToken.CURLYRIGHT - SwitchBlockStatementGroup = SwitchLabels * BlockStatements - SwitchLabels = Some(SwitchLabel) - SwitchLabel = JavaToken.CASE * ConstantExpression * JavaToken.COLON or - JavaToken.CASE * EnumConstantName * JavaToken.COLON or JavaToken.DEFAULT * JavaToken.COLON - EnumConstantName = Identifier - WhileStatement = JavaToken.WHILE * JavaToken.PARENTHLEFT * Expression * JavaToken.PARENTHRIGHT * Statement - WhileStatementNoShortIf = JavaToken.WHILE * JavaToken.PARENTHLEFT * Expression * JavaToken.PARENTHRIGHT * StatementNoShortIf - DoStatement = JavaToken.DO * Statement * JavaToken.WHILE * JavaToken.PARENTHLEFT * Expression * JavaToken.PARENTHRIGHT * JavaToken.SEMICOLON - ForStatement = BasicForStatement or EnhancedForStatement - ForStatementNoShortIf = BasicForStatementNoShortIf or EnhancedForStatementNoShortIf - BasicForStatement = JavaToken.FOR * JavaToken.PARENTHLEFT * Option(ForInit) * JavaToken.SEMICOLON * Option(Expression) * JavaToken.SEMICOLON * Option(ForUpdate) * JavaToken.PARENTHRIGHT * Statement - BasicForStatementNoShortIf = JavaToken.FOR * JavaToken.PARENTHLEFT * Option(ForInit) * JavaToken.SEMICOLON * Option(Expression) * JavaToken.SEMICOLON * Option(ForUpdate) * JavaToken.PARENTHRIGHT * StatementNoShortIf - ForInit = StatementExpressionList or LocalVariableDeclaration - ForUpdate = StatementExpressionList - StatementExpressionList = StatementExpression * Many(JavaToken.COMMA * StatementExpression) - EnhancedForStatement = JavaToken.FOR * JavaToken.PARENTHLEFT * Many(VariableModifier) * UnannType * VariableDeclaratorId * JavaToken.COLON * Expression * JavaToken.PARENTHRIGHT * Statement - EnhancedForStatementNoShortIf = JavaToken.FOR * JavaToken.PARENTHLEFT * Many(VariableModifier) * UnannType * VariableDeclaratorId * JavaToken.COLON * Expression * JavaToken.PARENTHRIGHT * StatementNoShortIf - BreakStatement = JavaToken.BREAK * Option(Identifier) * JavaToken.SEMICOLON - ContinueStatement = JavaToken.CONTINUE * Option(Identifier) * JavaToken.SEMICOLON - ReturnStatement = JavaToken.RETURN * Option(Expression) * JavaToken.SEMICOLON - ThrowStatement = JavaToken.THROW * Expression * JavaToken.SEMICOLON - SynchronizedStatement = JavaToken.SYNCHRONIZED * JavaToken.PARENTHLEFT * Expression * JavaToken.PARENTHRIGHT * Block - TryStatement = JavaToken.TRY * Block * Catches or JavaToken.TRY * Block * Option(Catches) * Finally or TryWithResourcesStatement - Catches = Some(CatchClause) - CatchClause = JavaToken.CATCH * JavaToken.PARENTHLEFT * CatchFormalParameter * JavaToken.PARENTHRIGHT * Block - CatchFormalParameter = Many(VariableModifier) * CatchType * VariableDeclaratorId - CatchType = UnannClassType * Many(JavaToken.ORBIT * ClassType) - Finally = JavaToken.FINALLY * Block - TryWithResourcesStatement = JavaToken.TRY * ResourceSpecification * Block * Option(Catches) * Option(Finally) - ResourceSpecification = JavaToken.PARENTHLEFT * ResourceList * Option(JavaToken.SEMICOLON) * JavaToken.PARENTHRIGHT - ResourceList = Resource * Many(JavaToken.COMMA * Resource) - Resource = Many(VariableModifier) * UnannType * VariableDeclaratorId * JavaToken.ASSIGN * Expression - - /** - * Productions from §15 (Expressions) - */ - - Primary = PrimaryNoNewArray or ArrayCreationExpression - PrimaryNoNewArray = Literal or ClassLiteral or JavaToken.THIS or TypeName * JavaToken.DOT * JavaToken.THIS or - JavaToken.PARENTHLEFT * Expression * JavaToken.PARENTHRIGHT or ClassInstanceCreationExpression or FieldAccess or - ArrayAccess or MethodInvocation or MethodReference - ClassLiteral = TypeName * Many(JavaToken.BRACKETLEFT * JavaToken.BRACKETRIGHT) * JavaToken.DOT * JavaToken.CLASS or - NumericType * Many(JavaToken.BRACKETLEFT * JavaToken.BRACKETRIGHT) * JavaToken.DOT * JavaToken.CLASS or - JavaToken.BOOLEAN * Many(JavaToken.BRACKETLEFT * JavaToken.BRACKETRIGHT) * JavaToken.DOT * JavaToken.CLASS or - JavaToken.VOID * JavaToken.DOT * JavaToken.CLASS - ClassInstanceCreationExpression = UnqualifiedClassInstanceCreationExpression or - ExpressionName * JavaToken.DOT * UnqualifiedClassInstanceCreationExpression or - Primary * JavaToken.DOT * UnqualifiedClassInstanceCreationExpression - UnqualifiedClassInstanceCreationExpression = - JavaToken.NEW * Option(TypeArguments) * classOrInterfaceTypeToInstantiate * JavaToken.PARENTHLEFT * Option(ArgumentList) * JavaToken.PARENTHRIGHT * Option(ClassBody) - classOrInterfaceTypeToInstantiate = Many(Annotation) * Identifier * Many(JavaToken.DOT * Many(Annotation) * Identifier) * Option(TypeArgumentsOrDiamond) - TypeArgumentsOrDiamond = TypeArguments or JavaToken.LT * JavaToken.GT - FieldAccess = Primary * JavaToken.DOT * Identifier or JavaToken.SUPER * JavaToken.DOT * Identifier or - TypeName * JavaToken.DOT * JavaToken.SUPER * JavaToken.DOT * Identifier - ArrayAccess = ExpressionName * JavaToken.BRACKETLEFT * Expression * JavaToken.BRACKETRIGHT or - PrimaryNoNewArray * JavaToken.BRACKETLEFT * Expression * JavaToken.BRACKETRIGHT - MethodInvocation = MethodName * JavaToken.PARENTHLEFT * Option(ArgumentList) * JavaToken.PARENTHRIGHT or - TypeName * JavaToken.DOT * Option(TypeArguments) * Identifier * JavaToken.PARENTHLEFT * Option(ArgumentList) * JavaToken.PARENTHRIGHT or - ExpressionName * JavaToken.DOT * Option(TypeArguments) * Identifier * JavaToken.PARENTHLEFT * Option(ArgumentList) * JavaToken.PARENTHRIGHT or - Primary * JavaToken.DOT * Option(TypeArguments) * Identifier * JavaToken.PARENTHLEFT * Option(ArgumentList) * JavaToken.PARENTHRIGHT or - JavaToken.SUPER * JavaToken.DOT * Option(TypeArguments) * Identifier * JavaToken.PARENTHLEFT * Option(ArgumentList) * JavaToken.PARENTHRIGHT or - TypeName * JavaToken.DOT * JavaToken.SUPER * JavaToken.DOT * Option(TypeArguments) * Identifier * JavaToken.PARENTHLEFT * Option(ArgumentList) * JavaToken.PARENTHRIGHT - ArgumentList = Expression * Many(JavaToken.COMMA * Expression) - MethodReference = ExpressionName * JavaToken.DOUBLECOLON * Option(TypeArguments) * Identifier or - ReferenceType * JavaToken.DOUBLECOLON * Option(TypeArguments) * Identifier or - Primary * JavaToken.DOUBLECOLON * Option(TypeArguments) * Identifier or - JavaToken.SUPER * JavaToken.DOUBLECOLON * Option(TypeArguments) * Identifier or - TypeName * JavaToken.DOT * JavaToken.SUPER * JavaToken.DOUBLECOLON * Option(TypeArguments) * Identifier or - ClassType * JavaToken.DOUBLECOLON * Option(TypeArguments) * JavaToken.NEW or - ArrayType * JavaToken.DOUBLECOLON * JavaToken.NEW - ArrayCreationExpression = JavaToken.NEW * PrimitiveType * DimExprs * Option(Dims) or - JavaToken.NEW * ClassOrInterfaceType * DimExprs * Option(Dims) or - JavaToken.NEW * PrimitiveType * Dims * ArrayInitializer or - JavaToken.NEW * ClassOrInterfaceType * Dims * ArrayInitializer - DimExprs = Some(DimExpr) - DimExpr = Many(Annotation) * JavaToken.BRACKETLEFT * Expression * JavaToken.BRACKETRIGHT - Expression = LambdaExpression or AssignmentExpression - LambdaExpression = LambdaParameters * JavaToken.ARROW * LambdaBody - LambdaParameters = Identifier or JavaToken.PARENTHLEFT * Option(FormalParameterList) * JavaToken.PARENTHRIGHT or - JavaToken.PARENTHLEFT * InferredFormalParameterList * JavaToken.PARENTHRIGHT - InferredFormalParameterList = Identifier * Many(JavaToken.COMMA * Identifier) - LambdaBody = Expression or Block - AssignmentExpression = ConditionalExpression or Assignment - Assignment = LeftHandSide * AssignmentOperator * Expression - LeftHandSide = ExpressionName or FieldAccess or ArrayAccess - AssignmentOperator = JavaToken.ASSIGN or JavaToken.STARASSIGN or JavaToken.SLASHASSIGN or JavaToken.PERCENTASSIGN or JavaToken.PLUSASSIGN or JavaToken.MINUSASSIGN or - JavaToken.SHIFTLEFTASSIGN or JavaToken.SHIFTRIGHTASSIGN or JavaToken.USRIGHTSHIFTASSIGN or JavaToken.ANDASSIGN or JavaToken.XORASSIGN or JavaToken.ORASSIGN - ConditionalExpression = ConditionalOrExpression or - ConditionalOrExpression * JavaToken.QUESTIONMARK * Expression * JavaToken.COLON * ConditionalExpression or - ConditionalOrExpression * JavaToken.QUESTIONMARK * Expression * JavaToken.COLON * LambdaExpression - ConditionalOrExpression = ConditionalAndExpression or - ConditionalOrExpression * JavaToken.OR * ConditionalAndExpression - ConditionalAndExpression = InclusiveOrExpression or - ConditionalAndExpression * JavaToken.AND * InclusiveOrExpression - InclusiveOrExpression = ExclusiveOrExpression or - InclusiveOrExpression * JavaToken.ORBIT * ExclusiveOrExpression - ExclusiveOrExpression = AndExpression or ExclusiveOrExpression * JavaToken.XORBIT * AndExpression - AndExpression = EqualityExpression or AndExpression * JavaToken.ANDBIT * EqualityExpression - EqualityExpression = RelationalExpression or EqualityExpression * JavaToken.EQ * RelationalExpression or - EqualityExpression * JavaToken.NOTEQ * RelationalExpression - RelationalExpression = ShiftExpression or RelationalExpression * JavaToken.LT * ShiftExpression or - RelationalExpression * JavaToken.GT * ShiftExpression or RelationalExpression * JavaToken.LESSEQ * ShiftExpression or - RelationalExpression * JavaToken.GREATEQ * ShiftExpression or RelationalExpression * JavaToken.INSTANCEOF * ReferenceType - ShiftExpression = AdditiveExpression or ShiftExpression * JavaToken.LT * JavaToken.LT * AdditiveExpression or - ShiftExpression * JavaToken.GT * JavaToken.GT * AdditiveExpression or - ShiftExpression * JavaToken.GT * JavaToken.GT * JavaToken.GT * AdditiveExpression - AdditiveExpression = MultiplicativeExpression or AdditiveExpression * JavaToken.PLUS * MultiplicativeExpression or - AdditiveExpression * JavaToken.MINUS * MultiplicativeExpression - MultiplicativeExpression = UnaryExpression or MultiplicativeExpression * JavaToken.STAR * UnaryExpression or - MultiplicativeExpression * JavaToken.SLASH * UnaryExpression or - MultiplicativeExpression * JavaToken.PERCENT * UnaryExpression - UnaryExpression = PreIncrementExpression or PreDecrementExpression or JavaToken.PLUS * UnaryExpression or - JavaToken.MINUS * UnaryExpression or UnaryExpressionNotPlusMinus - PreIncrementExpression = JavaToken.PLUSPLUS * UnaryExpression - PreDecrementExpression = JavaToken.MINUSMINUS * UnaryExpression - UnaryExpressionNotPlusMinus = PostfixExpression or JavaToken.TILDA * UnaryExpression or JavaToken.EXCLAMATIONMARK * UnaryExpression or - CastExpression - PostfixExpression = Primary or ExpressionName or PostIncrementExpression or PostDecrementExpression - PostIncrementExpression = PostfixExpression * JavaToken.PLUSPLUS - PostDecrementExpression = PostfixExpression * JavaToken.MINUSMINUS - CastExpression = JavaToken.PARENTHLEFT * PrimitiveType * JavaToken.PARENTHRIGHT * UnaryExpression or - JavaToken.PARENTHLEFT * ReferenceType * Many(AdditionalBound) * JavaToken.PARENTHRIGHT * UnaryExpressionNotPlusMinus or - JavaToken.PARENTHLEFT * ReferenceType * Many(AdditionalBound) * JavaToken.PARENTHRIGHT * LambdaExpression - ConstantExpression = Expression - - setStart(CompilationUnit) - } -} \ No newline at end of file diff --git a/benchmarks/src/jmh/kotlin/antlr4/Java8.g4 b/benchmarks/src/main/java/org/antlr/Java8.g4 similarity index 99% rename from benchmarks/src/jmh/kotlin/antlr4/Java8.g4 rename to benchmarks/src/main/java/org/antlr/Java8.g4 index 0a75e1741..af89ebed1 100644 --- a/benchmarks/src/jmh/kotlin/antlr4/Java8.g4 +++ b/benchmarks/src/main/java/org/antlr/Java8.g4 @@ -55,7 +55,7 @@ Total lexer+parser time 30844ms. grammar Java8; @header { -package antlr4; +package org.antlr; } /* diff --git a/benchmarks/src/main/kotlin/org/Antlr.kt b/benchmarks/src/main/kotlin/org/Antlr.kt new file mode 100644 index 000000000..dc1c59567 --- /dev/null +++ b/benchmarks/src/main/kotlin/org/Antlr.kt @@ -0,0 +1,25 @@ +package org + +import kotlinx.benchmark.* +import org.antlr.Java8Lexer +import org.antlr.Java8Parser +import org.antlr.v4.runtime.CharStreams +import org.antlr.v4.runtime.CommonTokenStream + + +@State(Scope.Benchmark) +class Antlr : BaseBench(){ + + @Benchmark + fun measureAntlr(blackhole: Blackhole) { + val antlrParser = + Java8Parser( + CommonTokenStream( + Java8Lexer( + CharStreams.fromString(fileContents) + ) + ) + ) + blackhole.consume(antlrParser.compilationUnit()) + } +} diff --git a/benchmarks/src/main/kotlin/org/BaseBench.kt b/benchmarks/src/main/kotlin/org/BaseBench.kt new file mode 100644 index 000000000..9bc706710 --- /dev/null +++ b/benchmarks/src/main/kotlin/org/BaseBench.kt @@ -0,0 +1,17 @@ +package org + +import kotlinx.benchmark.* +import java.io.File +@State(Scope.Benchmark) +abstract class BaseBench { + @Param("Throwables.java") + var fileName: String = "" + + lateinit var fileContents: String + + @Setup + open fun prepare() { + fileContents = File(fileName).readText() + } + +} \ No newline at end of file diff --git a/benchmarks/src/main/kotlin/org/Benchmarks.kt b/benchmarks/src/main/kotlin/org/Benchmarks.kt new file mode 100644 index 000000000..bc88c3e07 --- /dev/null +++ b/benchmarks/src/main/kotlin/org/Benchmarks.kt @@ -0,0 +1,58 @@ +package org + +import java7.JavaLexer +import java7.JavaToken +import org.ucfs.input.* +import org.ucfs.rsm.symbol.Term +import java.io.StringReader + +fun getResultPath( + pathToOutput: String, + inputName: String, + grammarMode: String, + grammarName: String, + sppfMode: String, +): String { + return pathToOutput + (if (pathToOutput.endsWith("/")) "" else "/") + "${inputName}_${grammarMode}_${grammarName}_${sppfMode}.csv" +} + + +fun getTokenStream(input: String): LinearInput { + val graph = LinearInput() + getTokenStream(input, graph) + return graph +} + + + +fun > getTokenStream(input: String, inputGraph: G): G { + val lexer = JavaLexer(StringReader(input)) + var token: JavaToken + var vertexId = 1 + + inputGraph.addVertex(vertexId) + inputGraph.addStartVertex(vertexId) + + while (true) { + token = lexer.yylex() as JavaToken + if (token == JavaToken.EOF) break + inputGraph.addEdge(vertexId, LinearInputLabel(token), ++vertexId) + } + + return inputGraph +} + +fun getCharStream(input: String): LinearInput { + val inputGraph = LinearInput() + var vertexId = 1 + + inputGraph.addVertex(vertexId) + inputGraph.addStartVertex(vertexId) + + for (ch in input) { + inputGraph.addEdge(vertexId, LinearInputLabel(Term(ch.toString())), ++vertexId) + inputGraph.addVertex(vertexId) + } + + return inputGraph +} diff --git a/benchmarks/src/main/kotlin/org/OfflineGll.kt b/benchmarks/src/main/kotlin/org/OfflineGll.kt new file mode 100644 index 000000000..0f74eaa6a --- /dev/null +++ b/benchmarks/src/main/kotlin/org/OfflineGll.kt @@ -0,0 +1,16 @@ +package org + +import kotlinx.benchmark.* +import org.ucfs.input.LinearInputLabel + + +@State(Scope.Benchmark) +class OfflineGll : BaseBench() { + + @Benchmark + fun measureGll(blackhole: Blackhole) { + val parser = org.ucfs.Java7Parser() + parser.input = getTokenStream(fileContents) + blackhole.consume(parser.parse()) + } +} diff --git a/benchmarks/src/main/kotlin/org/OnlineGll.kt b/benchmarks/src/main/kotlin/org/OnlineGll.kt new file mode 100644 index 000000000..8a3896b1e --- /dev/null +++ b/benchmarks/src/main/kotlin/org/OnlineGll.kt @@ -0,0 +1,29 @@ +package org + +import java7.Java7 +import kotlinx.benchmark.* +import org.junit.Before +import org.ucfs.input.LinearInput +import org.ucfs.input.LinearInputLabel +import org.ucfs.parser.Gll + + +@State(Scope.Benchmark) +class OnlineGll : BaseBench() { + + val startState = Java7().rsm + lateinit var tokens: LinearInput + + @Setup + @Before + override fun prepare() { + super.prepare() + tokens = getTokenStream(fileContents) + } + + @Benchmark + fun measureGll(blackhole: Blackhole) { + val gll = Gll.gll(startState, getTokenStream(fileContents)) + blackhole.consume(gll.parse()) + } +} diff --git a/benchmarks/src/main/kotlin/org/RecoveryOfflineGll.kt b/benchmarks/src/main/kotlin/org/RecoveryOfflineGll.kt new file mode 100644 index 000000000..316ef8809 --- /dev/null +++ b/benchmarks/src/main/kotlin/org/RecoveryOfflineGll.kt @@ -0,0 +1,15 @@ +package org + +import kotlinx.benchmark.* +import org.ucfs.input.LinearInputLabel + +@State(Scope.Benchmark) +class RecoveryOfflineGll : BaseBench() { + + @Benchmark + fun measureGll(blackhole: Blackhole) { + val parser = org.ucfs.Java7ParserRecovery() + parser.input = getTokenStream(fileContents) + blackhole.consume(parser.parse()) + } +} diff --git a/benchmarks/src/main/kotlin/org/RecoveryOnlineGll.kt b/benchmarks/src/main/kotlin/org/RecoveryOnlineGll.kt new file mode 100644 index 000000000..de020f5f1 --- /dev/null +++ b/benchmarks/src/main/kotlin/org/RecoveryOnlineGll.kt @@ -0,0 +1,29 @@ +package org + +import java7.Java7 +import kotlinx.benchmark.* +import org.junit.Before +import org.ucfs.input.LinearInput +import org.ucfs.input.LinearInputLabel +import org.ucfs.parser.Gll + + +@State(Scope.Benchmark) +class RecoveryOnlineGll : BaseBench() { + + val startState = Java7().rsm + lateinit var tokens: LinearInput + + @Setup + @Before + override fun prepare() { + super.prepare() + tokens = getTokenStream(fileContents) + } + + @Benchmark + fun measureGll(blackhole: Blackhole) { + val gll = Gll.recoveryGll(startState, getTokenStream(fileContents)) + blackhole.consume(gll.parse()) + } +} diff --git a/examples/build.gradle.kts b/examples/build.gradle.kts new file mode 100644 index 000000000..d3327a12b --- /dev/null +++ b/examples/build.gradle.kts @@ -0,0 +1,22 @@ +plugins { + + java + kotlin("jvm") version "1.9.20" + application +} + +group = "org.example" +version = "unspecified" + +application{ + mainClass = "java7.GeneratorKt" +} +repositories { + mavenCentral() +} + +dependencies { + implementation(project(":solver")) + implementation(project(":generator")) +} + diff --git a/benchmarks/src/jmh/kotlin/lexers/Java.x b/examples/src/main/java/java7/Java.x similarity index 98% rename from benchmarks/src/jmh/kotlin/lexers/Java.x rename to examples/src/main/java/java7/Java.x index b54c7e5ba..5e310aad3 100644 --- a/benchmarks/src/jmh/kotlin/lexers/Java.x +++ b/examples/src/main/java/java7/Java.x @@ -1,4 +1,4 @@ -package lexers; +package java7; import java.io.*; @@ -54,9 +54,9 @@ Comment = {TraditionalComment} | {DocumentationComment} TraditionalComment = "/*" [^*] ~"*/" | "/*" "*"+ "/" DocumentationComment = "/**" {CommentContent} "*"+ "/" CommentContent = ( [^*] | \*+ [^/*] )* - %% +"//".* { /* DO NOTHING */ } "boolean" { return JavaToken.BOOLEAN; } "byte" { return JavaToken.BYTE; } "short" { return JavaToken.SHORT; } diff --git a/examples/src/main/kotlin/dyck/DyckGrammar.kt b/examples/src/main/kotlin/dyck/DyckGrammar.kt new file mode 100644 index 000000000..940a5aa28 --- /dev/null +++ b/examples/src/main/kotlin/dyck/DyckGrammar.kt @@ -0,0 +1,19 @@ +package dyck + +import org.ucfs.grammar.combinator.Grammar +import org.ucfs.grammar.combinator.extension.StringExtension.times +import org.ucfs.grammar.combinator.regexp.Epsilon +import org.ucfs.grammar.combinator.regexp.Nt +import org.ucfs.grammar.combinator.regexp.or +import org.ucfs.grammar.combinator.regexp.times + +class DyckGrammar : Grammar() { + val S by Nt().asStart() + val Round by Nt("(" * S * ")") + val Quadrat by Nt("[" * S * "]") + val Curly by Nt("{" * S * "}") + + init { + S /= S * (Round or Quadrat or Curly) or Epsilon + } +} \ No newline at end of file diff --git a/examples/src/main/kotlin/java7/Generator.kt b/examples/src/main/kotlin/java7/Generator.kt new file mode 100644 index 000000000..955dff19a --- /dev/null +++ b/examples/src/main/kotlin/java7/Generator.kt @@ -0,0 +1,28 @@ +package java7 +import org.ucfs.parser.ParserGenerator +import org.ucfs.parser.RecoveryParserGenerator +import java.nio.file.Path +class Generator +fun main(args: Array){ + if(args.size != 1){ + throw IllegalArgumentException("Set first argument as path to generation") + } + val path = Path.of(args[0]) + println("Generate java7 UCFS parsers at ${path.toAbsolutePath()}") + generateJavaParser(path) + generateJavaRecoveryParser(path) +} + +fun generateJavaParser(path: Path) { + ParserGenerator( + Java7::class.java, + JavaToken::class.java + ).generate(path, "org.ucfs") +} +fun generateJavaRecoveryParser(path: Path) { + RecoveryParserGenerator( + Java7::class.java, + JavaToken::class.java + ).generate(path, "org.ucfs") +} + diff --git a/examples/src/main/kotlin/java7/Java7.kt b/examples/src/main/kotlin/java7/Java7.kt new file mode 100644 index 000000000..dcb27ed30 --- /dev/null +++ b/examples/src/main/kotlin/java7/Java7.kt @@ -0,0 +1,543 @@ +package java7 +import org.ucfs.grammar.combinator.Grammar +import org.ucfs.grammar.combinator.regexp.* + +class Java7 : Grammar() { + val CompilationUnit by Nt().asStart() + val Identifier by Nt() + val Literal by Nt() + val Type by Nt() + val PrimitiveType by Nt() + val ReferenceType by Nt() + val Annotation by Nt() + val NumericType by Nt() + val IntegralType by Nt() + val FloatingPointType by Nt() + val ClassOrInterfaceType by Nt() + val TypeVariable by Nt() + val ArrayType by Nt() + val ClassType by Nt() + val InterfaceType by Nt() + val TypeArguments by Nt() + val Dims by Nt() + val TypeParameter by Nt() + val TypeParameterModifier by Nt() + val TypeBound by Nt() + val AdditionalBound by Nt() + val TypeArgumentList by Nt() + val TypeArgument by Nt() + val Wildcard by Nt() + val WildcardBounds by Nt() + val TypeName by Nt() + val PackageOrTypeName by Nt() + val ExpressionName by Nt() + val AmbiguousName by Nt() + val MethodName by Nt() + val PackageName by Nt() + val Result by Nt() + val PackageDeclaration by Nt() + val ImportDeclaration by Nt() + val TypeDeclaration by Nt() + val PackageModifier by Nt() + val SingleTypeImportDeclaration by Nt() + val TypeImportOnDemandDeclaration by Nt() + val SingleStaticImportDeclaration by Nt() + val StaticImportOnDemandDeclaration by Nt() + val ClassDeclaration by Nt() + val InterfaceDeclaration by Nt() + val Throws by Nt() + val NormalClassDeclaration by Nt() + val EnumDeclaration by Nt() + val ClassModifier by Nt() + val TypeParameters by Nt() + val Superclass by Nt() + val Superinterfaces by Nt() + val ClassBody by Nt() + val TypeParameterList by Nt() + val InterfaceTypeList by Nt() + val ClassBodyDeclaration by Nt() + val ClassMemberDeclaration by Nt() + val InstanceInitializer by Nt() + val StaticInitializer by Nt() + val ConstructorDeclaration by Nt() + val FieldDeclaration by Nt() + val MethodDeclaration by Nt() + val FieldModifier by Nt() + val UnannType by Nt() + val VariableDeclaratorList by Nt() + val VariableDeclarator by Nt() + val VariableDeclaratorId by Nt() + val VariableInitializer by Nt() + val Expression by Nt() + val ArrayInitializer by Nt() + val UnannPrimitiveType by Nt() + val UnannReferenceType by Nt() + val UnannClassOrInterfaceType by Nt() + val UnannTypeVariable by Nt() + val UnannArrayType by Nt() + val UnannClassType by Nt() + val UnannInterfaceType by Nt() + val MethodModifier by Nt() + val MethodHeader by Nt() + val MethodBody by Nt() + val MethodDeclarator by Nt() + val FormalParameterList by Nt() + val ReceiverParameter by Nt() + val FormalParameters by Nt() + val LastFormalParameter by Nt() + val FormalParameter by Nt() + val VariableModifier by Nt() + val ExceptionTypeList by Nt() + val ExceptionType by Nt() + val Block by Nt() + val ConstructorModifier by Nt() + val ConstructorDeclarator by Nt() + val ConstructorBody by Nt() + val SimpleTypeName by Nt() + val ExplicitConstructorInvocation by Nt() + val EnumBody by Nt() + val EnumConstantList by Nt() + val EnumConstant by Nt() + val EnumConstantModifier by Nt() + val EnumBodyDeclarations by Nt() + val BlockStatements by Nt() + val ArgumentList by Nt() + val Primary by Nt() + val NormalInterfaceDeclaration by Nt() + val InterfaceModifier by Nt() + val ExtendsInterfaces by Nt() + val InterfaceBody by Nt() + val InterfaceMemberDeclaration by Nt() + val ConstantDeclaration by Nt() + val ConstantModifier by Nt() + val AnnotationTypeDeclaration by Nt() + val AnnotationTypeBody by Nt() + val AnnotationTypeMemberDeclaration by Nt() + val AnnotationTypeElementDeclaration by Nt() + val DefaultValue by Nt() + val NormalAnnotation by Nt() + val ElementValuePairList by Nt() + val ElementValuePair by Nt() + val ElementValue by Nt() + val ElementValueArrayInitializer by Nt() + val ElementValueList by Nt() + val MarkerAnnotation by Nt() + val SingleElementAnnotation by Nt() + val InterfaceMethodDeclaration by Nt() + val AnnotationTypeElementModifier by Nt() + val ConditionalExpression by Nt() + val VariableInitializerList by Nt() + val BlockStatement by Nt() + val LocalVariableDeclarationStatement by Nt() + val LocalVariableDeclaration by Nt() + val Statement by Nt() + val StatementNoShortIf by Nt() + val StatementWithoutTrailingSubstatement by Nt() + val EmptyStatement by Nt() + val LabeledStatement by Nt() + val LabeledStatementNoShortIf by Nt() + val ExpressionStatement by Nt() + val StatementExpression by Nt() + val IfThenStatement by Nt() + val IfThenElseStatement by Nt() + val IfThenElseStatementNoShortIf by Nt() + val AssertStatement by Nt() + val SwitchStatement by Nt() + val SwitchBlock by Nt() + val SwitchBlockStatementGroup by Nt() + val SwitchLabels by Nt() + val SwitchLabel by Nt() + val EnumConstantName by Nt() + val WhileStatement by Nt() + val WhileStatementNoShortIf by Nt() + val DoStatement by Nt() + val InterfaceMethodModifier by Nt() + val ForStatement by Nt() + val ForStatementNoShortIf by Nt() + val BasicForStatement by Nt() + val BasicForStatementNoShortIf by Nt() + val ForInit by Nt() + val ForUpdate by Nt() + val StatementExpressionList by Nt() + val EnhancedForStatement by Nt() + val EnhancedForStatementNoShortIf by Nt() + val BreakStatement by Nt() + val ContinueStatement by Nt() + val ReturnStatement by Nt() + val ThrowStatement by Nt() + val SynchronizedStatement by Nt() + val TryStatement by Nt() + val Catches by Nt() + val CatchClause by Nt() + val CatchFormalParameter by Nt() + val CatchType by Nt() + val Finally by Nt() + val TryWithResourcesStatement by Nt() + val ResourceSpecification by Nt() + val ResourceList by Nt() + val Resource by Nt() + val PrimaryNoNewArray by Nt() + val ClassLiteral by Nt() + val classOrInterfaceTypeToInstantiate by Nt() + val UnqualifiedClassInstanceCreationExpression by Nt() + val ClassInstanceCreationExpression by Nt() + val FieldAccess by Nt() + val TypeArgumentsOrDiamond by Nt() + val ArrayAccess by Nt() + val MethodInvocation by Nt() + val MethodReference by Nt() + val ArrayCreationExpression by Nt() + val DimExprs by Nt() + val DimExpr by Nt() + val LambdaExpression by Nt() + val LambdaParameters by Nt() + val InferredFormalParameterList by Nt() + val LambdaBody by Nt() + val AssignmentExpression by Nt() + val Assignment by Nt() + val LeftHandSide by Nt() + val AssignmentOperator by Nt() + val ConditionalOrExpression by Nt() + val ConditionalAndExpression by Nt() + val InclusiveOrExpression by Nt() + val ExclusiveOrExpression by Nt() + val AndExpression by Nt() + val EqualityExpression by Nt() + val RelationalExpression by Nt() + val ShiftExpression by Nt() + val AdditiveExpression by Nt() + val MultiplicativeExpression by Nt() + val PreIncrementExpression by Nt() + val PreDecrementExpression by Nt() + val UnaryExpressionNotPlusMinus by Nt() + val UnaryExpression by Nt() + val PostfixExpression by Nt() + val PostIncrementExpression by Nt() + val PostDecrementExpression by Nt() + val CastExpression by Nt() + val ConstantExpression by Nt() + + init { + Identifier /= JavaToken.ID + + Literal /= JavaToken.INTEGERLIT or JavaToken.FLOATINGLIT or JavaToken.BOOLEANLIT or + JavaToken.CHARLIT or JavaToken.STRINGLIT or JavaToken.NULLLIT + + /** + * Productions from §4 (Types, Values, and Variables) + */ + Type /= PrimitiveType or ReferenceType + PrimitiveType /= Many(Annotation) * NumericType or Many(Annotation) * JavaToken.BOOLEAN + NumericType /= IntegralType or FloatingPointType + IntegralType /= JavaToken.BYTE or JavaToken.SHORT or JavaToken.INT or JavaToken.LONG or JavaToken.CHAR + FloatingPointType /= JavaToken.FLOAT or JavaToken.DOUBLE + ReferenceType /= ClassOrInterfaceType or TypeVariable or ArrayType + ClassOrInterfaceType /= ClassType or InterfaceType + ClassType /= Many(Annotation) * Identifier * Option(TypeArguments) or + ClassOrInterfaceType * JavaToken.DOT * Many(Annotation) * Identifier * Option(TypeArguments) + InterfaceType /= ClassType + TypeVariable /= Many(Annotation) * Identifier + ArrayType /= PrimitiveType * Dims or ClassOrInterfaceType * Dims or TypeVariable * Dims + Dims /= some(Many(Annotation) * JavaToken.BRACKETLEFT * JavaToken.BRACKETRIGHT) + TypeParameter /= Many(TypeParameterModifier) * Identifier * Option(TypeBound) + TypeParameterModifier /= Annotation + TypeBound /= JavaToken.EXTENDS * TypeVariable or JavaToken.EXTENDS * ClassOrInterfaceType * Many(AdditionalBound) + AdditionalBound /= JavaToken.ANDBIT * InterfaceType + TypeArguments /= JavaToken.LT * TypeArgumentList * JavaToken.GT + TypeArgumentList /= TypeArgument * Many(JavaToken.COMMA * TypeArgument) + TypeArgument /= ReferenceType or Wildcard + Wildcard /= Many(Annotation) * JavaToken.QUESTIONMARK * Option(WildcardBounds) + WildcardBounds /= JavaToken.EXTENDS * ReferenceType or JavaToken.SUPER * ReferenceType + + /** + * Productions from §6 (Names) + */ + + TypeName /= Identifier or PackageOrTypeName * JavaToken.DOT * Identifier + PackageOrTypeName /= Identifier or PackageOrTypeName * JavaToken.DOT * Identifier + ExpressionName /= Identifier or AmbiguousName * JavaToken.DOT * Identifier + MethodName /= Identifier + PackageName /= Identifier or PackageName * JavaToken.DOT * Identifier + AmbiguousName /= Identifier or AmbiguousName * JavaToken.DOT * Identifier + + /** + * Productions from §7 (Packages) + */ + + CompilationUnit /= Option(PackageDeclaration) * Many(ImportDeclaration) * Many(TypeDeclaration) + PackageDeclaration /= Many(PackageModifier) * JavaToken.PACKAGE * Identifier * Many(JavaToken.DOT * Identifier) * JavaToken.SEMICOLON + PackageModifier /= Annotation + ImportDeclaration /= SingleTypeImportDeclaration or TypeImportOnDemandDeclaration or + SingleStaticImportDeclaration or StaticImportOnDemandDeclaration + SingleTypeImportDeclaration /= JavaToken.IMPORT * TypeName * JavaToken.SEMICOLON + TypeImportOnDemandDeclaration /= JavaToken.IMPORT * PackageOrTypeName * JavaToken.DOT * JavaToken.STAR * JavaToken.SEMICOLON + SingleStaticImportDeclaration /= JavaToken.IMPORT * JavaToken.STATIC * TypeName * JavaToken.DOT * Identifier * JavaToken.SEMICOLON + StaticImportOnDemandDeclaration /= JavaToken.IMPORT * JavaToken.STATIC * TypeName * JavaToken.DOT * JavaToken.STAR * JavaToken.SEMICOLON + TypeDeclaration /= ClassDeclaration or InterfaceDeclaration or JavaToken.SEMICOLON + + /** + * Productions from §8 (Classes) + */ + + ClassDeclaration /= NormalClassDeclaration or EnumDeclaration + NormalClassDeclaration /= Many(ClassModifier) * JavaToken.CLASS * Identifier * + Option(TypeParameters) * Option(Superclass) * Option(Superinterfaces) * ClassBody + ClassModifier /= Annotation or JavaToken.PUBLIC or JavaToken.PROTECTED or JavaToken.PRIVATE or + JavaToken.ABSTRACT or JavaToken.STATIC or JavaToken.FINAL or JavaToken.STRICTFP + TypeParameters /= JavaToken.LT * TypeParameterList * JavaToken.GT + TypeParameterList /= TypeParameter * Many(JavaToken.COMMA * TypeParameter) + Superclass /= JavaToken.EXTENDS * ClassType + Superinterfaces /= JavaToken.IMPLEMENTS * InterfaceTypeList + InterfaceTypeList /= InterfaceType * Many(JavaToken.COMMA * InterfaceType) + ClassBody /= JavaToken.CURLYLEFT * Many(ClassBodyDeclaration) * JavaToken.CURLYRIGHT + ClassBodyDeclaration /= ClassMemberDeclaration or InstanceInitializer or StaticInitializer or ConstructorDeclaration + ClassMemberDeclaration /= FieldDeclaration or MethodDeclaration or ClassDeclaration or InterfaceDeclaration or JavaToken.SEMICOLON + FieldDeclaration /= Many(FieldModifier) * UnannType * VariableDeclaratorList * JavaToken.SEMICOLON + FieldModifier /= Annotation or JavaToken.PUBLIC or JavaToken.PROTECTED or JavaToken.PRIVATE or JavaToken.STATIC or + JavaToken.FINAL or JavaToken.TRANSIENT or JavaToken.VOLATILE + VariableDeclaratorList /= VariableDeclarator * Many(JavaToken.COMMA * VariableDeclarator) + VariableDeclarator /= VariableDeclaratorId * Option(JavaToken.ASSIGN * VariableInitializer) + VariableDeclaratorId /= Identifier * Option(Dims) + VariableInitializer /= Expression or ArrayInitializer + UnannType /= UnannPrimitiveType or UnannReferenceType + UnannPrimitiveType /= NumericType or JavaToken.BOOLEAN + UnannReferenceType /= UnannClassOrInterfaceType or UnannTypeVariable or UnannArrayType + UnannClassOrInterfaceType /= UnannClassType or UnannInterfaceType + UnannClassType /= Identifier * Option(TypeArguments) or + UnannClassOrInterfaceType * JavaToken.DOT * Many(Annotation) * Identifier * Option(TypeArguments) + UnannInterfaceType /= UnannClassType + UnannTypeVariable /= Identifier + UnannArrayType /= UnannPrimitiveType * Dims or UnannClassOrInterfaceType * Dims or UnannTypeVariable * Dims + MethodDeclaration /= Many(MethodModifier) * MethodHeader * MethodBody + MethodModifier /= Annotation or JavaToken.PUBLIC or JavaToken.PROTECTED or JavaToken.PRIVATE or JavaToken.ABSTRACT or + JavaToken.STATIC or JavaToken.FINAL or JavaToken.SYNCHRONIZED or JavaToken.NATIVE or JavaToken.STRICTFP + MethodHeader /= Result * MethodDeclarator * Option(Throws) or + TypeParameters * Many(Annotation) * Result * MethodDeclarator * Option(Throws) + Result /= UnannType or JavaToken.VOID + MethodDeclarator /= Identifier * JavaToken.PARENTHLEFT * Option(FormalParameterList) * JavaToken.PARENTHRIGHT * Option(Dims) + FormalParameterList /= ReceiverParameter or FormalParameters * JavaToken.COMMA * LastFormalParameter or + LastFormalParameter + FormalParameters /= FormalParameter * Many(JavaToken.COMMA * FormalParameter) or + ReceiverParameter * Many(JavaToken.COMMA * FormalParameter) + FormalParameter /= Many(VariableModifier) * UnannType * VariableDeclaratorId + VariableModifier /= Annotation or JavaToken.FINAL + LastFormalParameter /= Many(VariableModifier) * UnannType * Many(Annotation) * JavaToken.ELLIPSIS * VariableDeclaratorId or FormalParameter + ReceiverParameter /= Many(Annotation) * UnannType * Option(Identifier * JavaToken.DOT) * JavaToken.THIS + Throws /= JavaToken.THROWS * ExceptionTypeList + ExceptionTypeList /= ExceptionType * Many(JavaToken.COMMA * ExceptionType) + ExceptionType /= ClassType or TypeVariable + MethodBody /= Block or JavaToken.SEMICOLON + InstanceInitializer /= Block + StaticInitializer /= JavaToken.STATIC * Block + ConstructorDeclaration /= Many(ConstructorModifier) * ConstructorDeclarator * Option(Throws) * ConstructorBody + ConstructorModifier /= Annotation or JavaToken.PUBLIC or JavaToken.PROTECTED or JavaToken.PRIVATE + ConstructorDeclarator /= Option(TypeParameters) * SimpleTypeName * JavaToken.PARENTHLEFT * Option(FormalParameterList) * JavaToken.PARENTHRIGHT + SimpleTypeName /= Identifier + ConstructorBody /= JavaToken.CURLYLEFT * Option(ExplicitConstructorInvocation) * Option(BlockStatements) * JavaToken.CURLYRIGHT + ExplicitConstructorInvocation /= Option(TypeArguments) * JavaToken.THIS * JavaToken.PARENTHLEFT * Option(ArgumentList) * JavaToken.PARENTHRIGHT * JavaToken.SEMICOLON or + Option(TypeArguments) * JavaToken.SUPER * JavaToken.PARENTHLEFT * Option(ArgumentList) * JavaToken.PARENTHRIGHT * JavaToken.SEMICOLON or + ExpressionName * JavaToken.DOT * Option(TypeArguments) * JavaToken.SUPER * JavaToken.PARENTHLEFT * Option(ArgumentList) * JavaToken.PARENTHRIGHT * JavaToken.SEMICOLON or + Primary * JavaToken.DOT * Option(TypeArguments) * JavaToken.SUPER * JavaToken.PARENTHLEFT * Option(ArgumentList) * JavaToken.PARENTHRIGHT * JavaToken.SEMICOLON + EnumDeclaration /= Many(ClassModifier) * JavaToken.ENUM * Identifier * Option(Superinterfaces) * EnumBody + EnumBody /= JavaToken.CURLYLEFT * Option(EnumConstantList) * Option(JavaToken.COMMA) * Option(EnumBodyDeclarations) * JavaToken.CURLYRIGHT + EnumConstantList /= EnumConstant * Many(JavaToken.COMMA * EnumConstant) + EnumConstant /= Many(EnumConstantModifier) * Identifier * Option(JavaToken.PARENTHLEFT * Option(ArgumentList) * JavaToken.PARENTHRIGHT * Option(ClassBody)) + EnumConstantModifier /= Annotation + EnumBodyDeclarations /= JavaToken.SEMICOLON * Many(ClassBodyDeclaration) + + /** + * Productions from §9 (Interfaces) + */ + + InterfaceDeclaration /= NormalInterfaceDeclaration or AnnotationTypeDeclaration + NormalInterfaceDeclaration /= + Many(InterfaceModifier) * JavaToken.INTERFACE * Identifier * Option(TypeParameters) * Option(ExtendsInterfaces) * InterfaceBody + InterfaceModifier /= Annotation or JavaToken.PUBLIC or JavaToken.PROTECTED or JavaToken.PRIVATE or + JavaToken.ABSTRACT or JavaToken.STATIC or JavaToken.STRICTFP + ExtendsInterfaces /= JavaToken.EXTENDS * InterfaceTypeList + InterfaceBody /= JavaToken.CURLYLEFT * Many(InterfaceMemberDeclaration) * JavaToken.CURLYRIGHT + InterfaceMemberDeclaration /= ConstantDeclaration or InterfaceMethodDeclaration or ClassDeclaration or InterfaceDeclaration or JavaToken.SEMICOLON + ConstantDeclaration /= Many(ConstantModifier) * UnannType * VariableDeclaratorList * JavaToken.SEMICOLON + ConstantModifier /= Annotation or JavaToken.PUBLIC or JavaToken.STATIC or JavaToken.FINAL + InterfaceMethodDeclaration /= Many(InterfaceMethodModifier) * MethodHeader * MethodBody + InterfaceMethodModifier /= Annotation or JavaToken.PUBLIC or JavaToken.ABSTRACT or JavaToken.DEFAULT or JavaToken.STATIC or JavaToken.STRICTFP + AnnotationTypeDeclaration /= Many(InterfaceModifier) * JavaToken.AT * JavaToken.INTERFACE * Identifier * AnnotationTypeBody + AnnotationTypeBody /= JavaToken.CURLYLEFT * Many(AnnotationTypeMemberDeclaration) * JavaToken.CURLYRIGHT + AnnotationTypeMemberDeclaration /= AnnotationTypeElementDeclaration or ConstantDeclaration or ClassDeclaration or InterfaceDeclaration or JavaToken.SEMICOLON + AnnotationTypeElementDeclaration /= + Many(AnnotationTypeElementModifier) * UnannType * Identifier * JavaToken.PARENTHLEFT * JavaToken.PARENTHRIGHT * Option(Dims) * Option(DefaultValue) * JavaToken.SEMICOLON + AnnotationTypeElementModifier /= Annotation or JavaToken.PUBLIC or JavaToken.ABSTRACT + DefaultValue /= JavaToken.DEFAULT * ElementValue + Annotation /= NormalAnnotation or MarkerAnnotation or SingleElementAnnotation + NormalAnnotation /= JavaToken.AT * TypeName * JavaToken.PARENTHLEFT * Option(ElementValuePairList) * JavaToken.PARENTHRIGHT + ElementValuePairList /= ElementValuePair * Many(JavaToken.COMMA * ElementValuePair) + ElementValuePair /= Identifier * JavaToken.ASSIGN * ElementValue + ElementValue /= ConditionalExpression or ElementValueArrayInitializer or Annotation + ElementValueArrayInitializer /= JavaToken.CURLYLEFT * Option(ElementValueList) * Option(JavaToken.COMMA) * JavaToken.CURLYRIGHT + ElementValueList /= ElementValue * Many(JavaToken.COMMA * ElementValue) + MarkerAnnotation /= JavaToken.AT * TypeName + SingleElementAnnotation /= JavaToken.AT * TypeName * JavaToken.PARENTHLEFT * ElementValue * JavaToken.PARENTHRIGHT + + /** + * Productions from §10 (Arrays) + */ + + ArrayInitializer /= JavaToken.CURLYLEFT * Option(VariableInitializerList) * Option(JavaToken.COMMA) * JavaToken.CURLYRIGHT + VariableInitializerList /= VariableInitializer * Many(JavaToken.COMMA * VariableInitializer) + + /** + * Productions from §14 (Blocks and Statements) + */ + + Block /= JavaToken.CURLYLEFT * Option(BlockStatements) * JavaToken.CURLYRIGHT + BlockStatements /= BlockStatement * Many(BlockStatement) + BlockStatement /= LocalVariableDeclarationStatement or ClassDeclaration or Statement + LocalVariableDeclarationStatement /= LocalVariableDeclaration * JavaToken.SEMICOLON + LocalVariableDeclaration /= Many(VariableModifier) * UnannType * VariableDeclaratorList + Statement /= StatementWithoutTrailingSubstatement or LabeledStatement or IfThenStatement or IfThenElseStatement or + WhileStatement or ForStatement + StatementNoShortIf /= StatementWithoutTrailingSubstatement or LabeledStatementNoShortIf or IfThenElseStatementNoShortIf or + WhileStatementNoShortIf or ForStatementNoShortIf + StatementWithoutTrailingSubstatement /= Block or EmptyStatement or ExpressionStatement or AssertStatement or + SwitchStatement or DoStatement or BreakStatement or ContinueStatement or ReturnStatement or SynchronizedStatement or + ThrowStatement or TryStatement + EmptyStatement /= JavaToken.SEMICOLON + LabeledStatement /= Identifier * JavaToken.COLON * Statement + LabeledStatementNoShortIf /= Identifier * JavaToken.COLON * StatementNoShortIf + ExpressionStatement /= StatementExpression * JavaToken.SEMICOLON + StatementExpression /= Assignment or PreIncrementExpression or PreDecrementExpression or PostIncrementExpression or + PostDecrementExpression or MethodInvocation or ClassInstanceCreationExpression + IfThenStatement /= JavaToken.IF * JavaToken.PARENTHLEFT * Expression * JavaToken.PARENTHRIGHT * Statement + IfThenElseStatement /= JavaToken.IF * JavaToken.PARENTHLEFT * Expression * JavaToken.PARENTHRIGHT * StatementNoShortIf * JavaToken.ELSE * Statement + IfThenElseStatementNoShortIf /= + JavaToken.IF * JavaToken.PARENTHLEFT * Expression * JavaToken.PARENTHRIGHT * StatementNoShortIf * JavaToken.ELSE * StatementNoShortIf + AssertStatement /= JavaToken.ASSERT * Expression * JavaToken.SEMICOLON or + JavaToken.ASSERT * Expression * JavaToken.COLON * Expression * JavaToken.SEMICOLON + SwitchStatement /= JavaToken.SWITCH * JavaToken.PARENTHLEFT * Expression * JavaToken.PARENTHRIGHT * SwitchBlock + SwitchBlock /= JavaToken.CURLYLEFT * Many(SwitchBlockStatementGroup) * Many(SwitchLabel) * JavaToken.CURLYRIGHT + SwitchBlockStatementGroup /= SwitchLabels * BlockStatements + SwitchLabels /= some(SwitchLabel) + SwitchLabel /= JavaToken.CASE * ConstantExpression * JavaToken.COLON or + JavaToken.CASE * EnumConstantName * JavaToken.COLON or JavaToken.DEFAULT * JavaToken.COLON + EnumConstantName /= Identifier + WhileStatement /= JavaToken.WHILE * JavaToken.PARENTHLEFT * Expression * JavaToken.PARENTHRIGHT * Statement + WhileStatementNoShortIf /= JavaToken.WHILE * JavaToken.PARENTHLEFT * Expression * JavaToken.PARENTHRIGHT * StatementNoShortIf + DoStatement /= JavaToken.DO * Statement * JavaToken.WHILE * JavaToken.PARENTHLEFT * Expression * JavaToken.PARENTHRIGHT * JavaToken.SEMICOLON + ForStatement /= BasicForStatement or EnhancedForStatement + ForStatementNoShortIf /= BasicForStatementNoShortIf or EnhancedForStatementNoShortIf + BasicForStatement /= JavaToken.FOR * JavaToken.PARENTHLEFT * Option(ForInit) * JavaToken.SEMICOLON * Option(Expression) * JavaToken.SEMICOLON * Option(ForUpdate) * JavaToken.PARENTHRIGHT * Statement + BasicForStatementNoShortIf /= JavaToken.FOR * JavaToken.PARENTHLEFT * Option(ForInit) * JavaToken.SEMICOLON * Option(Expression) * JavaToken.SEMICOLON * Option(ForUpdate) * JavaToken.PARENTHRIGHT * StatementNoShortIf + ForInit /= StatementExpressionList or LocalVariableDeclaration + ForUpdate /= StatementExpressionList + StatementExpressionList /= StatementExpression * Many(JavaToken.COMMA * StatementExpression) + EnhancedForStatement /= JavaToken.FOR * JavaToken.PARENTHLEFT * Many(VariableModifier) * UnannType * VariableDeclaratorId * JavaToken.COLON * Expression * JavaToken.PARENTHRIGHT * Statement + EnhancedForStatementNoShortIf /= JavaToken.FOR * JavaToken.PARENTHLEFT * Many(VariableModifier) * UnannType * VariableDeclaratorId * JavaToken.COLON * Expression * JavaToken.PARENTHRIGHT * StatementNoShortIf + BreakStatement /= JavaToken.BREAK * Option(Identifier) * JavaToken.SEMICOLON + ContinueStatement /= JavaToken.CONTINUE * Option(Identifier) * JavaToken.SEMICOLON + ReturnStatement /= JavaToken.RETURN * Option(Expression) * JavaToken.SEMICOLON + ThrowStatement /= JavaToken.THROW * Expression * JavaToken.SEMICOLON + SynchronizedStatement /= JavaToken.SYNCHRONIZED * JavaToken.PARENTHLEFT * Expression * JavaToken.PARENTHRIGHT * Block + TryStatement /= JavaToken.TRY * Block * Catches or JavaToken.TRY * Block * Option(Catches) * Finally or TryWithResourcesStatement + Catches /= some(CatchClause) + CatchClause /= JavaToken.CATCH * JavaToken.PARENTHLEFT * CatchFormalParameter * JavaToken.PARENTHRIGHT * Block + CatchFormalParameter /= Many(VariableModifier) * CatchType * VariableDeclaratorId + CatchType /= UnannClassType * Many(JavaToken.ORBIT * ClassType) + Finally /= JavaToken.FINALLY * Block + TryWithResourcesStatement /= JavaToken.TRY * ResourceSpecification * Block * Option(Catches) * Option(Finally) + ResourceSpecification /= JavaToken.PARENTHLEFT * ResourceList * Option(JavaToken.SEMICOLON) * JavaToken.PARENTHRIGHT + ResourceList /= Resource * Many(JavaToken.COMMA * Resource) + Resource /= Many(VariableModifier) * UnannType * VariableDeclaratorId * JavaToken.ASSIGN * Expression + + /** + * Productions from §15 (Expressions) + */ + + Primary /= PrimaryNoNewArray or ArrayCreationExpression + PrimaryNoNewArray /= Literal or ClassLiteral or JavaToken.THIS or TypeName * JavaToken.DOT * JavaToken.THIS or + JavaToken.PARENTHLEFT * Expression * JavaToken.PARENTHRIGHT or ClassInstanceCreationExpression or FieldAccess or + ArrayAccess or MethodInvocation or MethodReference + ClassLiteral /= TypeName * Many(JavaToken.BRACKETLEFT * JavaToken.BRACKETRIGHT) * JavaToken.DOT * JavaToken.CLASS or + NumericType * Many(JavaToken.BRACKETLEFT * JavaToken.BRACKETRIGHT) * JavaToken.DOT * JavaToken.CLASS or + JavaToken.BOOLEAN * Many(JavaToken.BRACKETLEFT * JavaToken.BRACKETRIGHT) * JavaToken.DOT * JavaToken.CLASS or + JavaToken.VOID * JavaToken.DOT * JavaToken.CLASS + ClassInstanceCreationExpression /= UnqualifiedClassInstanceCreationExpression or + ExpressionName * JavaToken.DOT * UnqualifiedClassInstanceCreationExpression or + Primary * JavaToken.DOT * UnqualifiedClassInstanceCreationExpression + UnqualifiedClassInstanceCreationExpression /= + JavaToken.NEW * Option(TypeArguments) * classOrInterfaceTypeToInstantiate * JavaToken.PARENTHLEFT * Option(ArgumentList) * JavaToken.PARENTHRIGHT * Option(ClassBody) + classOrInterfaceTypeToInstantiate /= Many(Annotation) * Identifier * Many(JavaToken.DOT * Many(Annotation) * Identifier) * Option(TypeArgumentsOrDiamond) + TypeArgumentsOrDiamond /= TypeArguments or JavaToken.LT * JavaToken.GT + FieldAccess /= Primary * JavaToken.DOT * Identifier or JavaToken.SUPER * JavaToken.DOT * Identifier or + TypeName * JavaToken.DOT * JavaToken.SUPER * JavaToken.DOT * Identifier + ArrayAccess /= ExpressionName * JavaToken.BRACKETLEFT * Expression * JavaToken.BRACKETRIGHT or + PrimaryNoNewArray * JavaToken.BRACKETLEFT * Expression * JavaToken.BRACKETRIGHT + MethodInvocation /= MethodName * JavaToken.PARENTHLEFT * Option(ArgumentList) * JavaToken.PARENTHRIGHT or + TypeName * JavaToken.DOT * Option(TypeArguments) * Identifier * JavaToken.PARENTHLEFT * Option(ArgumentList) * JavaToken.PARENTHRIGHT or + ExpressionName * JavaToken.DOT * Option(TypeArguments) * Identifier * JavaToken.PARENTHLEFT * Option(ArgumentList) * JavaToken.PARENTHRIGHT or + Primary * JavaToken.DOT * Option(TypeArguments) * Identifier * JavaToken.PARENTHLEFT * Option(ArgumentList) * JavaToken.PARENTHRIGHT or + JavaToken.SUPER * JavaToken.DOT * Option(TypeArguments) * Identifier * JavaToken.PARENTHLEFT * Option(ArgumentList) * JavaToken.PARENTHRIGHT or + TypeName * JavaToken.DOT * JavaToken.SUPER * JavaToken.DOT * Option(TypeArguments) * Identifier * JavaToken.PARENTHLEFT * Option(ArgumentList) * JavaToken.PARENTHRIGHT + ArgumentList /= Expression * Many(JavaToken.COMMA * Expression) + MethodReference /= ExpressionName * JavaToken.DOUBLECOLON * Option(TypeArguments) * Identifier or + ReferenceType * JavaToken.DOUBLECOLON * Option(TypeArguments) * Identifier or + Primary * JavaToken.DOUBLECOLON * Option(TypeArguments) * Identifier or + JavaToken.SUPER * JavaToken.DOUBLECOLON * Option(TypeArguments) * Identifier or + TypeName * JavaToken.DOT * JavaToken.SUPER * JavaToken.DOUBLECOLON * Option(TypeArguments) * Identifier or + ClassType * JavaToken.DOUBLECOLON * Option(TypeArguments) * JavaToken.NEW or + ArrayType * JavaToken.DOUBLECOLON * JavaToken.NEW + ArrayCreationExpression /= JavaToken.NEW * PrimitiveType * DimExprs * Option(Dims) or + JavaToken.NEW * ClassOrInterfaceType * DimExprs * Option(Dims) or + JavaToken.NEW * PrimitiveType * Dims * ArrayInitializer or + JavaToken.NEW * ClassOrInterfaceType * Dims * ArrayInitializer + DimExprs /= some(DimExpr) + DimExpr /= Many(Annotation) * JavaToken.BRACKETLEFT * Expression * JavaToken.BRACKETRIGHT + Expression /= LambdaExpression or AssignmentExpression + LambdaExpression /= LambdaParameters * JavaToken.ARROW * LambdaBody + LambdaParameters /= Identifier or JavaToken.PARENTHLEFT * Option(FormalParameterList) * JavaToken.PARENTHRIGHT or + JavaToken.PARENTHLEFT * InferredFormalParameterList * JavaToken.PARENTHRIGHT + InferredFormalParameterList /= Identifier * Many(JavaToken.COMMA * Identifier) + LambdaBody /= Expression or Block + AssignmentExpression /= ConditionalExpression or Assignment + Assignment /= LeftHandSide * AssignmentOperator * Expression + LeftHandSide /= ExpressionName or FieldAccess or ArrayAccess + AssignmentOperator /= JavaToken.ASSIGN or JavaToken.STARASSIGN or JavaToken.SLASHASSIGN or JavaToken.PERCENTASSIGN or JavaToken.PLUSASSIGN or JavaToken.MINUSASSIGN or + JavaToken.SHIFTLEFTASSIGN or JavaToken.SHIFTRIGHTASSIGN or JavaToken.USRIGHTSHIFTASSIGN or JavaToken.ANDASSIGN or JavaToken.XORASSIGN or JavaToken.ORASSIGN + ConditionalExpression /= ConditionalOrExpression or + ConditionalOrExpression * JavaToken.QUESTIONMARK * Expression * JavaToken.COLON * ConditionalExpression or + ConditionalOrExpression * JavaToken.QUESTIONMARK * Expression * JavaToken.COLON * LambdaExpression + ConditionalOrExpression /= ConditionalAndExpression or + ConditionalOrExpression * JavaToken.OR * ConditionalAndExpression + ConditionalAndExpression /= InclusiveOrExpression or + ConditionalAndExpression * JavaToken.AND * InclusiveOrExpression + InclusiveOrExpression /= ExclusiveOrExpression or + InclusiveOrExpression * JavaToken.ORBIT * ExclusiveOrExpression + ExclusiveOrExpression /= AndExpression or ExclusiveOrExpression * JavaToken.XORBIT * AndExpression + AndExpression /= EqualityExpression or AndExpression * JavaToken.ANDBIT * EqualityExpression + EqualityExpression /= RelationalExpression or EqualityExpression * JavaToken.EQ * RelationalExpression or + EqualityExpression * JavaToken.NOTEQ * RelationalExpression + RelationalExpression /= ShiftExpression or RelationalExpression * JavaToken.LT * ShiftExpression or + RelationalExpression * JavaToken.GT * ShiftExpression or RelationalExpression * JavaToken.LESSEQ * ShiftExpression or + RelationalExpression * JavaToken.GREATEQ * ShiftExpression or RelationalExpression * JavaToken.INSTANCEOF * ReferenceType + ShiftExpression /= AdditiveExpression or ShiftExpression * JavaToken.LT * JavaToken.LT * AdditiveExpression or + ShiftExpression * JavaToken.GT * JavaToken.GT * AdditiveExpression or + ShiftExpression * JavaToken.GT * JavaToken.GT * JavaToken.GT * AdditiveExpression + AdditiveExpression /= MultiplicativeExpression or AdditiveExpression * JavaToken.PLUS * MultiplicativeExpression or + AdditiveExpression * JavaToken.MINUS * MultiplicativeExpression + MultiplicativeExpression /= UnaryExpression or MultiplicativeExpression * JavaToken.STAR * UnaryExpression or + MultiplicativeExpression * JavaToken.SLASH * UnaryExpression or + MultiplicativeExpression * JavaToken.PERCENT * UnaryExpression + UnaryExpression /= PreIncrementExpression or PreDecrementExpression or JavaToken.PLUS * UnaryExpression or + JavaToken.MINUS * UnaryExpression or UnaryExpressionNotPlusMinus + PreIncrementExpression /= JavaToken.PLUSPLUS * UnaryExpression + PreDecrementExpression /= JavaToken.MINUSMINUS * UnaryExpression + UnaryExpressionNotPlusMinus /= PostfixExpression or JavaToken.TILDA * UnaryExpression or JavaToken.EXCLAMATIONMARK * UnaryExpression or + CastExpression + PostfixExpression /= Primary or ExpressionName or PostIncrementExpression or PostDecrementExpression + PostIncrementExpression /= PostfixExpression * JavaToken.PLUSPLUS + PostDecrementExpression /= PostfixExpression * JavaToken.MINUSMINUS + CastExpression /= JavaToken.PARENTHLEFT * PrimitiveType * JavaToken.PARENTHRIGHT * UnaryExpression or + JavaToken.PARENTHLEFT * ReferenceType * Many(AdditionalBound) * JavaToken.PARENTHRIGHT * UnaryExpressionNotPlusMinus or + JavaToken.PARENTHLEFT * ReferenceType * Many(AdditionalBound) * JavaToken.PARENTHRIGHT * LambdaExpression + ConstantExpression /= Expression + } +} \ No newline at end of file diff --git a/benchmarks/src/jmh/kotlin/lexers/JavaToken.kt b/examples/src/main/kotlin/java7/JavaToken.kt similarity index 99% rename from benchmarks/src/jmh/kotlin/lexers/JavaToken.kt rename to examples/src/main/kotlin/java7/JavaToken.kt index 80d2dec46..ef7afb958 100644 --- a/benchmarks/src/jmh/kotlin/lexers/JavaToken.kt +++ b/examples/src/main/kotlin/java7/JavaToken.kt @@ -1,4 +1,4 @@ -package lexers +package java7 import org.ucfs.parser.ParsingException import org.ucfs.rsm.symbol.ITerminal diff --git a/generator/src/main/kotlin/org/ucfs/IGeneratorFromGrammar.kt b/generator/src/main/kotlin/org/ucfs/IGeneratorFromGrammar.kt index b5ac7773e..47dcbe4f6 100644 --- a/generator/src/main/kotlin/org/ucfs/IGeneratorFromGrammar.kt +++ b/generator/src/main/kotlin/org/ucfs/IGeneratorFromGrammar.kt @@ -5,7 +5,6 @@ import com.squareup.kotlinpoet.ClassName import com.squareup.kotlinpoet.FileSpec import com.squareup.kotlinpoet.TypeName import org.ucfs.grammar.combinator.Grammar -import java.nio.file.Path /** * Common logic for generators that use a Grammar class @@ -27,8 +26,6 @@ interface IGeneratorFromGrammar { } throw GeneratorException(GeneratorException.GRAMMAR_EXPECTED) } - - fun generate(location: Path, pkg: String) } internal fun FileSpec.Builder.suppressWarningTypes(vararg types: String) { diff --git a/generator/src/main/kotlin/org/ucfs/ast/AstExtractor.kt b/generator/src/main/kotlin/org/ucfs/ast/AstExtractor.kt index f56d92f16..eb0e2c9f8 100644 --- a/generator/src/main/kotlin/org/ucfs/ast/AstExtractor.kt +++ b/generator/src/main/kotlin/org/ucfs/ast/AstExtractor.kt @@ -44,6 +44,7 @@ class AstExtractor(val pkg: String) { val ctor = nodeClass.getConstructor(Node::class.java, Int::class.java) val node: Node = ctor.newInstance(parent, getOffset(left, parent)) as Node + node.isRecovered = sppf.weight > 0 node.left = left parent.children.add(node) @@ -57,6 +58,7 @@ class AstExtractor(val pkg: String) { is TerminalSppfNode<*> -> { val node = TerminalNode(parent, getOffset(left, parent), sppf.terminal, left) + node.isRecovered = sppf.weight > 0 parent.children.add(node) parent.length += sppf.terminal.toString().length return node diff --git a/generator/src/main/kotlin/org/ucfs/ast/DotWriter.kt b/generator/src/main/kotlin/org/ucfs/ast/DotWriter.kt index 04c005db9..f023fad6c 100644 --- a/generator/src/main/kotlin/org/ucfs/ast/DotWriter.kt +++ b/generator/src/main/kotlin/org/ucfs/ast/DotWriter.kt @@ -39,7 +39,12 @@ class DotWriter { private fun getNodeView(node: Node): StringBuilder { val view = StringBuilder("\n${getId(node)} [ ${getNodeLabel(node)}") if (node is TerminalNode<*>) { - view.append(", color = green") + if(node.isRecovered) { + view.append(", color = red") + } + else{ + view.append(", color = green") + } } view.append("]") return view diff --git a/generator/src/main/kotlin/org/ucfs/ast/Node.kt b/generator/src/main/kotlin/org/ucfs/ast/Node.kt index 27dfdbdb2..9a82c34b5 100644 --- a/generator/src/main/kotlin/org/ucfs/ast/Node.kt +++ b/generator/src/main/kotlin/org/ucfs/ast/Node.kt @@ -13,4 +13,5 @@ open class Node( open var left: Node? = null var right: Node? = null var children: ArrayList = ArrayList() + var isRecovered: Boolean = false } \ No newline at end of file diff --git a/generator/src/main/kotlin/org/ucfs/ast/NodeClassesGenerator.kt b/generator/src/main/kotlin/org/ucfs/ast/NodeClassesGenerator.kt index 9521aa1ce..9e8980f8b 100644 --- a/generator/src/main/kotlin/org/ucfs/ast/NodeClassesGenerator.kt +++ b/generator/src/main/kotlin/org/ucfs/ast/NodeClassesGenerator.kt @@ -34,7 +34,7 @@ class NodeClassesGenerator(override val grammarClazz: Class<*>) : /** * Generate class for each nonterminal in grammar */ - override fun generate(location: Path, pkg: String) { + fun generate(location: Path, pkg: String) { for (nt in grammar.nonTerms) { val file = generateClassFile(nt, pkg) file.writeTo(location) diff --git a/generator/src/main/kotlin/org/ucfs/examples/dyck/DyckGrammar.kt b/generator/src/main/kotlin/org/ucfs/examples/dyck/DyckGrammar.kt index e94a65b9b..96a9ee3c9 100644 --- a/generator/src/main/kotlin/org/ucfs/examples/dyck/DyckGrammar.kt +++ b/generator/src/main/kotlin/org/ucfs/examples/dyck/DyckGrammar.kt @@ -7,16 +7,12 @@ import org.ucfs.grammar.combinator.regexp.many import org.ucfs.grammar.combinator.regexp.or class DyckGrammar : Grammar() { - var S by Nt() - var Round by Nt() - var Quadrat by Nt() - var Curly by Nt() + val S by Nt().asStart() + val Round by Nt("(" * S * ")") + val Quadrat by Nt("[" * S * "]") + val Curly by Nt("{" * S * "}") init { - setStart(S) - S = many(Round or Quadrat or Curly) - Round = "(" * S * ")" - Quadrat = "[" * S * "]" - Curly = "{" * S * "}" + S /= many(Round or Quadrat or Curly) } } diff --git a/generator/src/main/kotlin/org/ucfs/examples/golang/SimpleGolang.kt b/generator/src/main/kotlin/org/ucfs/examples/golang/SimpleGolang.kt index 967f2e169..59bb2217f 100644 --- a/generator/src/main/kotlin/org/ucfs/examples/golang/SimpleGolang.kt +++ b/generator/src/main/kotlin/org/ucfs/examples/golang/SimpleGolang.kt @@ -1,4 +1,4 @@ -package org.ucfs.examples.golang +package org.ucfs.examples.golang import org.ucfs.grammar.combinator.Grammar import org.ucfs.grammar.combinator.extension.StringExtension.or @@ -8,16 +8,8 @@ import org.ucfs.grammar.combinator.regexp.Nt import org.ucfs.grammar.combinator.regexp.or class SimpleGolang : Grammar() { - var Program by Nt() - var Block by Nt() - var Statement by Nt() - var IntExpr by Nt() - - init { - setStart(Program) - Program = Block - Block = Many(Statement) - Statement = IntExpr * ";" or "r" * IntExpr * ";" - IntExpr = "1" or "1" * "+" * "1" - } + val IntExpr by Nt("1" or "1" * "+" * "1") + val Statement by Nt(IntExpr * ";" or "r" * IntExpr * ";") + val Block by Nt(Many(Statement)) + val Program by Nt(Block).asStart() } diff --git a/generator/src/main/kotlin/org/ucfs/parser/IParserGenerator.kt b/generator/src/main/kotlin/org/ucfs/parser/AbstractParserGenerator.kt similarity index 64% rename from generator/src/main/kotlin/org/ucfs/parser/IParserGenerator.kt rename to generator/src/main/kotlin/org/ucfs/parser/AbstractParserGenerator.kt index 9a0a87e9a..7b85f170e 100644 --- a/generator/src/main/kotlin/org/ucfs/parser/IParserGenerator.kt +++ b/generator/src/main/kotlin/org/ucfs/parser/AbstractParserGenerator.kt @@ -7,8 +7,10 @@ import org.ucfs.IGeneratorFromGrammar import org.ucfs.descriptors.Descriptor import org.ucfs.grammar.combinator.Grammar import org.ucfs.grammar.combinator.regexp.Nt +import org.ucfs.input.IInputGraph import org.ucfs.input.ILabel import org.ucfs.nullable +import org.ucfs.parser.context.Context import org.ucfs.parser.context.IContext import org.ucfs.rsm.RsmState import org.ucfs.rsm.symbol.ITerminal @@ -18,25 +20,35 @@ import org.ucfs.suppressWarningTypes import java.nio.file.Path import java.util.stream.Collectors.toList -interface IParserGenerator : IGeneratorFromGrammar { - val grammar: Grammar + +abstract class AbstractParserGenerator(final override val grammarClazz: Class<*>) : IGeneratorFromGrammar { + val grammar: Grammar = buildGrammar(grammarClazz) companion object { - private const val PARSER = "Parser" + /** + * Types + */ val vertexType = TypeVariableName("VertexType") val labelType = TypeVariableName("LabelType", ILabel::class.java) val superClass = GeneratedParser::class.asTypeName().parameterizedBy(vertexType, labelType) - const val CTX_NAME = "ctx" - const val GRAMMAR_NAME = "grammar" - const val FUNCS_NAME = "ntFuncs" val descriptorType = Descriptor::class.asTypeName().parameterizedBy(vertexType) val sppfType = SppfNode::class.asTypeName().parameterizedBy(vertexType).nullable() + + /** + * Variable identifiers + */ + const val PARSER = "Parser" + const val RECOVERY = "Recovery" + const val VALUE_NAME = "value" + const val CTX_NAME = "ctx" + const val GRAMMAR_NAME = "grammar" const val DESCRIPTOR = "descriptor" const val SPPF_NODE = "curSppfNode" const val RSM_FIELD = "rsmState" + const val RSM_GRAMMAR_FIELD = "rsm" const val POS_FIELD = "inputPosition" - const val INPUT_FIELD = "input" - const val GET_NONTERMINAL = "getNonterminal" + const val INPUT_NAME = "input" + const val NONTERMINAL = "nonterm" const val GET_TERMINALS = "getTerminals" const val TERMINALS = "terminals" const val HANDLE_TERMINAL = "handleTerminal" @@ -44,26 +56,31 @@ interface IParserGenerator : IGeneratorFromGrammar { const val ID_FIELD_NAME = "id" const val POS_VAR_NAME = "pos" const val INPUT_EDGE_NAME = "inputEdge" + const val MAIN_PARSE_FUNC = "parse" + + /** + * Common methods + */ + fun getParseFunName(nonterminalName: String): String = "parse${nonterminalName}" - fun getParserClassName(grammarSimpleName: String): String { - return grammarSimpleName + PARSER - } } - /** * Generate all parser properties and methods */ - override fun generate(location: Path, pkg: String) { + fun generate(location: Path, pkg: String) { val file = getFileBuilder(pkg).build() file.writeTo(location) } + open fun getParserClassName(): String { + return grammarClazz.simpleName + PARSER + } /** * Build file builder */ - fun getFileBuilder(pkg: String): FileSpec.Builder { - val fileName = getParserClassName(grammarClazz.simpleName) + protected open fun getFileBuilder(pkg: String): FileSpec.Builder { + val fileName = getParserClassName() val parserClass = ClassName(pkg, fileName).parameterizedBy(vertexType, labelType) val parserClassBuilder = TypeSpec.classBuilder(parserClass.rawType.simpleName) @@ -71,6 +88,7 @@ interface IParserGenerator : IGeneratorFromGrammar { .addTypeVariable(labelType) .superclass(superClass) .addProperties(generateProperties()) + .addNtMapping() .addFunctions(generateParseFunctions()) val fileBuilder = FileSpec @@ -83,21 +101,26 @@ interface IParserGenerator : IGeneratorFromGrammar { return fileBuilder } + fun TypeSpec.Builder.addNtMapping(): TypeSpec.Builder { + addFunction(generateCallNtFuncs()) + return this + } + /** * Add properties in Parser class */ - fun generateProperties(): Iterable { + open fun generateProperties(): Iterable { return listOf( generateCtxProperty(), - generateGrammarProperty(grammarClazz) - ) + generateNonterminalsSpec() + - generateNtFuncsProperty() + generateGrammarProperty(grammarClazz), + generateInputProperty() + ) + generateNonterminalsSpec() } /** * Generate overriding of ctx property */ - fun generateCtxProperty(): PropertySpec { + private fun generateCtxProperty(): PropertySpec { val ctxType = IContext::class.asTypeName().parameterizedBy(vertexType, labelType) return PropertySpec.builder(CTX_NAME, ctxType, KModifier.LATEINIT, KModifier.OVERRIDE) .mutable() @@ -108,7 +131,7 @@ interface IParserGenerator : IGeneratorFromGrammar { * Generate overriding of grammar property * Anr it's initialization of corresponding @Grammar class */ - fun generateGrammarProperty(grammarClazz: Class<*>): PropertySpec { + private fun generateGrammarProperty(grammarClazz: Class<*>): PropertySpec { return PropertySpec .builder(GRAMMAR_NAME, grammarClazz, KModifier.OVERRIDE) .initializer( @@ -117,54 +140,41 @@ interface IParserGenerator : IGeneratorFromGrammar { .build() } - /** - * Generate overriding of property that map nonterminal to it's handling function. - * And initialize it. - */ - fun generateNtFuncsProperty(): PropertySpec { - val funcType = LambdaTypeName.get( - parameters = arrayOf( - ParameterSpec("descriptor", descriptorType), - ParameterSpec("sppf", sppfType.copy(nullable = true)) - ), - returnType = Unit::class.asTypeName() - ) - val mapType = HashMap::class - .asTypeName() - .parameterizedBy(Nonterminal::class.asTypeName(), funcType) - val mapInitializer = CodeBlock.builder() - .addStatement("hashMapOf(") + private fun generateCallNtFuncs(): FunSpec { + val funSpec = FunSpec.builder("callNtFuncs") + funSpec.addModifiers(KModifier.OVERRIDE) + .addParameter("nt", Nonterminal::class.asTypeName()) + .addParameter(DESCRIPTOR, descriptorType) + .addParameter(SPPF_NODE, sppfType) + .beginControlFlow("when(nt.name)", STATE_NAME, ID_FIELD_NAME) for (nt in grammar.nonTerms) { val ntName = nt.nonterm.name ?: throw GeneratorException("Unnamed nonterminal in grammar ${grammarClazz.simpleName}") - mapInitializer.addStatement("%L to ::%L,", ntName, getParseFunName(ntName)) + funSpec.addStatement("%S -> %L($DESCRIPTOR, $SPPF_NODE)", ntName, getParseFunName(ntName)) } - mapInitializer.addStatement(")") - - return PropertySpec - .builder(FUNCS_NAME, mapType, KModifier.OVERRIDE) - .initializer(mapInitializer.build()) - .build() + funSpec.endControlFlow() + return funSpec.build() } + /** * Generate Parse methods for all nonterminals */ - fun generateParseFunctions(): Iterable { + protected open fun generateParseFunctions(): Iterable { return grammar.nonTerms.map { generateParseFunction(it) } } /** * Generate Parse method for concrete nonterminal */ - fun generateParseFunction(nt: Nt): FunSpec { + private fun generateParseFunction(nt: Nt): FunSpec { val funSpec = FunSpec.builder(getParseFunName(nt.nonterm.name!!)) funSpec.addModifiers(KModifier.PRIVATE) .addParameter(DESCRIPTOR, descriptorType) .addParameter(SPPF_NODE, sppfType) .addStatement("val %L = %L.%L", STATE_NAME, DESCRIPTOR, RSM_FIELD) .addStatement("val %L = %L.%L", POS_VAR_NAME, DESCRIPTOR, POS_FIELD) - .beginControlFlow("when(%L.%L)", STATE_NAME, ID_FIELD_NAME) + .beginControlFlow("when(%L.%L)", STATE_NAME, "numId") for (state in nt.nonterm.getStates()) { generateParseForState(state, funSpec) @@ -179,7 +189,7 @@ interface IParserGenerator : IGeneratorFromGrammar { * (handle parsing for concrete state) */ fun generateParseForState(state: RsmState, funSpec: FunSpec.Builder) { - funSpec.addStatement("%S -> ", state.id) + funSpec.addStatement("%L -> ", state.numId) funSpec.beginControlFlow("") generateTerminalParsing(state, funSpec) generateNonterminalParsing(state, funSpec) @@ -189,14 +199,14 @@ interface IParserGenerator : IGeneratorFromGrammar { /** * Generate and add to funSpec method that parse all terminals edge from current state */ - fun generateTerminalParsing(state: RsmState, funSpec: FunSpec.Builder) { + private fun generateTerminalParsing(state: RsmState, funSpec: FunSpec.Builder) { if (state.terminalEdges.isNotEmpty()) { funSpec.addComment("handle terminal edges") funSpec.beginControlFlow( "for (%L in %L.%L.getEdges(%L))", INPUT_EDGE_NAME, CTX_NAME, - INPUT_FIELD, + INPUT_NAME, POS_VAR_NAME ) for (term in state.terminalEdges.keys) { @@ -209,14 +219,14 @@ interface IParserGenerator : IGeneratorFromGrammar { /** * Generate code for handle one Edge with Terminal<*> label */ - fun generateTerminalHandling(terminal: ITerminal): CodeBlock + abstract fun generateTerminalHandling(terminal: ITerminal): CodeBlock /** * Generate code for parsing all edges with Nonterminal label * from given @RsmState state */ - fun generateNonterminalParsing(state: RsmState, funSpec: FunSpec.Builder) { + private fun generateNonterminalParsing(state: RsmState, funSpec: FunSpec.Builder) { if (state.nonterminalEdges.isNotEmpty()) { funSpec.addComment("handle nonterminal edges") for (edge in state.nonterminalEdges) { @@ -237,7 +247,7 @@ interface IParserGenerator : IGeneratorFromGrammar { * Generate definition and initialization for all Nonterminals * as parser fields (with correspond nonterminal names) */ - fun generateNonterminalsSpec(): Iterable { + private fun generateNonterminalsSpec(): Iterable { return grammar.nonTerms.stream().map { generateNonterminalSpec(it) }.collect(toList()) } @@ -245,13 +255,44 @@ interface IParserGenerator : IGeneratorFromGrammar { * Generate definition and initialization for concrete Nonterminal * as parser field (with correspond nonterminal name) */ - fun generateNonterminalSpec(nt: Nt): PropertySpec { + private fun generateNonterminalSpec(nt: Nt): PropertySpec { val ntName = nt.nonterm.name!! val propertyBuilder = PropertySpec.builder(ntName, Nonterminal::class.asTypeName()) .addModifiers(KModifier.PRIVATE) - .initializer("%L.%L.%L()!!", GRAMMAR_NAME, ntName, GET_NONTERMINAL) + .initializer("%L.%L.%L", GRAMMAR_NAME, ntName, NONTERMINAL) return propertyBuilder.build() } + + protected open fun generateInputProperty(): PropertySpec { + return generateInputProperty( + Context::class.asTypeName().parameterizedBy(vertexType, labelType) + ) + } + + protected fun generateInputProperty(ctxType: ParameterizedTypeName): PropertySpec { + val inputType = IInputGraph::class.asTypeName().parameterizedBy(vertexType, labelType) + return PropertySpec.builder(INPUT_NAME, inputType, KModifier.OVERRIDE) + .mutable() + .getter( + FunSpec.getterBuilder() + .addStatement("return %L.%L", CTX_NAME, INPUT_NAME) + .build() + ) + .setter( + FunSpec.setterBuilder() + .addParameter(VALUE_NAME, inputType) + .addStatement( + "%L = %L(%L.%L, %L)", + CTX_NAME, + ctxType.rawType, + GRAMMAR_NAME, + RSM_GRAMMAR_FIELD, + VALUE_NAME + ) + .build() + ) + .build() + } } diff --git a/generator/src/main/kotlin/org/ucfs/parser/GeneratedParser.kt b/generator/src/main/kotlin/org/ucfs/parser/GeneratedParser.kt index 1c58efbac..1310d3ac8 100644 --- a/generator/src/main/kotlin/org/ucfs/parser/GeneratedParser.kt +++ b/generator/src/main/kotlin/org/ucfs/parser/GeneratedParser.kt @@ -5,38 +5,34 @@ import org.ucfs.grammar.combinator.Grammar import org.ucfs.input.Edge import org.ucfs.input.IInputGraph import org.ucfs.input.ILabel -import org.ucfs.parser.context.Context import org.ucfs.rsm.RsmState import org.ucfs.rsm.symbol.ITerminal import org.ucfs.rsm.symbol.Nonterminal import org.ucfs.sppf.node.SppfNode + abstract class GeneratedParser : IGll { abstract val grammar: Grammar - var input: IInputGraph - get() { - return ctx.input - } - set(value) { - ctx = Context(grammar.rsm, value) - } + abstract var input: IInputGraph - protected abstract val ntFuncs: HashMap, SppfNode?) -> Unit> + /** + * Processes faster than map from nonterminal to method (proved experimentally) + */ + protected abstract fun callNtFuncs( + nt: Nonterminal, + descriptor: Descriptor, + curSppfNode: SppfNode? + ): Unit override fun parse(descriptor: Descriptor) { val state = descriptor.rsmState val nt = state.nonterminal - val handleEdges = ntFuncs[nt] ?: throw ParsingException("Nonterminal ${nt.name} is absent from the grammar!") - val pos = descriptor.inputPosition - - ctx.descriptors.addToHandled(descriptor) val curSppfNode = descriptor.sppfNode val epsilonSppfNode = ctx.sppf.getEpsilonSppfNode(descriptor) - val leftExtent = curSppfNode?.leftExtent val rightExtent = curSppfNode?.rightExtent @@ -44,23 +40,19 @@ abstract class GeneratedParser : pop(descriptor.gssNode, curSppfNode ?: epsilonSppfNode, pos) } + ctx.descriptors.addToHandled(descriptor) + if (state.isStart && state.isFinal) { checkAcceptance( epsilonSppfNode, epsilonSppfNode!!.leftExtent, epsilonSppfNode!!.rightExtent, - state.nonterminal + nt ) } - checkAcceptance(curSppfNode, leftExtent, rightExtent, state.nonterminal) + checkAcceptance(curSppfNode, leftExtent, rightExtent, nt) - for (inputEdge in ctx.input.getEdges(pos)) { - if (inputEdge.label.terminal == null) { - handleTerminalOrEpsilonEdge(descriptor, curSppfNode, null, descriptor.rsmState, inputEdge.head, 0) - continue - } - } - handleEdges(descriptor, curSppfNode) + callNtFuncs(nt, descriptor, curSppfNode) } protected fun handleTerminal( @@ -71,14 +63,13 @@ abstract class GeneratedParser : curSppfNode: SppfNode? ) { - val newStates = state.terminalEdges[terminal] ?: throw ParsingException( - "State $state does not contains edges " + - "\nby terminal $terminal" + - "\naccessible edges: ${state.terminalEdges}\n" - ) - if (inputEdge.label.terminal == terminal) { + val newStates = state.terminalEdges[terminal] ?: throw ParsingException( + "State $state does not contains edges " + + "\nby terminal $terminal" + + "\naccessible edges: ${state.terminalEdges}\n" + ) for (target in newStates) { handleTerminalOrEpsilonEdge( descriptor, diff --git a/generator/src/main/kotlin/org/ucfs/parser/ParserGenerator.kt b/generator/src/main/kotlin/org/ucfs/parser/ParserGenerator.kt index 48dcc3120..d552fcec4 100644 --- a/generator/src/main/kotlin/org/ucfs/parser/ParserGenerator.kt +++ b/generator/src/main/kotlin/org/ucfs/parser/ParserGenerator.kt @@ -2,40 +2,26 @@ package org.ucfs.parser import com.squareup.kotlinpoet.CodeBlock import com.squareup.kotlinpoet.FileSpec -import org.ucfs.grammar.combinator.Grammar import org.ucfs.rsm.symbol.ITerminal -import java.nio.file.Path /** * Generator for a parser that uses a third-party lexer. * Unlike the scannerless parser , it uses scanner enumeration objects as terminals. - * @see ScanerlessParserGenerator */ -class ParserGenerator(override val grammarClazz: Class<*>, private val terminalsEnum: Class<*>) : IParserGenerator { - - init { - buildGrammar(grammarClazz) - } - +open class ParserGenerator(grammarClazz: Class<*>, private val terminalsEnum: Class<*>) : + AbstractParserGenerator(grammarClazz) { override fun generateTerminalHandling(terminal: ITerminal): CodeBlock { val terminalName = "${terminalsEnum.simpleName}.$terminal" return CodeBlock.of( - "%L(%L, %L, %L, %L, %L)", - IParserGenerator.HANDLE_TERMINAL, - terminalName, - IParserGenerator.STATE_NAME, - IParserGenerator.INPUT_EDGE_NAME, - IParserGenerator.DESCRIPTOR, - IParserGenerator.SPPF_NODE + "%L(%L, %L, %L, %L, %L)", HANDLE_TERMINAL, terminalName, STATE_NAME, INPUT_EDGE_NAME, DESCRIPTOR, SPPF_NODE ) } - private fun getFileBuilder(location: Path, pkg: String): FileSpec.Builder { + override fun getFileBuilder(pkg: String): FileSpec.Builder { val builder = super.getFileBuilder(pkg) builder.addImport(terminalsEnum.packageName, terminalsEnum.simpleName) return builder } - override val grammar: Grammar = buildGrammar(grammarClazz) } diff --git a/generator/src/main/kotlin/org/ucfs/parser/RecoveryParserGenerator.kt b/generator/src/main/kotlin/org/ucfs/parser/RecoveryParserGenerator.kt new file mode 100644 index 000000000..46d7802d8 --- /dev/null +++ b/generator/src/main/kotlin/org/ucfs/parser/RecoveryParserGenerator.kt @@ -0,0 +1,41 @@ +package org.ucfs.parser + +import com.squareup.kotlinpoet.FunSpec +import com.squareup.kotlinpoet.KModifier +import com.squareup.kotlinpoet.ParameterizedTypeName.Companion.parameterizedBy +import com.squareup.kotlinpoet.PropertySpec +import com.squareup.kotlinpoet.asTypeName +import org.ucfs.intersection.RecoveryIntersection +import org.ucfs.parser.context.RecoveryContext + +/** + * Generator for a parser with error-recovery that uses a third-party lexer. + */ +class RecoveryParserGenerator(grammarClazz: Class<*>, terminalsEnum: Class<*>) : + ParserGenerator(grammarClazz, terminalsEnum) { + companion object { + val recoveryEngineType = RecoveryIntersection::class.java.asTypeName() + const val RECOVERY_METHOD_NAME = "handleRecoveryEdges" + } + + override fun generateInputProperty(): PropertySpec { + return generateInputProperty( + RecoveryContext::class.asTypeName().parameterizedBy(vertexType, labelType) + ) + } + + override fun generateParseFunctions(): Iterable { + return super.generateParseFunctions() + generateMainLoopFunction() + } + + private fun generateMainLoopFunction(): FunSpec { + return FunSpec.builder(MAIN_PARSE_FUNC).addModifiers(KModifier.OVERRIDE).addParameter( + DESCRIPTOR, descriptorType + ).addStatement("super.%L()", MAIN_PARSE_FUNC) + .addStatement("%L.%L(this, %L)", recoveryEngineType, RECOVERY_METHOD_NAME, DESCRIPTOR).build() + } + override fun getParserClassName(): String { + return super.getParserClassName() + RECOVERY + } + +} diff --git a/generator/src/main/kotlin/org/ucfs/parser/ScanerlessParserGenerator.kt b/generator/src/main/kotlin/org/ucfs/parser/ScanerlessParserGenerator.kt index 12073173b..4e1ea5805 100644 --- a/generator/src/main/kotlin/org/ucfs/parser/ScanerlessParserGenerator.kt +++ b/generator/src/main/kotlin/org/ucfs/parser/ScanerlessParserGenerator.kt @@ -5,16 +5,13 @@ import com.squareup.kotlinpoet.KModifier import com.squareup.kotlinpoet.ParameterizedTypeName.Companion.parameterizedBy import com.squareup.kotlinpoet.PropertySpec import com.squareup.kotlinpoet.asTypeName -import org.ucfs.grammar.combinator.Grammar -import org.ucfs.parser.IParserGenerator.Companion.INPUT_EDGE_NAME import org.ucfs.rsm.symbol.ITerminal /** * Scanerless parser generator * Store @Grammar terminals as list of @Terminal<*> type */ -class ScanerlessParserGenerator(override val grammarClazz: Class<*>) : IParserGenerator { - override val grammar: Grammar = buildGrammar(grammarClazz) +class ScanerlessParserGenerator(grammarClazz: Class<*>) : AbstractParserGenerator(grammarClazz) { private val terminals: List = grammar.getTerminals().toList() override fun generateProperties(): Iterable { @@ -26,13 +23,13 @@ class ScanerlessParserGenerator(override val grammarClazz: Class<*>) : IParserGe ): CodeBlock { return CodeBlock.of( "%L(%L[%L], %L, %L, %L, %L)", - IParserGenerator.HANDLE_TERMINAL, - IParserGenerator.TERMINALS, + HANDLE_TERMINAL, + TERMINALS, terminals.indexOf(terminal), - IParserGenerator.STATE_NAME, + STATE_NAME, INPUT_EDGE_NAME, - IParserGenerator.DESCRIPTOR, - IParserGenerator.SPPF_NODE + DESCRIPTOR, + SPPF_NODE ) } @@ -41,14 +38,17 @@ class ScanerlessParserGenerator(override val grammarClazz: Class<*>) : IParserGe * filed in parser */ private fun generateTerminalsSpec(): PropertySpec { - val termListType = List::class.asTypeName() - .parameterizedBy( - ITerminal::class.asTypeName() - ) + val termListType = List::class.asTypeName().parameterizedBy( + ITerminal::class.asTypeName() + ) val propertyBuilder = - PropertySpec.builder(IParserGenerator.TERMINALS, termListType) - .addModifiers(KModifier.PRIVATE) - .initializer("%L.%L().%L()", IParserGenerator.GRAMMAR_NAME, IParserGenerator.GET_TERMINALS, "toList") + PropertySpec.builder(TERMINALS, termListType).addModifiers(KModifier.PRIVATE) + .initializer( + "%L.%L().%L()", + GRAMMAR_NAME, + GET_TERMINALS, + "toList" + ) return propertyBuilder.build() } diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 249e5832f090a2944b7473328c07c9755baa3196..e6441136f3d4ba8a0da8d277868979cfbc8ad796 100644 GIT binary patch literal 43453 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 yu?e%!_ptzGB|8GrCfu%p?(_ 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
NnX)EH+Nua)3Y(c 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 /dev/null && pwd -P ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum @@ -133,22 +131,29 @@ 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. + if ! command -v java >/dev/null 2>&1 + then + 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 fi # Increase the maximum file descriptors if we can. if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then case $MAX_FD in #( max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 MAX_FD=$( ulimit -H -n ) || warn "Could not query maximum file descriptor limit" esac case $MAX_FD in #( '' | soft) :;; #( *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 ulimit -n "$MAX_FD" || warn "Could not set maximum file descriptor limit to $MAX_FD" esac @@ -193,11 +198,15 @@ if "$cygwin" || "$msys" ; then 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. + +# 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"' + +# Collect all arguments for the java command: +# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, +# and any embedded shellness will be escaped. +# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be +# treated as '${Hostname}' itself on the command line. set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ @@ -205,6 +214,12 @@ set -- \ org.gradle.wrapper.GradleWrapperMain \ "$@" +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + # Use "xargs" to parse quoted args. # # With -n1 it outputs one arg per line, with the quotes and backslashes removed. diff --git a/gradlew.bat b/gradlew.bat index ac1b06f93..7101f8e46 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -14,7 +14,7 @@ @rem limitations under the License. @rem -@if "%DEBUG%" == "" @echo off +@if "%DEBUG%"=="" @echo off @rem ########################################################################## @rem @rem Gradle startup script for Windows @@ -25,7 +25,8 @@ if "%OS%"=="Windows_NT" setlocal set DIRNAME=%~dp0 -if "%DIRNAME%" == "" set DIRNAME=. +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @@ -40,13 +41,13 @@ if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto execute +if %ERRORLEVEL% equ 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. +echo. 1>&2 +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 goto fail @@ -56,11 +57,11 @@ 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. +echo. 1>&2 +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 goto fail @@ -75,13 +76,15 @@ set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar :end @rem End local scope for the variables with windows NT shell -if "%ERRORLEVEL%"=="0" goto mainEnd +if %ERRORLEVEL% equ 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 +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% :mainEnd if "%OS%"=="Windows_NT" endlocal diff --git a/scripts/generate_all.sh b/scripts/generate_all.sh new file mode 100755 index 000000000..2dd7e7437 --- /dev/null +++ b/scripts/generate_all.sh @@ -0,0 +1,30 @@ +#!/bin/bash +shopt -s nullglob #ingore failed patterns +rootPrj=$(pwd) +parserDest="../benchmarks/src/main/kotlin/" +antlrSrc="benchmarks/src/main/java/org/antlr" +lexerSrc="examples/src/main/java/java7" + +printf "\n\nINSTALL PACKAGES\n" +apt-get install jflex +apt-get install antlr4 + +printf "\n\nGENERATE FILES\n" + +printf "\nGenerate ANTLR4 files" +cd $antlrSrc +antlr4 Java8.g4 +cd $rootPrj + +printf "\nGenerate lexers" +cd $lexerSrc +for lexer_name in *.jflex *.jlex *.lex *.flex *.x +do + jflex $lexer_name +done +cd $rootPrj + + +printf "\nGenerate UCFS parser files at" +echo $parserDest +./gradlew :examples:run --args=$parserDest \ No newline at end of file diff --git a/scripts/run_bench.sh b/scripts/run_bench.sh new file mode 100755 index 000000000..473dccba2 --- /dev/null +++ b/scripts/run_bench.sh @@ -0,0 +1,14 @@ +#!/bin/bash +shopt -s nullglob #ingore failed patterns +rootPrj=$(pwd) + +printf "\n\nRUN BENCHMARKS\n" +mkdir -p benchmarks/logs +for dataset in #/home/olga/gllgen/java7/junit #/home/olga/gllgen/dataset_black_box/too_little +do + for tool in Recovery #Antlr Online Offline + do + echo "running $tool on $dataset, start at $(date)" + ./gradlew benchmark -PtoolName=$tool -Pdataset=$dataset >> benchmarks/logs/stdout_$tool.txt 2>> benchmarks/logs/stderr_$tool.txt + done +done diff --git a/settings.gradle.kts b/settings.gradle.kts index f244834c7..9d660d937 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -6,3 +6,4 @@ include("solver") include("benchmarks") include("generator") include("test-shared") +include("examples") diff --git a/solver/src/main/kotlin/org/ucfs/descriptors/Descriptor.kt b/solver/src/main/kotlin/org/ucfs/descriptors/Descriptor.kt index 1ec7648a1..90bc3c8dd 100644 --- a/solver/src/main/kotlin/org/ucfs/descriptors/Descriptor.kt +++ b/solver/src/main/kotlin/org/ucfs/descriptors/Descriptor.kt @@ -46,6 +46,10 @@ open class Descriptor( return true } + + override fun toString(): String { + return "Descriptor(${rsmState.nonterminal}, inputPosition=$inputPosition)" + } } diff --git a/solver/src/main/kotlin/org/ucfs/grammar/combinator/Grammar.kt b/solver/src/main/kotlin/org/ucfs/grammar/combinator/Grammar.kt index d27655f65..dc9b58020 100644 --- a/solver/src/main/kotlin/org/ucfs/grammar/combinator/Grammar.kt +++ b/solver/src/main/kotlin/org/ucfs/grammar/combinator/Grammar.kt @@ -27,15 +27,22 @@ open class Grammar { } else throw IllegalArgumentException("Only NT object can be start state for Grammar") } + fun Nt.asStart(): Nt { + if (this@Grammar::startNt.isInitialized) { + throw Exception("Nonterminal ${nonterm.name} is already initialized") + } + startNt = this + return this + } + /** * Builds a Rsm for the grammar */ private fun buildRsm(): RsmState { nonTerms.forEach { it.buildRsmBox() } - val startState = startNt.getNonterminal()?.startState //if nonterminal not initialized -- it will be checked in buildRsmBox() - return startState!! + return startNt.nonterm.startState } /** diff --git a/solver/src/main/kotlin/org/ucfs/grammar/combinator/regexp/DerivedSymbol.kt b/solver/src/main/kotlin/org/ucfs/grammar/combinator/regexp/DerivedSymbol.kt index d4b550892..cfcbe0926 100644 --- a/solver/src/main/kotlin/org/ucfs/grammar/combinator/regexp/DerivedSymbol.kt +++ b/solver/src/main/kotlin/org/ucfs/grammar/combinator/regexp/DerivedSymbol.kt @@ -1,6 +1,7 @@ package org.ucfs.grammar.combinator.regexp interface DerivedSymbol : Regexp { + override fun derive(symbol: DerivedSymbol): Regexp { return if (this == symbol) Epsilon else Empty } diff --git a/solver/src/main/kotlin/org/ucfs/grammar/combinator/regexp/Many.kt b/solver/src/main/kotlin/org/ucfs/grammar/combinator/regexp/Many.kt index e7a6bcee5..949bce2ac 100644 --- a/solver/src/main/kotlin/org/ucfs/grammar/combinator/regexp/Many.kt +++ b/solver/src/main/kotlin/org/ucfs/grammar/combinator/regexp/Many.kt @@ -20,4 +20,4 @@ fun many(some: Regexp): Many { val Regexp.many: Many get() = Many(this) -fun Some(exp: Regexp) = exp * Many(exp) \ No newline at end of file +fun some(exp: Regexp) = exp * Many(exp) \ No newline at end of file diff --git a/solver/src/main/kotlin/org/ucfs/grammar/combinator/regexp/Nt.kt b/solver/src/main/kotlin/org/ucfs/grammar/combinator/regexp/Nt.kt index f1b1dd527..a9d5f6949 100644 --- a/solver/src/main/kotlin/org/ucfs/grammar/combinator/regexp/Nt.kt +++ b/solver/src/main/kotlin/org/ucfs/grammar/combinator/regexp/Nt.kt @@ -5,35 +5,41 @@ import org.ucfs.rsm.RsmState import org.ucfs.rsm.symbol.Nonterminal import kotlin.reflect.KProperty -open class Nt : DerivedSymbol { +open class Nt() : DerivedSymbol { + private lateinit var name : String + constructor(lhs: Regexp) : this() { + rsmDescription = lhs + } + lateinit var nonterm: Nonterminal private set private lateinit var rsmDescription: Regexp fun isInitialized(): Boolean { - return ::nonterm.isInitialized + return ::rsmDescription.isInitialized } fun buildRsmBox() { + nonterm.startState = RsmState(nonterm, isStart = true, rsmDescription.acceptEpsilon()) nonterm.startState.buildRsmBox(rsmDescription) } - override fun getNonterminal(): Nonterminal? { - return nonterm - } + operator fun getValue(grammar: Grammar, property: KProperty<*>): Nt = this - operator fun setValue(grammar: Grammar, property: KProperty<*>, lrh: Regexp) { - if (!this::nonterm.isInitialized) { - nonterm = Nonterminal(property.name) - grammar.nonTerms.add(this) - rsmDescription = lrh - nonterm.startState = RsmState(nonterm, isStart = true, rsmDescription.acceptEpsilon()) - } else { - throw Exception("Nonterminal ${property.name} is already initialized") + operator fun divAssign(lhs: Regexp) { + if (isInitialized()) { + throw Exception("Nonterminal '${nonterm.name}' is already initialized") } - + rsmDescription = lhs } - operator fun getValue(grammar: Grammar, property: KProperty<*>): Regexp = this -} \ No newline at end of file + operator fun provideDelegate( + grammar: Grammar, property: KProperty<*> + ): Nt { + name = property.name + nonterm = Nonterminal(property.name) + grammar.nonTerms.add(this) + return this + } +} diff --git a/solver/src/main/kotlin/org/ucfs/grammar/combinator/regexp/Regexp.kt b/solver/src/main/kotlin/org/ucfs/grammar/combinator/regexp/Regexp.kt index 4e052892e..c4559ab09 100644 --- a/solver/src/main/kotlin/org/ucfs/grammar/combinator/regexp/Regexp.kt +++ b/solver/src/main/kotlin/org/ucfs/grammar/combinator/regexp/Regexp.kt @@ -1,14 +1,11 @@ package org.ucfs.grammar.combinator.regexp -import org.ucfs.rsm.symbol.Nonterminal - sealed interface Regexp { /* Based on Brzozowski derivative */ fun derive(symbol: DerivedSymbol): Regexp - fun getNonterminal(): Nonterminal? = null /* Does the expression accept an epsilon diff --git a/solver/src/main/kotlin/org/ucfs/gss/GssNode.kt b/solver/src/main/kotlin/org/ucfs/gss/GssNode.kt index b5b8315d8..86d74c6f3 100644 --- a/solver/src/main/kotlin/org/ucfs/gss/GssNode.kt +++ b/solver/src/main/kotlin/org/ucfs/gss/GssNode.kt @@ -45,9 +45,7 @@ class GssNode( fun addEdge(rsmState: RsmState, sppfNode: SppfNode?, gssNode: GssNode): Boolean { val label = Pair(rsmState, sppfNode) - if (!edges.containsKey(label)) edges[label] = HashSet() - - return edges.getValue(label).add(gssNode) + return edges.computeIfAbsent(label) { HashSet() }.add(gssNode) } override fun toString() = "GSSNode(nonterminal=$nonterminal, inputPosition=$inputPosition)" diff --git a/solver/src/main/kotlin/org/ucfs/input/IInputGraph.kt b/solver/src/main/kotlin/org/ucfs/input/IInputGraph.kt index 73f5fe9e1..fcf0f00ad 100644 --- a/solver/src/main/kotlin/org/ucfs/input/IInputGraph.kt +++ b/solver/src/main/kotlin/org/ucfs/input/IInputGraph.kt @@ -1,18 +1,12 @@ package org.ucfs.input -import org.ucfs.descriptors.Descriptor -import org.ucfs.parser.context.IContext -import org.ucfs.rsm.RsmState -import org.ucfs.rsm.symbol.ITerminal -import org.ucfs.rsm.symbol.Nonterminal -import org.ucfs.sppf.node.SppfNode - /** * Input graph interface * @param VertexType - type of vertex in input graph * @param LabelType - type of label on edges in input graph */ interface IInputGraph { + /** * Collection of all vertices in graph */ @@ -91,55 +85,4 @@ interface IInputGraph { */ fun isFinal(vertex: VertexType): Boolean - /** - * Process outgoing edges from input position in given descriptor, according to processing logic, represented as - * separate functions for both outgoing terminal and nonterminal edges from rsmState in descriptor - * @param handleTerminalOrEpsilonEdge - function for processing terminal and epsilon edges in RSM - * @param handleNonterminalEdge - function for processing nonterminal edges in RSM - * @param ctx - configuration of Gll parser instance - * @param descriptor - descriptor, represents current parsing stage - * @param sppfNode - root node of derivation tree, corresponds to already parsed portion of input - */ - fun handleEdges( - handleTerminalOrEpsilonEdge: ( - descriptor: Descriptor, - sppfNode: SppfNode?, - terminal: ITerminal?, - targetState: RsmState, - targetVertex: VertexType, - targetWeight: Int, - ) -> Unit, - handleNonterminalEdge: ( - descriptor: Descriptor, - nonterminal: Nonterminal, - targetStates: HashSet, - sppfNode: SppfNode? - ) -> Unit, - ctx: IContext, - descriptor: Descriptor, - sppfNode: SppfNode? - ) { - val rsmState = descriptor.rsmState - val inputPosition = descriptor.inputPosition - val terminalEdges = rsmState.terminalEdges - val nonterminalEdges = rsmState.nonterminalEdges - - for (inputEdge in ctx.input.getEdges(inputPosition)) { - if (inputEdge.label.terminal == null) { - handleTerminalOrEpsilonEdge(descriptor, sppfNode, null, descriptor.rsmState, inputEdge.head, 0) - continue - } - for ((edgeTerminal, targetStates) in terminalEdges) { - if (inputEdge.label.terminal == edgeTerminal) { - for (target in targetStates) { - handleTerminalOrEpsilonEdge(descriptor, sppfNode, edgeTerminal, target, inputEdge.head, 0) - } - } - } - } - - for ((edgeNonterminal, targetStates) in nonterminalEdges) { - handleNonterminalEdge(descriptor, edgeNonterminal, targetStates, sppfNode) - } - } } \ No newline at end of file diff --git a/solver/src/main/kotlin/org/ucfs/input/RecoveryLinearInput.kt b/solver/src/main/kotlin/org/ucfs/input/RecoveryLinearInput.kt deleted file mode 100644 index d0e7b704c..000000000 --- a/solver/src/main/kotlin/org/ucfs/input/RecoveryLinearInput.kt +++ /dev/null @@ -1,27 +0,0 @@ -package org.ucfs.input - -import org.ucfs.rsm.symbol.Term - -class RecoveryLinearInput - : LinearInput(), IRecoveryInputGraph { - companion object { - /** - * Split CharSequence into stream of strings, separated by space symbol - */ - fun buildFromString(input: String): IRecoveryInputGraph { - val inputGraph = RecoveryLinearInput() - var curVertexId = 0 - - inputGraph.addStartVertex(curVertexId) - inputGraph.addVertex(curVertexId) - - for (x in input.trim().split(' ')) { - if (x.isNotEmpty()) { - inputGraph.addEdge(curVertexId, LinearInputLabel(Term(x)), ++curVertexId) - inputGraph.addVertex(curVertexId) - } - } - return inputGraph - } - } -} \ No newline at end of file diff --git a/solver/src/main/kotlin/org/ucfs/intersection/IIntersectionEngine.kt b/solver/src/main/kotlin/org/ucfs/intersection/IIntersectionEngine.kt new file mode 100644 index 000000000..44d5b0583 --- /dev/null +++ b/solver/src/main/kotlin/org/ucfs/intersection/IIntersectionEngine.kt @@ -0,0 +1,14 @@ +package org.ucfs.intersection + +import org.ucfs.descriptors.Descriptor +import org.ucfs.input.ILabel +import org.ucfs.parser.IGll +import org.ucfs.sppf.node.SppfNode + +interface IIntersectionEngine { + fun handleEdges( + gll: IGll, + descriptor: Descriptor, + sppfNode: SppfNode? + ) +} \ No newline at end of file diff --git a/solver/src/main/kotlin/org/ucfs/intersection/IntersectionEngine.kt b/solver/src/main/kotlin/org/ucfs/intersection/IntersectionEngine.kt new file mode 100644 index 000000000..00a056bad --- /dev/null +++ b/solver/src/main/kotlin/org/ucfs/intersection/IntersectionEngine.kt @@ -0,0 +1,44 @@ +package org.ucfs.intersection + +import org.ucfs.descriptors.Descriptor +import org.ucfs.input.ILabel +import org.ucfs.parser.IGll +import org.ucfs.sppf.node.SppfNode + +object IntersectionEngine : IIntersectionEngine { + + /** + * Process outgoing edges from input position in given descriptor, according to processing logic, represented as + * separate functions for both outgoing terminal and nonterminal edges from rsmState in descriptor + * @param gll - Gll parser instance + * @param descriptor - descriptor, represents current parsing stage + * @param sppfNode - root node of derivation tree, corresponds to already parsed portion of input + */ + override fun handleEdges( + gll: IGll, + descriptor: Descriptor, + sppfNode: SppfNode? + ) { + val rsmState = descriptor.rsmState + val inputPosition = descriptor.inputPosition + val terminalEdges = rsmState.terminalEdges + val nonterminalEdges = rsmState.nonterminalEdges + for (inputEdge in gll.ctx.input.getEdges(inputPosition)) { + if (inputEdge.label.terminal == null) { + gll.handleTerminalOrEpsilonEdge(descriptor, sppfNode, null, descriptor.rsmState, inputEdge.head, 0) + continue + } + for ((edgeTerminal, targetStates) in terminalEdges) { + if (inputEdge.label.terminal == edgeTerminal) { + for (target in targetStates) { + gll.handleTerminalOrEpsilonEdge(descriptor, sppfNode, edgeTerminal, target, inputEdge.head, 0) + } + } + } + } + + for ((edgeNonterminal, targetStates) in nonterminalEdges) { + gll.handleNonterminalEdge(descriptor, edgeNonterminal, targetStates, sppfNode) + } + } +} \ No newline at end of file diff --git a/solver/src/main/kotlin/org/ucfs/input/IRecoveryInputGraph.kt b/solver/src/main/kotlin/org/ucfs/intersection/RecoveryIntersection.kt similarity index 58% rename from solver/src/main/kotlin/org/ucfs/input/IRecoveryInputGraph.kt rename to solver/src/main/kotlin/org/ucfs/intersection/RecoveryIntersection.kt index 58491f632..4741bb0af 100644 --- a/solver/src/main/kotlin/org/ucfs/input/IRecoveryInputGraph.kt +++ b/solver/src/main/kotlin/org/ucfs/intersection/RecoveryIntersection.kt @@ -1,56 +1,29 @@ -package org.ucfs.input +package org.ucfs.intersection import org.ucfs.descriptors.Descriptor -import org.ucfs.parser.context.IContext +import org.ucfs.input.Edge +import org.ucfs.input.ILabel +import org.ucfs.input.RecoveryEdge +import org.ucfs.parser.IGll import org.ucfs.rsm.RsmState import org.ucfs.rsm.symbol.ITerminal -import org.ucfs.rsm.symbol.Nonterminal import org.ucfs.sppf.node.SppfNode -/** - * Part of error recovery mechanism. - * Input graph interface with additional methods to support error recovery logic - * @param VertexType - type of vertex in input graph - * @param LabelType - type of label on edges in input graph - */ -interface IRecoveryInputGraph : IInputGraph { +object RecoveryIntersection : IIntersectionEngine{ /** * Process outgoing edges from input position in given descriptor, according to processing logic, represented as * separate functions for processing both outgoing terminal and nonterminal edges from rsmState in descriptor. * Additionally, considers error recovering edges in input graph. Those are the edges that were not present in * initial graph, but could be useful later to successfully parse input - * @param handleTerminalOrEpsilonEdge - function for processing terminal and epsilon edges in RSM - * @param handleNonterminalEdge - function for processing nonterminal edges in RSM - * @param ctx - configuration of Gll parser instance + * @param gll - Gll parser instance * @param descriptor - descriptor, represents current parsing stage * @param sppfNode - root node of derivation tree, corresponds to already parsed portion of input */ - override fun handleEdges( - handleTerminalOrEpsilonEdge: ( - curDescriptor: Descriptor, - curSppfNode: SppfNode?, - terminal: ITerminal?, - targetState: RsmState, - targetVertex: VertexType, - targetWeight: Int, - ) -> Unit, - handleNonterminalEdge: ( - descriptor: Descriptor, - nonterminal: Nonterminal, - targetStates: HashSet, - sppfNode: SppfNode? - ) -> Unit, - ctx: IContext, - descriptor: Descriptor, - sppfNode: SppfNode? + override fun handleEdges( + gll: IGll, descriptor: Descriptor, sppfNode: SppfNode? ) { - super.handleEdges(handleTerminalOrEpsilonEdge, handleNonterminalEdge, ctx, descriptor, sppfNode) - val errorRecoveryEdges = createRecoveryEdges(descriptor) - handleRecoveryEdges( - errorRecoveryEdges, - handleTerminalOrEpsilonEdge, - descriptor - ) + IntersectionEngine.handleEdges(gll, descriptor, sppfNode) + handleRecoveryEdges(gll, descriptor) } /** @@ -58,13 +31,15 @@ interface IRecoveryInputGraph : IInputGraph (destination, weight) */ - private fun createRecoveryEdges(descriptor: Descriptor): HashSet> { + private fun createRecoveryEdges( + gll: IGll, descriptor: Descriptor + ): HashSet> { val inputPosition = descriptor.inputPosition val rsmState = descriptor.rsmState val terminalEdges = rsmState.terminalEdges val errorRecoveryEdges = HashSet>() - val currentEdges = getEdges(inputPosition) + val currentEdges = gll.ctx.input.getEdges(inputPosition) if (currentEdges.isNotEmpty()) { addTerminalRecoveryEdges(terminalEdges, errorRecoveryEdges, inputPosition, rsmState, currentEdges) @@ -82,7 +57,7 @@ interface IRecoveryInputGraph : IInputGraph addEpsilonRecoveryEdges( terminalEdges: HashMap>, errorRecoveryEdges: HashSet>, inputPosition: VertexType, @@ -103,7 +78,7 @@ interface IRecoveryInputGraph : IInputGraph addTerminalRecoveryEdges( terminalEdges: HashMap>, errorRecoveryEdges: HashSet>, inputPosition: VertexType, @@ -126,29 +101,19 @@ interface IRecoveryInputGraph : IInputGraph>, - handleTerminalOrEpsilonEdge: ( - descriptor: Descriptor, - sppfNode: SppfNode?, - terminal: ITerminal?, - targetState: RsmState, - targetVertex: VertexType, - targetWeight: Int, - ) -> Unit, - descriptor: Descriptor + fun handleRecoveryEdges( + gll: IGll, descriptor: Descriptor ) { + val errorRecoveryEdges: HashSet> = createRecoveryEdges(gll, descriptor) val terminalEdges = descriptor.rsmState.terminalEdges for (errorRecoveryEdge in errorRecoveryEdges) { @@ -157,23 +122,13 @@ interface IRecoveryInputGraph : IInputGraph : IInputGraph private constructor( - override var ctx: IContext, + override var ctx: IContext, val engine: IIntersectionEngine ) : IGll { companion object { @@ -28,10 +30,9 @@ class Gll private constructor( * @return default instance of gll parser */ fun gll( - startState: RsmState, - inputGraph: IInputGraph + startState: RsmState, inputGraph: IInputGraph ): Gll { - return Gll(Context(startState, inputGraph)) + return Gll(Context(startState, inputGraph), IntersectionEngine) } /** @@ -42,10 +43,9 @@ class Gll private constructor( * @return recovery instance of gll parser */ fun recoveryGll( - startState: RsmState, - inputGraph: IRecoveryInputGraph + startState: RsmState, inputGraph: IInputGraph ): Gll { - return Gll(RecoveryContext(startState, inputGraph)) + return Gll(RecoveryContext(startState, inputGraph), RecoveryIntersection) } } @@ -78,21 +78,16 @@ class Gll private constructor( pop(descriptor.gssNode, sppfNode ?: epsilonSppfNode, pos) } - ctx.descriptors.addToHandled(descriptor) if (state.isStart && state.isFinal) { - checkAcceptance(epsilonSppfNode, epsilonSppfNode!!.leftExtent, epsilonSppfNode!!.rightExtent, state.nonterminal) + checkAcceptance( + epsilonSppfNode, epsilonSppfNode!!.leftExtent, epsilonSppfNode!!.rightExtent, state.nonterminal + ) } checkAcceptance(sppfNode, leftExtent, rightExtent, state.nonterminal) - ctx.input.handleEdges( - this::handleTerminalOrEpsilonEdge, - this::handleNonterminalEdge, - ctx, - descriptor, - sppfNode - ) + engine.handleEdges(this, descriptor, sppfNode) } } diff --git a/solver/src/main/kotlin/org/ucfs/parser/IGll.kt b/solver/src/main/kotlin/org/ucfs/parser/IGll.kt index 1f4435a78..e2b9309a4 100644 --- a/solver/src/main/kotlin/org/ucfs/parser/IGll.kt +++ b/solver/src/main/kotlin/org/ucfs/parser/IGll.kt @@ -74,14 +74,11 @@ interface IGll { weight: Int, ): GssNode { val gssNode = GssNode(nonterminal, inputPosition, weight) - - if (ctx.createdGssNodes.containsKey(gssNode)) { - if (ctx.createdGssNodes.getValue(gssNode).minWeightOfLeftPart > weight) { - ctx.createdGssNodes.getValue(gssNode).minWeightOfLeftPart = weight - } - } else ctx.createdGssNodes[gssNode] = gssNode - - return ctx.createdGssNodes.getValue(gssNode) + val storedNode = ctx.createdGssNodes.computeIfAbsent(gssNode) { gssNode } + if (storedNode.minWeightOfLeftPart > weight) { + storedNode.minWeightOfLeftPart = weight + } + return storedNode } /** @@ -99,8 +96,9 @@ interface IGll { sppfNode: SppfNode?, inputPosition: VertexType, ): GssNode { - val newNode = - getOrCreateGssNode(nonterminal, inputPosition, weight = gssNode.minWeightOfLeftPart + (sppfNode?.weight ?: 0)) + val newNode = getOrCreateGssNode( + nonterminal, inputPosition, weight = gssNode.minWeightOfLeftPart + (sppfNode?.weight ?: 0) + ) if (newNode.addEdge(rsmState, sppfNode, gssNode)) { if (ctx.poppedGssNodes.containsKey(newNode)) { @@ -154,15 +152,11 @@ interface IGll { * @param nonterminal - nonterminal, which defines language we check belonging to */ fun checkAcceptance( - sppfNode: SppfNode?, - leftExtent: VertexType?, - rightExtent: VertexType?, - nonterminal: Nonterminal + sppfNode: SppfNode?, leftExtent: VertexType?, rightExtent: VertexType?, nonterminal: Nonterminal ) { - if (sppfNode is SymbolSppfNode - && nonterminal == ctx.startState.nonterminal - && ctx.input.isStart(leftExtent!!) - && ctx.input.isFinal(rightExtent!!) + if (sppfNode is SymbolSppfNode && nonterminal == ctx.startState.nonterminal && ctx.input.isStart( + leftExtent!! + ) && ctx.input.isFinal(rightExtent!!) ) { if (ctx.parseResult == null || ctx.parseResult!!.weight > sppfNode.weight) { ctx.parseResult = sppfNode @@ -172,12 +166,11 @@ interface IGll { val pair = Pair(leftExtent, rightExtent) val distance = ctx.sppf.minDistance(sppfNode) - ctx.reachabilityPairs[pair] = - if (ctx.reachabilityPairs.containsKey(pair)) { - minOf(distance, ctx.reachabilityPairs[pair]!!) - } else { - distance - } + ctx.reachabilityPairs[pair] = if (ctx.reachabilityPairs.containsKey(pair)) { + minOf(distance, ctx.reachabilityPairs[pair]!!) + } else { + distance + } } } diff --git a/solver/src/main/kotlin/org/ucfs/parser/context/Context.kt b/solver/src/main/kotlin/org/ucfs/parser/context/Context.kt index dbd7a163c..6498b5539 100644 --- a/solver/src/main/kotlin/org/ucfs/parser/context/Context.kt +++ b/solver/src/main/kotlin/org/ucfs/parser/context/Context.kt @@ -14,8 +14,7 @@ import org.ucfs.sppf.node.SppfNode * @param LabelType - type of label on edges in input graph */ class Context( - override val startState: RsmState, - override val input: IInputGraph + override val startState: RsmState, override val input: IInputGraph ) : IContext { override val descriptors: DescriptorsStorage = DescriptorsStorage() override val sppf: Sppf = Sppf() diff --git a/solver/src/main/kotlin/org/ucfs/parser/context/IContext.kt b/solver/src/main/kotlin/org/ucfs/parser/context/IContext.kt index d622f1f03..821a047f3 100644 --- a/solver/src/main/kotlin/org/ucfs/parser/context/IContext.kt +++ b/solver/src/main/kotlin/org/ucfs/parser/context/IContext.kt @@ -73,8 +73,9 @@ interface IContext { val leftExtent = sppfNode?.leftExtent val rightExtent = sppfNode?.rightExtent - if (parseResult == null && sppfNode is SymbolSppfNode<*> && state.nonterminal == startState.nonterminal && - input.isStart(leftExtent!!) && input.isFinal(rightExtent!!) + if (parseResult == null && sppfNode is SymbolSppfNode<*> && state.nonterminal == startState.nonterminal && input.isStart( + leftExtent!! + ) && input.isFinal(rightExtent!!) ) { descriptors.removeFromHandled(descriptor) } diff --git a/solver/src/main/kotlin/org/ucfs/parser/context/RecoveryContext.kt b/solver/src/main/kotlin/org/ucfs/parser/context/RecoveryContext.kt index e965ea025..d4b77bd36 100644 --- a/solver/src/main/kotlin/org/ucfs/parser/context/RecoveryContext.kt +++ b/solver/src/main/kotlin/org/ucfs/parser/context/RecoveryContext.kt @@ -3,8 +3,8 @@ package org.ucfs.parser.context import org.ucfs.descriptors.Descriptor import org.ucfs.descriptors.RecoveringDescriptorsStorage import org.ucfs.gss.GssNode +import org.ucfs.input.IInputGraph import org.ucfs.input.ILabel -import org.ucfs.input.IRecoveryInputGraph import org.ucfs.rsm.RsmState import org.ucfs.sppf.RecoverySppf import org.ucfs.sppf.node.SppfNode @@ -15,8 +15,7 @@ import org.ucfs.sppf.node.SppfNode * @param LabelType - type of label on edges in input graph */ class RecoveryContext( - override val startState: RsmState, - override val input: IRecoveryInputGraph + override val startState: RsmState, override val input: IInputGraph ) : IContext { override val descriptors: RecoveringDescriptorsStorage = RecoveringDescriptorsStorage() override val sppf: RecoverySppf = RecoverySppf() diff --git a/solver/src/main/kotlin/org/ucfs/rsm/RsmState.kt b/solver/src/main/kotlin/org/ucfs/rsm/RsmState.kt index a9f57f516..a3e219e17 100644 --- a/solver/src/main/kotlin/org/ucfs/rsm/RsmState.kt +++ b/solver/src/main/kotlin/org/ucfs/rsm/RsmState.kt @@ -13,16 +13,8 @@ open class RsmState( val isStart: Boolean = false, val isFinal: Boolean = false, ) { - val id: String = getId(nonterminal) - - companion object { - private val counters = HashMap() - private fun getId(nt: Nonterminal): String { - val id = counters.getOrPut(nt) { 0 } - counters[nt] = id + 1 - return "${nt.name}_${(id)}" - } - } + val numId: Int = nonterminal.getNextRsmStateId() + val id: String = "${nonterminal.name}_${(numId)}" val outgoingEdges get() = terminalEdges.plus(nonterminalEdges) diff --git a/solver/src/main/kotlin/org/ucfs/rsm/symbol/Nonterminal.kt b/solver/src/main/kotlin/org/ucfs/rsm/symbol/Nonterminal.kt index 895806e16..c68da6e16 100644 --- a/solver/src/main/kotlin/org/ucfs/rsm/symbol/Nonterminal.kt +++ b/solver/src/main/kotlin/org/ucfs/rsm/symbol/Nonterminal.kt @@ -3,10 +3,17 @@ package org.ucfs.rsm.symbol import org.ucfs.rsm.RsmState import java.util.* -class Nonterminal(val name: String?) : Symbol { +data class Nonterminal(val name: String?) : Symbol { lateinit var startState: RsmState + private var rsmStateLastId = 0 override fun toString() = "Nonterminal(${name ?: this.hashCode()})" + fun getNextRsmStateId(): Int { + val id = rsmStateLastId + rsmStateLastId++ + return id + } + /** * Get all states from RSM for current nonterminal */ diff --git a/solver/src/test/kotlin/rsm/api/TerminalsEqualsTest.kt b/solver/src/test/kotlin/rsm/api/TerminalsEqualsTest.kt index 7e7a4ea23..7965bd6e5 100644 --- a/solver/src/test/kotlin/rsm/api/TerminalsEqualsTest.kt +++ b/solver/src/test/kotlin/rsm/api/TerminalsEqualsTest.kt @@ -3,29 +3,27 @@ package rsm.api import org.junit.jupiter.api.Test import org.ucfs.grammar.combinator.Grammar import org.ucfs.grammar.combinator.regexp.Nt -import org.ucfs.rsm.symbol.Term import org.ucfs.grammar.combinator.regexp.or import org.ucfs.grammar.combinator.regexp.times +import org.ucfs.rsm.symbol.Term import rsm.RsmTest import kotlin.test.assertTrue class TerminalsEqualsTest : RsmTest { class AStarTerms : Grammar() { - var S by Nt() + val S by Nt().asStart() init { - setStart(S) - S = Term("a") or Term("a") * S or S * S + S /= Term("a") or Term("a") * S or S * S } } class AStar : Grammar() { - var S by Nt() + val S by Nt().asStart() val A = Term("a") init { - setStart(S) - S = A or A * S or S * S + S /= A or A * S or S * S } } diff --git a/solver/src/test/kotlin/rsm/builder/AStarTest.kt b/solver/src/test/kotlin/rsm/builder/AStarTest.kt index fecf6799e..0805e2aa8 100644 --- a/solver/src/test/kotlin/rsm/builder/AStarTest.kt +++ b/solver/src/test/kotlin/rsm/builder/AStarTest.kt @@ -3,27 +3,26 @@ package rsm.builder import org.junit.jupiter.api.Test import org.ucfs.grammar.combinator.Grammar import org.ucfs.grammar.combinator.regexp.Nt -import org.ucfs.rsm.symbol.Term import org.ucfs.grammar.combinator.regexp.or import org.ucfs.grammar.combinator.regexp.times +import org.ucfs.rsm.symbol.Term import rsm.RsmTest import kotlin.test.assertNotNull import kotlin.test.assertTrue class AStarTest : RsmTest { class AStar : Grammar() { - var S by Nt() + val S by Nt().asStart() init { - setStart(S) - S = Term("a") or Term("a") * S or S * S + S /= Term("a") or Term("a") * S or S * S } } @Test fun testRsm() { val grammar = AStar() - assertNotNull(grammar.S.getNonterminal()) + assertNotNull(grammar.S.nonterm) assertTrue { equalsByNtName(getAStarRsm("S"), grammar.rsm) } } } \ No newline at end of file diff --git a/test-shared/src/test/kotlin/parser/generated/RuntimeCompiler.kt b/test-shared/src/test/kotlin/parser/generated/RuntimeCompiler.kt index 97808077c..084dbd068 100644 --- a/test-shared/src/test/kotlin/parser/generated/RuntimeCompiler.kt +++ b/test-shared/src/test/kotlin/parser/generated/RuntimeCompiler.kt @@ -5,7 +5,6 @@ import com.tschuchort.compiletesting.SourceFile import org.ucfs.GeneratorException import org.ucfs.input.LinearInputLabel import org.ucfs.parser.GeneratedParser -import org.ucfs.parser.IParserGenerator import org.ucfs.parser.ParserGenerator import org.ucfs.parser.ScanerlessParserGenerator import parser.generated.GllGeneratedTest.Companion.DSL_FILE_NAME @@ -38,20 +37,21 @@ object RuntimeCompiler { @Suppress("UNCHECKED_CAST") fun loadScanerlessParser(grammarFolderFile: File): Class<*> { val grammarName = grammarFolderFile.name - val parserName = IParserGenerator.getParserClassName(SCANERLESS_DSL_FILE_NAME) + //val parserName = ScanerlessParserGenerator().getParserClassName(SCANERLESS_DSL_FILE_NAME) - fun generateParserCode(): KotlinCompilation.Result { + fun generateParserCode(): Pair { val grammar = getKtSource(grammarFolderFile, SCANERLESS_DSL_FILE_NAME) val compilationResult = compileClasses(listOf(grammar)) val classLoader = compilationResult.classLoader val grammarClass = classLoader.loadFromGrammar(SCANERLESS_DSL_FILE_NAME, grammarName) - ScanerlessParserGenerator(grammarClass).generate(parsersFolder, getParserPkg(grammarName)) - return compilationResult + val generator = ScanerlessParserGenerator(grammarClass) + generator.generate(parsersFolder, getParserPkg(grammarName)) + return Pair(compilationResult, generator.getParserClassName()) } - var compilationResult = generateParserCode() + var (compilationResult, parserName) = generateParserCode() val parser = getKtSource(generationPath.resolve(grammarName).toFile(), parserName) compilationResult = compileClasses( @@ -76,9 +76,8 @@ object RuntimeCompiler { @Suppress("UNCHECKED_CAST") fun loadParser(grammarFolderFile: File): ParsingClasses { val grammarName = grammarFolderFile.name - val parserName = IParserGenerator.getParserClassName(DSL_FILE_NAME) - fun generateParserCode(): KotlinCompilation.Result { + fun generateParserCode(): Pair { val token = getKtSource(grammarFolderFile, TOKENS) val grammar = getKtSource(grammarFolderFile, DSL_FILE_NAME) val compilationResult = compileClasses(listOf(token, grammar)) @@ -87,11 +86,12 @@ object RuntimeCompiler { val grammarClass = classLoader.loadFromGrammar(DSL_FILE_NAME, grammarName) val tokenClass = classLoader.loadFromGrammar(TOKENS, grammarName) - ParserGenerator(grammarClass, tokenClass).generate(parsersFolder, getParserPkg(grammarName)) - return compilationResult + val generator = ParserGenerator(grammarClass, tokenClass) + generator.generate(parsersFolder, getParserPkg(grammarName)) + return Pair(compilationResult, generator.getParserClassName()) } - var compilationResult = generateParserCode() + var (compilationResult, parserName) = generateParserCode() val lexer = getKtSource(grammarFolderFile, LEXER_NAME) val parser = getKtSource(generationPath.resolve(grammarName).toFile(), parserName) @@ -131,7 +131,7 @@ object RuntimeCompiler { /** * Compile all files for given sources */ - fun compileClasses(sourceFiles: List, classpath: List = emptyList()): KotlinCompilation.Result { + private fun compileClasses(sourceFiles: List, classpath: List = emptyList()): KotlinCompilation.Result { val compileResult = KotlinCompilation().apply { sources = sourceFiles //use application classpath diff --git a/test-shared/src/test/resources/grammars/a/ScanerlessGrammarDsl.kt b/test-shared/src/test/resources/grammars/a/ScanerlessGrammarDsl.kt index 4f571948e..cbdcb0490 100644 --- a/test-shared/src/test/resources/grammars/a/ScanerlessGrammarDsl.kt +++ b/test-shared/src/test/resources/grammars/a/ScanerlessGrammarDsl.kt @@ -5,10 +5,5 @@ import org.ucfs.grammar.combinator.regexp.Nt import org.ucfs.rsm.symbol.Term class ScanerlessGrammarDsl : Grammar() { - var S by Nt() - - init { - setStart(S) - S = Term("a") - } + val S by Nt(Term("a")).asStart() } \ No newline at end of file diff --git a/test-shared/src/test/resources/grammars/aBStar/ScanerlessGrammarDsl.kt b/test-shared/src/test/resources/grammars/aBStar/ScanerlessGrammarDsl.kt index 001837da3..d2b31d29b 100644 --- a/test-shared/src/test/resources/grammars/aBStar/ScanerlessGrammarDsl.kt +++ b/test-shared/src/test/resources/grammars/aBStar/ScanerlessGrammarDsl.kt @@ -5,11 +5,5 @@ import org.ucfs.grammar.combinator.extension.StringExtension.many import org.ucfs.grammar.combinator.regexp.Nt class ScanerlessGrammarDsl : Grammar() { - var S by Nt() - - init { - setStart(S) - S = many("ab") - } - + val S by Nt(many("ab")).asStart() } \ No newline at end of file diff --git a/test-shared/src/test/resources/grammars/aStar/ScanerlessGrammarDsl.kt b/test-shared/src/test/resources/grammars/aStar/ScanerlessGrammarDsl.kt index 34bcb8295..d90138d27 100644 --- a/test-shared/src/test/resources/grammars/aStar/ScanerlessGrammarDsl.kt +++ b/test-shared/src/test/resources/grammars/aStar/ScanerlessGrammarDsl.kt @@ -5,10 +5,5 @@ import org.ucfs.grammar.combinator.extension.StringExtension.many import org.ucfs.grammar.combinator.regexp.Nt class ScanerlessGrammarDsl : Grammar() { - var S by Nt() - - init { - setStart(S) - S = many("a") - } + val S by Nt(many("a")).asStart() } \ No newline at end of file diff --git a/test-shared/src/test/resources/grammars/ab/ScanerlessGrammarDsl.kt b/test-shared/src/test/resources/grammars/ab/ScanerlessGrammarDsl.kt index 65470f834..c58ef9e75 100644 --- a/test-shared/src/test/resources/grammars/ab/ScanerlessGrammarDsl.kt +++ b/test-shared/src/test/resources/grammars/ab/ScanerlessGrammarDsl.kt @@ -4,11 +4,6 @@ import org.ucfs.grammar.combinator.Grammar import org.ucfs.grammar.combinator.extension.StringExtension.times import org.ucfs.grammar.combinator.regexp.Nt -class ScanerlessGrammarDsl: Grammar() { - var S by Nt() - - init { - setStart(S) - S = "a" * "b" - } +class ScanerlessGrammarDsl : Grammar() { + val S by Nt("a" * "b").asStart() } \ No newline at end of file diff --git a/test-shared/src/test/resources/grammars/abc/ScanerlessGrammarDsl.kt b/test-shared/src/test/resources/grammars/abc/ScanerlessGrammarDsl.kt index 5ed08add0..89e5fc4cc 100644 --- a/test-shared/src/test/resources/grammars/abc/ScanerlessGrammarDsl.kt +++ b/test-shared/src/test/resources/grammars/abc/ScanerlessGrammarDsl.kt @@ -6,14 +6,7 @@ import org.ucfs.grammar.combinator.regexp.* import org.ucfs.rsm.symbol.Term class ScanerlessGrammarDsl: Grammar() { - var S by Nt() - var A by Nt() - var B by Nt() - - init { - setStart(S) - S = "a" * B * "c" or A * "c" - A = "a" * "b" - B = Term("b") - } + val A by Nt("a" * "b") + val B by Nt(Term("b")) + val S by Nt("a" * B * "c" or A * "c").asStart() } \ No newline at end of file diff --git a/test-shared/src/test/resources/grammars/ambiguous/ScanerlessGrammarDsl.kt b/test-shared/src/test/resources/grammars/ambiguous/ScanerlessGrammarDsl.kt index 0620486c1..f1a5994af 100644 --- a/test-shared/src/test/resources/grammars/ambiguous/ScanerlessGrammarDsl.kt +++ b/test-shared/src/test/resources/grammars/ambiguous/ScanerlessGrammarDsl.kt @@ -5,10 +5,9 @@ import org.ucfs.grammar.combinator.extension.StringExtension.or import org.ucfs.grammar.combinator.regexp.* class ScanerlessGrammarDsl: Grammar() { - var S by Nt() + val S by Nt().asStart() init { - setStart(S) - S = "a" or S or S * S or S * S * S + S /= "a" or S or S * S or S * S * S } } \ No newline at end of file diff --git a/test-shared/src/test/resources/grammars/bracket_star_x/ScanerlessGrammarDsl.kt b/test-shared/src/test/resources/grammars/bracket_star_x/ScanerlessGrammarDsl.kt index 1f58819e3..61cd06766 100644 --- a/test-shared/src/test/resources/grammars/bracket_star_x/ScanerlessGrammarDsl.kt +++ b/test-shared/src/test/resources/grammars/bracket_star_x/ScanerlessGrammarDsl.kt @@ -6,12 +6,10 @@ import org.ucfs.grammar.combinator.extension.StringExtension.times import org.ucfs.grammar.combinator.regexp.Nt class ScanerlessGrammarDsl : Grammar() { - var List by Nt() - var Elem by Nt() + val List by Nt().asStart() + val Elem by Nt("x" or List) init { - setStart(List) - List = "[" * Elem - Elem = "x" or List + List /= "[" * Elem } } \ No newline at end of file diff --git a/test-shared/src/test/resources/grammars/cAPlusBStar/ScanerlessGrammarDsl.kt b/test-shared/src/test/resources/grammars/cAPlusBStar/ScanerlessGrammarDsl.kt index df87254c2..b322316ec 100644 --- a/test-shared/src/test/resources/grammars/cAPlusBStar/ScanerlessGrammarDsl.kt +++ b/test-shared/src/test/resources/grammars/cAPlusBStar/ScanerlessGrammarDsl.kt @@ -1,15 +1,12 @@ package grammars.cAPlusBStar import org.ucfs.grammar.combinator.Grammar -import org.ucfs.grammar.combinator.regexp.* +import org.ucfs.grammar.combinator.regexp.many +import org.ucfs.grammar.combinator.regexp.Nt +import org.ucfs.grammar.combinator.regexp.some +import org.ucfs.grammar.combinator.regexp.times import org.ucfs.rsm.symbol.Term class ScanerlessGrammarDsl : Grammar() { - var S by Nt() - - init { - setStart(S) - S = Term("c") * Some(Term("a")) * Many(Term("b")) - } - + val S by Nt(Term("c") * some(Term("a")) * many(Term("b"))).asStart() } \ No newline at end of file diff --git a/test-shared/src/test/resources/grammars/c_a_star_b_star/ScanerlessGrammarDsl.kt b/test-shared/src/test/resources/grammars/c_a_star_b_star/ScanerlessGrammarDsl.kt index 9d159c4c5..389baa6f6 100644 --- a/test-shared/src/test/resources/grammars/c_a_star_b_star/ScanerlessGrammarDsl.kt +++ b/test-shared/src/test/resources/grammars/c_a_star_b_star/ScanerlessGrammarDsl.kt @@ -3,15 +3,10 @@ package grammars.c_a_star_b_star import org.ucfs.grammar.combinator.Grammar import org.ucfs.grammar.combinator.extension.StringExtension.many import org.ucfs.grammar.combinator.extension.StringExtension.times -import org.ucfs.grammar.combinator.regexp.times import org.ucfs.grammar.combinator.regexp.Nt +import org.ucfs.grammar.combinator.regexp.times -class ScanerlessGrammarDsl: Grammar() { - var S by Nt() - - init { - setStart(S) - S = "c" * many("a") * many("b") - } +class ScanerlessGrammarDsl : Grammar() { + val S by Nt("c" * many("a") * many("b")).asStart() } \ No newline at end of file diff --git a/test-shared/src/test/resources/grammars/dyck/ScanerlessGrammarDsl.kt b/test-shared/src/test/resources/grammars/dyck/ScanerlessGrammarDsl.kt index a355ebd66..31ec62d11 100644 --- a/test-shared/src/test/resources/grammars/dyck/ScanerlessGrammarDsl.kt +++ b/test-shared/src/test/resources/grammars/dyck/ScanerlessGrammarDsl.kt @@ -5,10 +5,9 @@ import org.ucfs.grammar.combinator.extension.StringExtension.times import org.ucfs.grammar.combinator.regexp.* class ScanerlessGrammarDsl: Grammar() { - var S by Nt() + val S by Nt().asStart() init { - setStart(S) - S = Epsilon or "(" * S * ")" * S + S /= Epsilon or "(" * S * ")" * S } } \ No newline at end of file diff --git a/test-shared/src/test/resources/grammars/g1/ScanerlessGrammarDsl.kt b/test-shared/src/test/resources/grammars/g1/ScanerlessGrammarDsl.kt index ed27f613f..81c88b793 100644 --- a/test-shared/src/test/resources/grammars/g1/ScanerlessGrammarDsl.kt +++ b/test-shared/src/test/resources/grammars/g1/ScanerlessGrammarDsl.kt @@ -2,14 +2,15 @@ package grammars.g1 import org.ucfs.grammar.combinator.Grammar import org.ucfs.grammar.combinator.extension.StringExtension.times -import org.ucfs.grammar.combinator.regexp.* +import org.ucfs.grammar.combinator.regexp.Nt +import org.ucfs.grammar.combinator.regexp.Option +import org.ucfs.grammar.combinator.regexp.or -class ScanerlessGrammarDsl: Grammar() { - var S by Nt() +class ScanerlessGrammarDsl : Grammar() { + val S by Nt().asStart() init { - setStart(S) - S = "subClassOf_r" * Option(S) * "subClassOf" or + S /= "subClassOf_r" * Option(S) * "subClassOf" or "type_r" * Option(S) * "type" } } \ No newline at end of file diff --git a/test-shared/src/test/resources/grammars/g2/ScanerlessGrammarDsl.kt b/test-shared/src/test/resources/grammars/g2/ScanerlessGrammarDsl.kt index e3a974b90..6c95899c3 100644 --- a/test-shared/src/test/resources/grammars/g2/ScanerlessGrammarDsl.kt +++ b/test-shared/src/test/resources/grammars/g2/ScanerlessGrammarDsl.kt @@ -3,13 +3,12 @@ package grammars.g2 import org.ucfs.grammar.combinator.Grammar import org.ucfs.grammar.combinator.extension.StringExtension.or import org.ucfs.grammar.combinator.extension.StringExtension.times -import org.ucfs.grammar.combinator.regexp.* +import org.ucfs.grammar.combinator.regexp.Nt -class ScanerlessGrammarDsl: Grammar() { - var S by Nt() +class ScanerlessGrammarDsl : Grammar() { + val S by Nt().asStart() init { - setStart(S) - S = "subClassOf" or "subClassOf_r" * S * "subClassOf" + S /= "subClassOf" or "subClassOf_r" * S * "subClassOf" } } \ No newline at end of file diff --git a/test-shared/src/test/resources/grammars/geo/ScanerlessGrammarDsl.kt b/test-shared/src/test/resources/grammars/geo/ScanerlessGrammarDsl.kt index 5f8cf2632..081d96493 100644 --- a/test-shared/src/test/resources/grammars/geo/ScanerlessGrammarDsl.kt +++ b/test-shared/src/test/resources/grammars/geo/ScanerlessGrammarDsl.kt @@ -2,13 +2,13 @@ package grammars.geo import org.ucfs.grammar.combinator.Grammar import org.ucfs.grammar.combinator.extension.StringExtension.times -import org.ucfs.grammar.combinator.regexp.* +import org.ucfs.grammar.combinator.regexp.Nt +import org.ucfs.grammar.combinator.regexp.Option -class ScanerlessGrammarDsl: Grammar() { - var S by Nt() +class ScanerlessGrammarDsl : Grammar() { + val S by Nt().asStart() init { - setStart(S) - S = "broaderTransitive" * Option(S) * "broaderTransitive_r" + S /= "broaderTransitive" * Option(S) * "broaderTransitive_r" } } \ No newline at end of file diff --git a/test-shared/src/test/resources/grammars/multi_dyck/ScanerlessGrammarDsl.kt b/test-shared/src/test/resources/grammars/multi_dyck/ScanerlessGrammarDsl.kt index 7075dbb05..c071badd4 100644 --- a/test-shared/src/test/resources/grammars/multi_dyck/ScanerlessGrammarDsl.kt +++ b/test-shared/src/test/resources/grammars/multi_dyck/ScanerlessGrammarDsl.kt @@ -5,16 +5,12 @@ import org.ucfs.grammar.combinator.extension.StringExtension.times import org.ucfs.grammar.combinator.regexp.* class ScanerlessGrammarDsl: Grammar() { - var S by Nt() - var S1 by Nt() - var S2 by Nt() - var S3 by Nt() + val S by Nt().asStart() + val S1 by Nt("(" * S * ")" * S) + val S2 by Nt("{" * S * "}" * S) + val S3 by Nt("[" * S * "]" * S) init { - setStart(S) - S = Epsilon or S1 or S2 or S3 - S1 = "(" * S * ")" * S - S2 = "{" * S * "}" * S - S3 = "[" * S * "]" * S + S /= Epsilon or S1 or S2 or S3 } } \ No newline at end of file diff --git a/test-shared/src/test/resources/grammars/simple_golang/ScanerlessGrammarDsl.kt b/test-shared/src/test/resources/grammars/simple_golang/ScanerlessGrammarDsl.kt index fb61ca6b2..2d12dfd8a 100644 --- a/test-shared/src/test/resources/grammars/simple_golang/ScanerlessGrammarDsl.kt +++ b/test-shared/src/test/resources/grammars/simple_golang/ScanerlessGrammarDsl.kt @@ -3,19 +3,13 @@ package grammars.simple_golang import org.ucfs.grammar.combinator.Grammar import org.ucfs.grammar.combinator.extension.StringExtension.or import org.ucfs.grammar.combinator.extension.StringExtension.times -import org.ucfs.grammar.combinator.regexp.* +import org.ucfs.grammar.combinator.regexp.Many +import org.ucfs.grammar.combinator.regexp.Nt +import org.ucfs.grammar.combinator.regexp.or -class ScanerlessGrammarDsl: Grammar() { - var Program by Nt() - var Block by Nt() - var Statement by Nt() - var IntExpr by Nt() - - init { - setStart(Program) - Program = Block - Block = Many(Statement) - Statement = IntExpr * ";" or "r" * IntExpr * ";" - IntExpr = "1" or "1" * "+" * "1" - } +class ScanerlessGrammarDsl : Grammar() { + val IntExpr by Nt("1" or "1" * "+" * "1") + val Statement by Nt(IntExpr * ";" or "r" * IntExpr * ";") + val Block by Nt(Many(Statement)) + val Program by Nt(Block).asStart() } \ No newline at end of file