Skip to content

Commit

Permalink
CLEANUP: Dry up codegen, remove needless RubyArray usage, ensure cons…
Browse files Browse the repository at this point in the history
…ecutive numbering of generated classes

Fixes elastic#9312
  • Loading branch information
original-brownbear committed Apr 2, 2018
1 parent 99be638 commit 43f37ad
Show file tree
Hide file tree
Showing 5 changed files with 176 additions and 210 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -14,18 +14,6 @@ final class ClassFields {

private final Collection<Closure> afterInit = new ArrayList<>();

/**
* Add a field of given type that is initialized by the given {@link SyntaxElement} that will
* be executed in the class body.
* Renders as e.g. {@code private final Ruby field5 = RubyUtil.RUBY}.
* @param type Type of the field
* @param initializer Syntax to initialize it in-line.
* @return The field's syntax element that can be used in method bodies
*/
public ValueSyntaxElement add(final Class<?> type, final SyntaxElement initializer) {
return addField(FieldDefinition.withInitializer(definitions.size(), type, initializer));
}

/**
* Adds a field holding the given {@link Object}.
* @param obj Object to add field for
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import java.util.stream.StreamSupport;
Expand All @@ -25,7 +24,7 @@
/**
* One step of a compiled pipeline that compiles to a {@link Dataset}.
*/
public final class ComputeStepSyntaxElement<T extends Dataset> implements SyntaxElement {
public final class ComputeStepSyntaxElement<T extends Dataset> {

private static final Path SOURCE_DIR = debugDir();

Expand All @@ -37,36 +36,26 @@ public final class ComputeStepSyntaxElement<T extends Dataset> implements Syntax
private static final Map<ComputeStepSyntaxElement<?>, Class<? extends Dataset>> CLASS_CACHE
= new HashMap<>();

/**
* Sequence number to ensure unique naming for runtime compiled classes.
*/
private static final AtomicInteger SEQUENCE = new AtomicInteger(0);

/**
* Pattern to remove redundant {@code ;} from formatted code since {@link Formatter} does not
* remove those.
*/
private static final Pattern REDUNDANT_SEMICOLON = Pattern.compile("\n[ ]*;\n");

private final String name;

private final Iterable<MethodSyntaxElement> methods;

private final ClassFields fields;

private final Class<T> type;

ComputeStepSyntaxElement(final Iterable<MethodSyntaxElement> methods,
final ClassFields fields, final Class<T> interfce) {
this(
String.format("CompiledDataset%d", SEQUENCE.incrementAndGet()), methods, fields,
interfce
);
public static <T extends Dataset> ComputeStepSyntaxElement<T> create(
final Iterable<MethodSyntaxElement> methods, final ClassFields fields,
final Class<T> interfce) {
return new ComputeStepSyntaxElement<>(methods, fields, interfce);
}

private ComputeStepSyntaxElement(final String name, final Iterable<MethodSyntaxElement> methods,
private ComputeStepSyntaxElement(final Iterable<MethodSyntaxElement> methods,
final ClassFields fields, final Class<T> interfce) {
this.name = name;
this.methods = methods;
this.fields = fields;
type = interfce;
Expand All @@ -82,7 +71,8 @@ public T instantiate() {
if (CLASS_CACHE.containsKey(this)) {
clazz = CLASS_CACHE.get(this);
} else {
final String code = generateCode();
final String name = String.format("CompiledDataset%d", CLASS_CACHE.size());
final String code = generateCode(name);
final Path sourceFile = SOURCE_DIR.resolve(String.format("%s.java", name));
Files.write(sourceFile, code.getBytes(StandardCharsets.UTF_8));
COMPILER.cookFile(sourceFile.toFile());
Expand All @@ -102,15 +92,25 @@ public T instantiate() {
}

@Override
public String generateCode() {
public int hashCode() {
return normalizedSource().hashCode();
}

@Override
public boolean equals(final Object other) {
return other instanceof ComputeStepSyntaxElement &&
normalizedSource().equals(((ComputeStepSyntaxElement<?>) other).normalizedSource());
}

private String generateCode(final String name) {
try {
return REDUNDANT_SEMICOLON.matcher(new Formatter().formatSource(
String.format(
"package org.logstash.generated;\npublic final class %s implements %s { %s }",
name,
type.getName(),
SyntaxFactory.join(
fields.inlineAssigned().generateCode(), fieldsAndCtor(),
fields.inlineAssigned().generateCode(), fieldsAndCtor(name),
combine(
StreamSupport.stream(methods.spliterator(), false)
.toArray(SyntaxElement[]::new)
Expand All @@ -123,22 +123,6 @@ public String generateCode() {
}
}

@Override
public int hashCode() {
return normalizedSource().hashCode();
}

@Override
public boolean equals(final Object other) {
return other instanceof ComputeStepSyntaxElement &&
normalizedSource().equals(((ComputeStepSyntaxElement<?>) other).normalizedSource());
}

@Override
public String toString() {
return generateCode();
}

private static Path debugDir() {
final Path sourceDir;
try {
Expand Down Expand Up @@ -181,16 +165,15 @@ private Object[] ctorArguments() {
* @return Source of this class, with its name set to {@code CONSTANT}.
*/
private String normalizedSource() {
return new ComputeStepSyntaxElement<>("CONSTANT", methods, fields, type)
.generateCode();
return this.generateCode("CONSTANT");
}

/**
* Generates the Java code for defining one field and constructor argument for each given value.
* constructor for
* @return Java Source String
*/
private String fieldsAndCtor() {
private String fieldsAndCtor(final String name) {
final Closure constructor = new Closure();
final FieldDeclarationGroup ctorFields = fields.ctorAssigned();
final Collection<VariableDefinition> ctor = new ArrayList<>();
Expand Down
Loading

0 comments on commit 43f37ad

Please sign in to comment.