Встраивание констант из модулей

This commit is contained in:
Victor 2016-07-24 14:30:55 +03:00
parent 8077b643bf
commit 1842c4c387
6 changed files with 58 additions and 64 deletions

View File

@ -31,6 +31,7 @@ task runOptimizing(dependsOn: classes, type: JavaExec) {
main = project.mainClass
classpath = sourceSets.main.runtimeClasspath
ignoreExitValue = true
// args '-o 9 -m -a -f examples/game/minesweeper.own'.split(' ')
args '-o 9 -m -a -f program.own'.split(' ')
}

View File

@ -1,59 +0,0 @@
package com.annimon.ownlang.annotations;
import java.lang.reflect.Modifier;
import java.util.Arrays;
import java.util.Optional;
import java.util.Set;
import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.RoundEnvironment;
import javax.annotation.processing.SupportedAnnotationTypes;
import javax.annotation.processing.SupportedSourceVersion;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.Element;
import javax.lang.model.element.ElementKind;
import javax.lang.model.element.TypeElement;
import javax.lang.model.type.ExecutableType;
import javax.lang.model.type.TypeKind;
import javax.lang.model.util.SimpleTypeVisitor6;
import javax.tools.Diagnostic.Kind;
@SupportedAnnotationTypes("com.annimon.ownlang.annotations.ConstantInitializer")
@SupportedSourceVersion(SourceVersion.RELEASE_6)
public class ConstantInitializerAnnotationProcessor extends AbstractProcessor {
// https://github.com/corgrath/abandoned-Requires-Static-Method-Annotation
private static final String METHOD_NAME = "initConstants";
@Override
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
Set<? extends Element> elements = roundEnv.getElementsAnnotatedWith(ConstantInitializer.class);
for (Element element : elements) {
final Optional<? extends Element> result = element.getEnclosedElements().stream()
.filter(e -> e.getKind() == ElementKind.METHOD)
.filter(m -> m.getSimpleName().contentEquals(METHOD_NAME))
.filter(m -> m.getModifiers().containsAll(Arrays.asList(Modifier.PUBLIC, Modifier.STATIC)))
.filter(m -> m.asType().accept(visitor, null))
.findFirst();
if (result.isPresent()) {
showError(element);
return true;
}
}
return true;
}
private void showError(Element element) {
final String message = String.format("Class %s requires a method"
+ " `public static void %s() {}`", element.getSimpleName(), METHOD_NAME);
processingEnv.getMessager().printMessage(Kind.ERROR, message, element);
}
private final SimpleTypeVisitor6<Boolean, Void> visitor = new SimpleTypeVisitor6<Boolean, Void>() {
@Override
public Boolean visitExecutable(ExecutableType t, Void v) {
if (t.getReturnType().getKind() != TypeKind.VOID) return false;
if (!t.getParameterTypes().isEmpty()) return false;
return true;
}
};
}

View File

@ -1,6 +1,7 @@
package com.annimon.ownlang.parser.ast;
import com.annimon.ownlang.lib.modules.Module;
import java.lang.reflect.Method;
/**
*
@ -9,6 +10,7 @@ import com.annimon.ownlang.lib.modules.Module;
public final class UseStatement extends InterruptableNode implements Statement {
private static final String PACKAGE = "com.annimon.ownlang.lib.modules.";
private static final String INIT_CONSTANTS_METHOD = "initConstants";
public final Expression expression;
@ -28,6 +30,18 @@ public final class UseStatement extends InterruptableNode implements Statement {
}
}
public void loadConstants() {
try {
final String moduleName = expression.eval().asString();
final Class<?> moduleClass = Class.forName(PACKAGE + moduleName);
final Method method = moduleClass.getMethod(INIT_CONSTANTS_METHOD);
if (method != null) {
method.invoke(this);
}
} catch (Exception ex) {
}
}
@Override
public void accept(Visitor visitor) {
visitor.visit(this);

View File

@ -23,7 +23,7 @@ public class ConstantPropagation extends OptimizationVisitor<Map<String, Value>>
public Node optimize(Node node) {
final Map<String, VariableInfo> variables = new HashMap<>();
// Find variables
node.accept(new VariablesGrabber(), variables);
node.accept(new VariablesGrabber(true), variables);
// Filter only string/number values with 1 modification
final Map<String, Value> candidates = new HashMap<>();
for (Map.Entry<String, VariableInfo> e : variables.entrySet()) {

View File

@ -1,5 +1,7 @@
package com.annimon.ownlang.parser.optimization;
import com.annimon.ownlang.lib.Value;
import com.annimon.ownlang.lib.Variables;
import com.annimon.ownlang.parser.ast.Accessible;
import com.annimon.ownlang.parser.ast.Argument;
import com.annimon.ownlang.parser.ast.AssignmentExpression;
@ -11,6 +13,7 @@ import com.annimon.ownlang.parser.ast.FunctionDefineStatement;
import com.annimon.ownlang.parser.ast.MatchExpression;
import com.annimon.ownlang.parser.ast.Node;
import com.annimon.ownlang.parser.ast.UnaryExpression;
import com.annimon.ownlang.parser.ast.UseStatement;
import com.annimon.ownlang.parser.ast.ValueExpression;
import com.annimon.ownlang.parser.ast.VariableExpression;
import static com.annimon.ownlang.parser.visitors.VisitorUtils.isValue;
@ -21,11 +24,25 @@ import java.util.Map;
public class VariablesGrabber extends OptimizationVisitor<Map<String, VariableInfo>> {
public static Map<String, VariableInfo> getInfo(Node node) {
return getInfo(node, false);
}
public static Map<String, VariableInfo> getInfo(Node node, boolean grabModuleConstants) {
Map<String, VariableInfo> variableInfos = new HashMap<>();
node.accept(new VariablesGrabber(), variableInfos);
node.accept(new VariablesGrabber(grabModuleConstants), variableInfos);
return variableInfos;
}
private final boolean grabModuleConstants;
public VariablesGrabber() {
this(false);
}
public VariablesGrabber(boolean grabModuleConstants) {
this.grabModuleConstants = grabModuleConstants;
}
@Override
public Node visit(AssignmentExpression s, Map<String, VariableInfo> t) {
if (!isVariable((Node)s.target)) {
@ -99,6 +116,27 @@ public class VariablesGrabber extends OptimizationVisitor<Map<String, VariableIn
return super.visit(s, t);
}
@Override
public Node visit(UseStatement s, Map<String, VariableInfo> t) {
if (grabModuleConstants) {
// To get module variables we need to store current variables, clear all, then load module.
final Map<String, Value> currentVariables = new HashMap<>(Variables.variables());
Variables.variables().clear();
if (isValue(s.expression)) {
s.loadConstants();
}
// Grab module variables
for (Map.Entry<String, Value> entry : Variables.variables().entrySet()) {
final VariableInfo var = variableInfo(t, entry.getKey());
var.value = entry.getValue();
t.put(entry.getKey(), var);
}
// Restore previous variables
Variables.variables().putAll(currentVariables);
}
return super.visit(s, t);
}
private VariableInfo variableInfo(Map<String, VariableInfo> t, final String variableName) {