Skip to content

Commit

Permalink
add mapping as function in generator
Browse files Browse the repository at this point in the history
  • Loading branch information
bachish committed May 9, 2024
1 parent 67f2650 commit a6c72a6
Show file tree
Hide file tree
Showing 8 changed files with 243 additions and 31 deletions.
15 changes: 11 additions & 4 deletions benchmarks/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@

plugins {
java
kotlin("jvm") version "1.9.20"
Expand Down Expand Up @@ -40,22 +41,28 @@ fun getArgs(): Array<String>{
benchmark {
configurations {
named("main"){
param("fileName", "BaseTestRunner.java")
param("fileName", *getArgs())
this.reportFormat = "csv"
iterations = 10
iterations = 15
iterationTime = 2000
iterationTimeUnit = "ms"
warmups = 15
warmups = 5
outputTimeUnit = "ms"
mode = "avgt"
// include(".*Online.*")
val tools = "toolName"
if(hasProperty(tools)){
println("Run benchmarks for: .*${property(tools)}.*")
include(".*${property(tools)}.*")
}
}
}
targets {
register("main")
}

}


allOpen {
annotation("org.openjdk.jmh.annotations.State")
}
Expand Down
19 changes: 19 additions & 0 deletions benchmarks/src/main/resources/RealSystem.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package org.junit.internal;

import java.io.PrintStream;

public class RealSystem implements JUnitSystem {

/**
* Will be removed in the next major release
*/
@Deprecated
public void exit(int code) {
System.exit(code);
}

public PrintStream out() {
return System.out;
}

}
25 changes: 25 additions & 0 deletions benchmarks/src/main/resources/SortingRequest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package org.junit.internal.requests;

import java.util.Comparator;

import org.junit.runner.Description;
import org.junit.runner.Request;
import org.junit.runner.Runner;
import org.junit.runner.manipulation.Sorter;

public class SortingRequest extends Request {
private final Request request;
private final Comparator<Description> comparator;

public SortingRequest(Request request, Comparator<Description> comparator) {
this.request = request;
this.comparator = comparator;
}

@Override
public Runner getRunner() {
Runner runner = request.getRunner();
new Sorter(comparator).apply(runner);
return runner;
}
}
24 changes: 24 additions & 0 deletions benchmarks/src/main/resources/SuiteMethodBuilder.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package org.junit.internal.builders;

import org.junit.internal.runners.SuiteMethod;
import org.junit.runner.Runner;
import org.junit.runners.model.RunnerBuilder;

public class SuiteMethodBuilder extends RunnerBuilder {
@Override
public Runner runnerForClass(Class<?> each) throws Throwable {
if (hasSuiteMethod(each)) {
return new SuiteMethod(each);
}
return null;
}

public boolean hasSuiteMethod(Class<?> testClass) {
try {
testClass.getMethod("suite");
} catch (NoSuchMethodException e) {
return false;
}
return true;
}
}
101 changes: 101 additions & 0 deletions benchmarks/src/main/resources/TextListener.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
package org.junit.internal;

import java.io.PrintStream;
import java.text.NumberFormat;
import java.util.List;

import org.junit.runner.Description;
import org.junit.runner.Result;
import org.junit.runner.notification.Failure;
import org.junit.runner.notification.RunListener;

public class TextListener extends RunListener {

private final PrintStream writer;

public TextListener(JUnitSystem system) {
this(system.out());
}

public TextListener(PrintStream writer) {
this.writer = writer;
}

@Override
public void testRunFinished(Result result) {
printHeader(result.getRunTime());
printFailures(result);
printFooter(result);
}

@Override
public void testStarted(Description description) {
writer.append('.');
}

@Override
public void testFailure(Failure failure) {
writer.append('E');
}

@Override
public void testIgnored(Description description) {
writer.append('I');
}

/*
* Internal methods
*/

private PrintStream getWriter() {
return writer;
}

protected void printHeader(long runTime) {
getWriter().println();
getWriter().println("Time: " + elapsedTimeAsString(runTime));
}

protected void printFailures(Result result) {
List<Failure> failures = result.getFailures();
if (failures.size() == 0) {
return;
}
if (failures.size() == 1) {
getWriter().println("There was " + failures.size() + " failure:");
} else {
getWriter().println("There were " + failures.size() + " failures:");
}
int i = 1;
for (Failure each : failures) {
printFailure(each, "" + i++);
}
}

protected void printFailure(Failure each, String prefix) {
getWriter().println(prefix + ") " + each.getTestHeader());
getWriter().print(each.getTrace());
}

protected void printFooter(Result result) {
if (result.wasSuccessful()) {
getWriter().println();
getWriter().print("OK");
getWriter().println(" (" + result.getRunCount() + " test" + (result.getRunCount() == 1 ? "" : "s") + ")");

} else {
getWriter().println();
getWriter().println("FAILURES!!!");
getWriter().println("Tests run: " + result.getRunCount() + ", Failures: " + result.getFailureCount());
}
getWriter().println();
}

/**
* Returns the formatted string of the elapsed time. Duplicated from
* BaseTestRunner. Fix it.
*/
protected String elapsedTimeAsString(long runTime) {
return NumberFormat.getInstance().format((double) runTime / 1000);
}
}
40 changes: 22 additions & 18 deletions generator/src/main/kotlin/org/ucfs/parser/GeneratedParser.kt
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,18 @@ abstract class GeneratedParser<VertexType, LabelType : ILabel> :
ctx = Context(grammar.rsm, value)
}

protected abstract val ntFuncs: HashMap<Nonterminal, (Descriptor<VertexType>, SppfNode<VertexType>?) -> Unit>
//protected abstract val ntFuncs: HashMap<String, (Descriptor<VertexType>, SppfNode<VertexType>?) -> Unit>
protected abstract fun callNtFuncs(
nt: Nonterminal,
descriptor: Descriptor<VertexType>,
curSppfNode: SppfNode<VertexType>?
): Unit

override fun parse(descriptor: Descriptor<VertexType>) {
val state = descriptor.rsmState
val nt = state.nonterminal

val handleEdges = ntFuncs[nt] ?: throw ParsingException("Nonterminal ${nt.name} is absent from the grammar!")
// val handleEdges = ntFuncs[nt] ?: throw ParsingException("Nonterminal ${nt.name} is absent from the grammar!")

val pos = descriptor.inputPosition

Expand All @@ -49,18 +54,18 @@ abstract class GeneratedParser<VertexType, LabelType : ILabel> :
epsilonSppfNode,
epsilonSppfNode!!.leftExtent,
epsilonSppfNode!!.rightExtent,
state.nonterminal
nt
)
}
checkAcceptance(curSppfNode, leftExtent, rightExtent, state.nonterminal)

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)
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)
// }
// }
callNtFuncs(nt, descriptor, curSppfNode)
// ntFuncs[nt.name]!!(descriptor, curSppfNode)
}

