From 4b3f4f4f00bb899b659d52cf9a1aa5b624f8b7c2 Mon Sep 17 00:00:00 2001 From: Olga Bachishe Date: Fri, 31 May 2024 18:06:14 +0300 Subject: [PATCH] improve offline performance (replace overriding to generation) --- .gitignore | 1 - benchmarks/src/main/kotlin/org/Performance.kt | 403 ------------------ .../src/main/kotlin/org/RecoveryOfflineGll.kt | 2 +- .../src/main/kotlin/org/SimpleOfflineGll.kt | 2 +- .../ucfs/parser/AbstractParserGenerator.kt | 76 ++-- .../kotlin/org/ucfs/parser/GeneratedParser.kt | 37 +- .../kotlin/org/ucfs/parser/ParserGenerator.kt | 9 +- .../ucfs/parser/RecoveryParserGenerator.kt | 11 +- .../ucfs/parser/ScanerlessParserGenerator.kt | 17 +- .../parser/generated/IOfflineGllTest.kt | 4 +- .../generated/ScanerlessGllGeneratedTest.kt | 2 +- 11 files changed, 68 insertions(+), 496 deletions(-) delete mode 100644 benchmarks/src/main/kotlin/org/Performance.kt diff --git a/.gitignore b/.gitignore index 8f13912fc..d849c2e27 100644 --- a/.gitignore +++ b/.gitignore @@ -91,5 +91,4 @@ bin/ /benchmarks/src/main/kotlin/org/ucfs/* /benchmarks/src/main/java/org/ucfs/* /benchmarks/logs/ -/examples/src/main/java/java7/JavaLexer.java /examples/src/main/java/java8/JavaLexer.java diff --git a/benchmarks/src/main/kotlin/org/Performance.kt b/benchmarks/src/main/kotlin/org/Performance.kt deleted file mode 100644 index 9d886c027..000000000 --- a/benchmarks/src/main/kotlin/org/Performance.kt +++ /dev/null @@ -1,403 +0,0 @@ -package org - -import org.ucfs.input.LinearInputLabel -import org.ucfs.sppf.node.SppfNode - -class Performance {} -val code = - """package org.junit.experimental.categories; - -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.util.Collections; -import java.util.HashSet; -import java.util.Set; - -import org.junit.runner.Description; -import org.junit.runner.manipulation.Filter; -import org.junit.runner.manipulation.NoTestsRemainException; -import org.junit.runners.Suite; -import org.junit.runners.model.InitializationError; -import org.junit.runners.model.RunnerBuilder; - -/** - * From a given set of test classes, runs only the classes and methods that are - * annotated with either the category given with the @IncludeCategory - * annotation, or a subtype of that category. - *

- * Note that, for now, annotating suites with {@code @Category} has no effect. - * Categories must be annotated on the direct method or class. - *

- * Example: - *

- * public interface FastTests {
- * }
- *
- * public interface SlowTests {
- * }
- *
- * public interface SmokeTests
- * }
- *
- * public static class A {
- *     @Test
- *     public void a() {
- *         fail();
- *     }
- *
- *     @Category(SlowTests.class)
- *     @Test
- *     public void b() {
- *     }
- *
- *     @Category({FastTests.class, SmokeTests.class})
- *     @Test
- *     public void c() {
- *     }
- * }
- *
- * @Category({SlowTests.class, FastTests.class})
- * public static class B {
- *     @Test
- *     public void d() {
- *     }
- * }
- *
- * @RunWith(Categories.class)
- * @IncludeCategory(SlowTests.class)
- * @SuiteClasses({A.class, B.class})
- * // Note that Categories is a kind of Suite
- * public static class SlowTestSuite {
- *     // Will run A.b and B.d, but not A.a and A.c
- * }
- * 
- *

- * Example to run multiple categories: - *

- * @RunWith(Categories.class)
- * @IncludeCategory({FastTests.class, SmokeTests.class})
- * @SuiteClasses({A.class, B.class})
- * public static class FastOrSmokeTestSuite {
- *     // Will run A.c and B.d, but not A.b because it is not any of FastTests or SmokeTests
- * }
- * 
- * - * @version 4.12 - * @see Categories at JUnit wiki - */ -public class Categories extends Suite { - - @Retention(RetentionPolicy.RUNTIME) - public @interface IncludeCategory { - /** - * Determines the tests to run that are annotated with categories specified in - * the value of this annotation or their subtypes unless excluded with {@link ExcludeCategory}. - */ - public Class[] value() default {}; - - /** - * If true, runs tests annotated with any of the categories in - * {@link IncludeCategory#value()}. Otherwise, runs tests only if annotated with all of the categories. - */ - public boolean matchAny() default true; - } - - @Retention(RetentionPolicy.RUNTIME) - public @interface ExcludeCategory { - /** - * Determines the tests which do not run if they are annotated with categories specified in the - * value of this annotation or their subtypes regardless of being included in {@link IncludeCategory#value()}. - */ - public Class[] value() default {}; - - /** - * If true, the tests annotated with any of the categories in {@link ExcludeCategory#value()} - * do not run. Otherwise, the tests do not run if and only if annotated with all categories. - */ - public boolean matchAny() default true; - } - - public static class CategoryFilter extends Filter { - private final Set> included; - private final Set> excluded; - private final boolean includedAny; - private final boolean excludedAny; - - public static CategoryFilter include(boolean matchAny, Class... categories) { - if (hasNull(categories)) { - throw new NullPointerException("has null category"); - } - return categoryFilter(matchAny, createSet(categories), true, null); - } - - public static CategoryFilter include(Class category) { - return include(true, category); - } - - public static CategoryFilter include(Class... categories) { - return include(true, categories); - } - - public static CategoryFilter exclude(boolean matchAny, Class... categories) { - if (hasNull(categories)) { - throw new NullPointerException("has null category"); - } - return categoryFilter(true, null, matchAny, createSet(categories)); - } - - public static CategoryFilter exclude(Class category) { - return exclude(true, category); - } - - public static CategoryFilter exclude(Class... categories) { - return exclude(true, categories); - } - - public static CategoryFilter categoryFilter(boolean matchAnyInclusions, Set> inclusions, - boolean matchAnyExclusions, Set> exclusions) { - return new CategoryFilter(matchAnyInclusions, inclusions, matchAnyExclusions, exclusions); - } - - protected CategoryFilter(boolean matchAnyIncludes, Set> includes, - boolean matchAnyExcludes, Set> excludes) { - includedAny = matchAnyIncludes; - excludedAny = matchAnyExcludes; - included = copyAndRefine(includes); - excluded = copyAndRefine(excludes); - } - - /** - * @see #toString() - */ - @Override - public String describe() { - return toString(); - } - - /** - * Returns string in the form "[included categories] - [excluded categories]", where both - * sets have comma separated names of categories. - * - * @return string representation for the relative complement of excluded categories set - * in the set of included categories. Examples: - *
    - *
  • "categories [all]" for all included categories and no excluded ones; - *
  • "categories [all] - [A, B]" for all included categories and given excluded ones; - *
  • "categories [A, B] - [C, D]" for given included categories and given excluded ones. - *
- * @see Class#toString() name of category - */ - @Override public String toString() { - StringBuilder description= new StringBuilder("categories ") - .append(included.isEmpty() ? "[all]" : included); - if (!excluded.isEmpty()) { - description.append(" - ").append(excluded); - } - return description.toString(); - } - - @Override - public boolean shouldRun(Description description) { - if (hasCorrectCategoryAnnotation(description)) { - return true; - } - - for (Description each : description.getChildren()) { - if (shouldRun(each)) { - return true; - } - } - - return false; - } - - private boolean hasCorrectCategoryAnnotation(Description description) { - final Set> childCategories= categories(description); - - // If a child has no categories, immediately return. - if (childCategories.isEmpty()) { - return included.isEmpty(); - } - - if (!excluded.isEmpty()) { - if (excludedAny) { - if (matchesAnyParentCategories(childCategories, excluded)) { - return false; - } - } else { - if (matchesAllParentCategories(childCategories, excluded)) { - return false; - } - } - } - - if (included.isEmpty()) { - // Couldn't be excluded, and with no suite's included categories treated as should run. - return true; - } else { - if (includedAny) { - return matchesAnyParentCategories(childCategories, included); - } else { - return matchesAllParentCategories(childCategories, included); - } - } - } - - /** - * @return true if at least one (any) parent category match a child, otherwise false. - * If empty parentCategories, returns false. - */ - private boolean matchesAnyParentCategories(Set> childCategories, Set> parentCategories) { - for (Class parentCategory : parentCategories) { - if (hasAssignableTo(childCategories, parentCategory)) { - return true; - } - } - return false; - } - - /** - * @return false if at least one parent category does not match children, otherwise true. - * If empty parentCategories, returns true. - */ - private boolean matchesAllParentCategories(Set> childCategories, Set> parentCategories) { - for (Class parentCategory : parentCategories) { - if (!hasAssignableTo(childCategories, parentCategory)) { - return false; - } - } - return true; - } - - private static Set> categories(Description description) { - Set> categories= new HashSet>(); - Collections.addAll(categories, directCategories(description)); - Collections.addAll(categories, directCategories(parentDescription(description))); - return categories; - } - - private static Description parentDescription(Description description) { - Class testClass= description.getTestClass(); - return testClass == null ? null : Description.createSuiteDescription(testClass); - } - - private static Class[] directCategories(Description description) { - if (description == null) { - return new Class[0]; - } - - Category annotation= description.getAnnotation(Category.class); - return annotation == null ? new Class[0] : annotation.value(); - } - - private static Set> copyAndRefine(Set> classes) { - HashSet> c= new HashSet>(); - if (classes != null) { - c.addAll(classes); - } - c.remove(null); - return c; - } - - private static boolean hasNull(Class... classes) { - if (classes == null) return false; - for (Class clazz : classes) { - if (clazz == null) { - return true; - } - } - return false; - } - } - - public Categories(Class klass, RunnerBuilder builder) throws InitializationError { - super(klass, builder); - try { - Set> included= getIncludedCategory(klass); - Set> excluded= getExcludedCategory(klass); - boolean isAnyIncluded= isAnyIncluded(klass); - boolean isAnyExcluded= isAnyExcluded(klass); - - filter(CategoryFilter.categoryFilter(isAnyIncluded, included, isAnyExcluded, excluded)); - } catch (NoTestsRemainException e) { - throw new InitializationError(e); - } - assertNoCategorizedDescendentsOfUncategorizeableParents(getDescription()); - } - - private static Set> getIncludedCategory(Class klass) { - IncludeCategory annotation= klass.getAnnotation(IncludeCategory.class); - return createSet(annotation == null ? null : annotation.value()); - } - - private static boolean isAnyIncluded(Class klass) { - IncludeCategory annotation= klass.getAnnotation(IncludeCategory.class); - return annotation == null || annotation.matchAny(); - } - - private static Set> getExcludedCategory(Class klass) { - ExcludeCategory annotation= klass.getAnnotation(ExcludeCategory.class); - return createSet(annotation == null ? null : annotation.value()); - } - - private static boolean isAnyExcluded(Class klass) { - ExcludeCategory annotation= klass.getAnnotation(ExcludeCategory.class); - return annotation == null || annotation.matchAny(); - } - - private static void assertNoCategorizedDescendentsOfUncategorizeableParents(Description description) throws InitializationError { - if (!canHaveCategorizedChildren(description)) { - assertNoDescendantsHaveCategoryAnnotations(description); - } - for (Description each : description.getChildren()) { - assertNoCategorizedDescendentsOfUncategorizeableParents(each); - } - } - - private static void assertNoDescendantsHaveCategoryAnnotations(Description description) throws InitializationError { - for (Description each : description.getChildren()) { - if (each.getAnnotation(Category.class) != null) { - throw new InitializationError("Category annotations on Parameterized classes are not supported on individual methods."); - } - assertNoDescendantsHaveCategoryAnnotations(each); - } - } - - // If children have names like [0], our current magical category code can't determine their parentage. - private static boolean canHaveCategorizedChildren(Description description) { - for (Description each : description.getChildren()) { - if (each.getTestClass() == null) { - return false; - } - } - return true; - } - - private static boolean hasAssignableTo(Set> assigns, Class to) { - for (final Class from : assigns) { - if (to.isAssignableFrom(from)) { - return true; - } - } - return false; - } - - private static Set> createSet(Class... t) { - final Set> set= new HashSet>(); - if (t != null) { - Collections.addAll(set, t); - } - return set; - } -} -""" -fun main() { - for (i in 0..2_000) - parse(code) -} - -fun parse(code: String): SppfNode? { - val parser = org.ucfs.Java8Parser() - parser.setInput(getTokenStream(code)) - return parser.parse().first -} \ No newline at end of file diff --git a/benchmarks/src/main/kotlin/org/RecoveryOfflineGll.kt b/benchmarks/src/main/kotlin/org/RecoveryOfflineGll.kt index e54060649..0d2fdd3f7 100644 --- a/benchmarks/src/main/kotlin/org/RecoveryOfflineGll.kt +++ b/benchmarks/src/main/kotlin/org/RecoveryOfflineGll.kt @@ -9,7 +9,7 @@ class RecoveryOfflineGll : BaseBench() { @Benchmark fun measureGll(blackhole: Blackhole) { val parser = org.ucfs.Java8ParserRecovery() - parser.input = getTokenStream(fileContents) + parser.setInput(getTokenStream(fileContents)) blackhole.consume(parser.parse()) } } diff --git a/benchmarks/src/main/kotlin/org/SimpleOfflineGll.kt b/benchmarks/src/main/kotlin/org/SimpleOfflineGll.kt index 2d46407e8..b4de9cd26 100644 --- a/benchmarks/src/main/kotlin/org/SimpleOfflineGll.kt +++ b/benchmarks/src/main/kotlin/org/SimpleOfflineGll.kt @@ -10,7 +10,7 @@ class SimpleOfflineGll : BaseBench() { @Benchmark fun measureGll(blackhole: Blackhole) { val parser = org.ucfs.Java8Parser() - parser.input = getTokenStream(fileContents) + parser.setInput(getTokenStream(fileContents)) blackhole.consume(parser.parse()) } } diff --git a/generator/src/main/kotlin/org/ucfs/parser/AbstractParserGenerator.kt b/generator/src/main/kotlin/org/ucfs/parser/AbstractParserGenerator.kt index 7b85f170e..8089e4d29 100644 --- a/generator/src/main/kotlin/org/ucfs/parser/AbstractParserGenerator.kt +++ b/generator/src/main/kotlin/org/ucfs/parser/AbstractParserGenerator.kt @@ -76,6 +76,7 @@ abstract class AbstractParserGenerator(final override val grammarClazz: Class<*> open fun getParserClassName(): String { return grammarClazz.simpleName + PARSER } + /** * Build file builder */ @@ -89,7 +90,7 @@ abstract class AbstractParserGenerator(final override val grammarClazz: Class<*> .superclass(superClass) .addProperties(generateProperties()) .addNtMapping() - .addFunctions(generateParseFunctions()) + .addFunctions(generateMethods()) val fileBuilder = FileSpec .builder(pkg, parserClass.rawType.simpleName) @@ -111,9 +112,8 @@ abstract class AbstractParserGenerator(final override val grammarClazz: Class<*> */ open fun generateProperties(): Iterable { return listOf( - generateCtxProperty(), + // generateCtxProperty(), generateGrammarProperty(grammarClazz), - generateInputProperty() ) + generateNonterminalsSpec() } @@ -133,7 +133,7 @@ abstract class AbstractParserGenerator(final override val grammarClazz: Class<*> */ private fun generateGrammarProperty(grammarClazz: Class<*>): PropertySpec { return PropertySpec - .builder(GRAMMAR_NAME, grammarClazz, KModifier.OVERRIDE) + .builder(GRAMMAR_NAME, grammarClazz) .initializer( CodeBlock.of("${grammarClazz.simpleName}()") ) @@ -156,6 +156,9 @@ abstract class AbstractParserGenerator(final override val grammarClazz: Class<*> return funSpec.build() } + private fun generateMethods(): Iterable { + return generateParseFunctions() + generateInputSetter() + } /** * Generate Parse methods for all nonterminals @@ -168,15 +171,20 @@ abstract class AbstractParserGenerator(final override val grammarClazz: Class<*> * Generate Parse method for concrete nonterminal */ private fun generateParseFunction(nt: Nt): FunSpec { + val states = nt.nonterm.getStates() 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, "numId") - for (state in nt.nonterm.getStates()) { + if (states.any { state -> state.terminalEdges.isNotEmpty() }) { + funSpec.addStatement("val %L = %L.%L", POS_VAR_NAME, DESCRIPTOR, POS_FIELD) + } + + funSpec.beginControlFlow("when(%L.%L)", STATE_NAME, "numId") + + for (state in states.sortedBy { it.numId }) { generateParseForState(state, funSpec) } @@ -209,18 +217,22 @@ abstract class AbstractParserGenerator(final override val grammarClazz: Class<*> INPUT_NAME, POS_VAR_NAME ) + + funSpec.beginControlFlow("when(%L.label.terminal)", INPUT_EDGE_NAME) for (term in state.terminalEdges.keys) { - funSpec.addStatement(generateTerminalHandling(term).toString()) + val terminalName = getTerminalName(term) + funSpec.addStatement("%L -> ", terminalName) + funSpec.addStatement("%L(%L, %L, %L, %L, %L)", HANDLE_TERMINAL, terminalName, + STATE_NAME, INPUT_EDGE_NAME, DESCRIPTOR, SPPF_NODE) } + funSpec.addStatement("else -> {}") + funSpec.endControlFlow() + funSpec.endControlFlow() } } - /** - * Generate code for handle one Edge with Terminal<*> label - */ - abstract fun generateTerminalHandling(terminal: ITerminal): CodeBlock - + abstract fun getTerminalName(terminal: ITerminal): String /** * Generate code for parsing all edges with Nonterminal label @@ -264,33 +276,23 @@ abstract class AbstractParserGenerator(final override val grammarClazz: Class<*> return propertyBuilder.build() } - protected open fun generateInputProperty(): PropertySpec { - return generateInputProperty( - Context::class.asTypeName().parameterizedBy(vertexType, labelType) - ) + protected open fun getContextType(): ParameterizedTypeName { + return Context::class.asTypeName().parameterizedBy(vertexType, labelType) } - protected fun generateInputProperty(ctxType: ParameterizedTypeName): PropertySpec { + private fun generateInputSetter(): FunSpec { + val ctxType = getContextType() 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() + return FunSpec.builder("setInput") + .addModifiers(KModifier.OVERRIDE) + .addParameter(VALUE_NAME, inputType) + .addStatement( + "%L = %L(%L.%L, %L)", + CTX_NAME, + ctxType.rawType, + GRAMMAR_NAME, + RSM_GRAMMAR_FIELD, + VALUE_NAME ) .build() } diff --git a/generator/src/main/kotlin/org/ucfs/parser/GeneratedParser.kt b/generator/src/main/kotlin/org/ucfs/parser/GeneratedParser.kt index 1310d3ac8..8fd160aba 100644 --- a/generator/src/main/kotlin/org/ucfs/parser/GeneratedParser.kt +++ b/generator/src/main/kotlin/org/ucfs/parser/GeneratedParser.kt @@ -1,21 +1,21 @@ package org.ucfs.parser import org.ucfs.descriptors.Descriptor -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.IContext import org.ucfs.rsm.RsmState import org.ucfs.rsm.symbol.ITerminal import org.ucfs.rsm.symbol.Nonterminal import org.ucfs.sppf.node.SppfNode - +/** + * If overriding field uses -- 1.2 % longer parser operation (due to hashset initialisation) + */ abstract class GeneratedParser : IGll { - abstract val grammar: Grammar - - abstract var input: IInputGraph + override lateinit var ctx: IContext /** * Processes faster than map from nonterminal to method (proved experimentally) @@ -62,24 +62,17 @@ abstract class GeneratedParser : descriptor: Descriptor, curSppfNode: SppfNode? ) { - - - 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 state.terminalEdges[terminal] ?: emptyList()) { + handleTerminalOrEpsilonEdge( + descriptor, + curSppfNode, + terminal, + target, + inputEdge.head, + 0 ) - for (target in newStates) { - handleTerminalOrEpsilonEdge( - descriptor, - curSppfNode, - terminal, - target, - inputEdge.head, - 0 - ) - } } } + + abstract fun setInput(input: IInputGraph) } \ No newline at end of file diff --git a/generator/src/main/kotlin/org/ucfs/parser/ParserGenerator.kt b/generator/src/main/kotlin/org/ucfs/parser/ParserGenerator.kt index d552fcec4..adda63a87 100644 --- a/generator/src/main/kotlin/org/ucfs/parser/ParserGenerator.kt +++ b/generator/src/main/kotlin/org/ucfs/parser/ParserGenerator.kt @@ -1,6 +1,5 @@ package org.ucfs.parser -import com.squareup.kotlinpoet.CodeBlock import com.squareup.kotlinpoet.FileSpec import org.ucfs.rsm.symbol.ITerminal @@ -10,12 +9,10 @@ import org.ucfs.rsm.symbol.ITerminal */ 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)", HANDLE_TERMINAL, terminalName, STATE_NAME, INPUT_EDGE_NAME, DESCRIPTOR, SPPF_NODE - ) + + override fun getTerminalName(terminal: ITerminal): String { + return "${terminalsEnum.simpleName}.$terminal" } override fun getFileBuilder(pkg: String): FileSpec.Builder { diff --git a/generator/src/main/kotlin/org/ucfs/parser/RecoveryParserGenerator.kt b/generator/src/main/kotlin/org/ucfs/parser/RecoveryParserGenerator.kt index 46d7802d8..fccc413a6 100644 --- a/generator/src/main/kotlin/org/ucfs/parser/RecoveryParserGenerator.kt +++ b/generator/src/main/kotlin/org/ucfs/parser/RecoveryParserGenerator.kt @@ -1,10 +1,7 @@ package org.ucfs.parser -import com.squareup.kotlinpoet.FunSpec -import com.squareup.kotlinpoet.KModifier +import com.squareup.kotlinpoet.* 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 @@ -18,10 +15,8 @@ class RecoveryParserGenerator(grammarClazz: Class<*>, terminalsEnum: Class<*>) : const val RECOVERY_METHOD_NAME = "handleRecoveryEdges" } - override fun generateInputProperty(): PropertySpec { - return generateInputProperty( - RecoveryContext::class.asTypeName().parameterizedBy(vertexType, labelType) - ) + override fun getContextType(): ParameterizedTypeName { + return RecoveryContext::class.asTypeName().parameterizedBy(vertexType, labelType) } override fun generateParseFunctions(): Iterable { diff --git a/generator/src/main/kotlin/org/ucfs/parser/ScanerlessParserGenerator.kt b/generator/src/main/kotlin/org/ucfs/parser/ScanerlessParserGenerator.kt index 4e1ea5805..7db03b47d 100644 --- a/generator/src/main/kotlin/org/ucfs/parser/ScanerlessParserGenerator.kt +++ b/generator/src/main/kotlin/org/ucfs/parser/ScanerlessParserGenerator.kt @@ -1,6 +1,5 @@ package org.ucfs.parser -import com.squareup.kotlinpoet.CodeBlock import com.squareup.kotlinpoet.KModifier import com.squareup.kotlinpoet.ParameterizedTypeName.Companion.parameterizedBy import com.squareup.kotlinpoet.PropertySpec @@ -18,21 +17,11 @@ class ScanerlessParserGenerator(grammarClazz: Class<*>) : AbstractParserGenerato return super.generateProperties() + generateTerminalsSpec() } - override fun generateTerminalHandling( - terminal: ITerminal, - ): CodeBlock { - return CodeBlock.of( - "%L(%L[%L], %L, %L, %L, %L)", - HANDLE_TERMINAL, - TERMINALS, - terminals.indexOf(terminal), - STATE_NAME, - INPUT_EDGE_NAME, - DESCRIPTOR, - SPPF_NODE - ) + override fun getTerminalName(terminal: ITerminal): String { + return "$TERMINALS[${terminals.indexOf(terminal)}]" } + /** * Generate definition and initialization for Terminals as * filed in parser diff --git a/test-shared/src/test/kotlin/parser/generated/IOfflineGllTest.kt b/test-shared/src/test/kotlin/parser/generated/IOfflineGllTest.kt index 19d83b50f..026b6c256 100644 --- a/test-shared/src/test/kotlin/parser/generated/IOfflineGllTest.kt +++ b/test-shared/src/test/kotlin/parser/generated/IOfflineGllTest.kt @@ -20,7 +20,7 @@ interface IOfflineGllTest : IDynamicGllTest { input: IInputGraph ): DynamicNode { return DynamicTest.dynamicTest("[fail] $caseName") { - gll.input = input + gll.setInput(input) val result = gll.parse().first Assertions.assertNull(result) } @@ -36,7 +36,7 @@ interface IOfflineGllTest : IDynamicGllTest { input: IInputGraph ): DynamicNode { return DynamicTest.dynamicTest("[ok] $caseName") { - gll.input = input + gll.setInput(input) val result = gll.parse() if (result.first == null) { System.err.println("input: $input") diff --git a/test-shared/src/test/kotlin/parser/generated/ScanerlessGllGeneratedTest.kt b/test-shared/src/test/kotlin/parser/generated/ScanerlessGllGeneratedTest.kt index 093da8444..fc556a7fb 100644 --- a/test-shared/src/test/kotlin/parser/generated/ScanerlessGllGeneratedTest.kt +++ b/test-shared/src/test/kotlin/parser/generated/ScanerlessGllGeneratedTest.kt @@ -52,7 +52,7 @@ class ScanerlessGllGeneratedTest : IOfflineGllTest { gll: GeneratedParser ): DynamicNode { return DynamicTest.dynamicTest("[ok] $caseName") { - gll.input = LinearInput.buildFromString(input) + gll.setInput(LinearInput.buildFromString(input)) val result = gll.parse().first assertNotNull(result) assertEquals(input.replace(SPACE, ""), buildStringFromSppf(result))