mirror of
https://github.com/aNNiMON/Own-Programming-Language-Tutorial.git
synced 2024-09-20 00:34:20 +03:00
Встраивание констант из модулей
This commit is contained in:
parent
8077b643bf
commit
1842c4c387
@ -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(' ')
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
};
|
||||
}
|
@ -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);
|
||||
|
@ -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()) {
|
||||
|
@ -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) {
|
||||
|
Loading…
Reference in New Issue
Block a user