protected fun handleTerminal(
Expand All @@ -71,14 +76,13 @@ abstract class GeneratedParser<VertexType, LabelType : ILabel> :
curSppfNode: SppfNode<VertexType>?
) {

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,
Expand Down
43 changes: 37 additions & 6 deletions generator/src/main/kotlin/org/ucfs/parser/IParserGenerator.kt
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,12 @@ import java.util.stream.Collectors.toList
interface IParserGenerator : IGeneratorFromGrammar {
val grammar: Grammar

/**
* Define a way to store relation between nonterminal
* and their parsing method
*/
fun mappingAsFunction(): Boolean = true

companion object {
private const val PARSER = "Parser"
val vertexType = TypeVariableName("VertexType")
Expand Down Expand Up @@ -71,6 +77,7 @@ interface IParserGenerator : IGeneratorFromGrammar {
.addTypeVariable(labelType)
.superclass(superClass)
.addProperties(generateProperties())
.addNtMapping()
.addFunctions(generateParseFunctions())

val fileBuilder = FileSpec
Expand All @@ -83,15 +90,23 @@ interface IParserGenerator : IGeneratorFromGrammar {
return fileBuilder
}

fun TypeSpec.Builder.addNtMapping(): TypeSpec.Builder {
if (mappingAsFunction()) {
addFunction(generateCallNtFuncs())
} else {
addProperty(generateNtFuncsProperty())
}
return this
}

/**
* Add properties in Parser class
*/
fun generateProperties(): Iterable<PropertySpec> {
return listOf(
generateCtxProperty(),
generateGrammarProperty(grammarClazz)
) + generateNonterminalsSpec() +
generateNtFuncsProperty()
) + generateNonterminalsSpec()
}

/**
Expand All @@ -117,6 +132,22 @@ interface IParserGenerator : IGeneratorFromGrammar {
.build()
}

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}")
funSpec.addStatement("%S -> %L($DESCRIPTOR, $SPPF_NODE)", ntName, getParseFunName(ntName))
}
funSpec.endControlFlow()
return funSpec.build()
}

/**
* Generate overriding of property that map nonterminal to it's handling function.
* And initialize it.
Expand All @@ -131,13 +162,13 @@ interface IParserGenerator : IGeneratorFromGrammar {
)
val mapType = HashMap::class
.asTypeName()
.parameterizedBy(Nonterminal::class.asTypeName(), funcType)
.parameterizedBy(String::class.asTypeName(), funcType)
val mapInitializer = CodeBlock.builder()
.addStatement("hashMapOf(")
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))
mapInitializer.addStatement("%S to ::%L,", ntName, getParseFunName(ntName))
}
mapInitializer.addStatement(")")

Expand All @@ -164,7 +195,7 @@ interface IParserGenerator : IGeneratorFromGrammar {
.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)
Expand All @@ -179,7 +210,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)
Expand Down
Loading

0 comments on commit a6c72a6

Please sign in to comment.