mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2024-12-22 16:14:10 -08:00
AST optimizations and output code minification
This commit is contained in:
parent
bc68602dae
commit
ce0859beac
|
@ -120,6 +120,7 @@ public class Decompiler {
|
|||
clsNode.getMethods().add(decompile(method));
|
||||
}
|
||||
clsNode.getInterfaces().addAll(cls.getInterfaces());
|
||||
clsNode.getModifiers().addAll(mapModifiers(cls.getModifiers()));
|
||||
return clsNode;
|
||||
}
|
||||
|
||||
|
@ -213,6 +214,7 @@ public class Decompiler {
|
|||
}
|
||||
Optimizer optimizer = new Optimizer();
|
||||
optimizer.optimize(methodNode, method.getProgram());
|
||||
methodNode.getModifiers().addAll(mapModifiers(method.getModifiers()));
|
||||
return methodNode;
|
||||
}
|
||||
|
||||
|
@ -220,6 +222,8 @@ public class Decompiler {
|
|||
Set<NodeModifier> result = EnumSet.noneOf(NodeModifier.class);
|
||||
if (modifiers.contains(ElementModifier.STATIC)) {
|
||||
result.add(NodeModifier.STATIC);
|
||||
} else if (modifiers.contains(ElementModifier.INTERFACE)) {
|
||||
result.add(NodeModifier.INTERFACE);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
|
|
@ -37,6 +37,8 @@ public class Optimizer {
|
|||
UnusedVariableEliminator unusedEliminator = new UnusedVariableEliminator(paramCount, method.getVariables());
|
||||
method.getBody().acceptVisitor(unusedEliminator);
|
||||
method.getVariables().subList(unusedEliminator.lastIndex, method.getVariables().size()).clear();
|
||||
RedundantLabelEliminator labelEliminator = new RedundantLabelEliminator();
|
||||
method.getBody().acceptVisitor(labelEliminator);
|
||||
for (int i = 0; i < method.getVariables().size(); ++i) {
|
||||
method.getVariables().set(i, i);
|
||||
}
|
||||
|
|
|
@ -28,6 +28,10 @@ class OptimizingVisitor implements StatementVisitor, ExprVisitor {
|
|||
private ReadWriteStatsBuilder stats;
|
||||
Map<IdentifiedStatement, Integer> referencedStatements = new HashMap<>();
|
||||
private List<Statement> resultSequence;
|
||||
private int[] variableDecl;
|
||||
private List<Boolean> invocations;
|
||||
private int lastMethodCall;
|
||||
private boolean hasMethodCall;
|
||||
|
||||
public OptimizingVisitor(ReadWriteStatsBuilder stats) {
|
||||
this.stats = stats;
|
||||
|
@ -118,22 +122,27 @@ class OptimizingVisitor implements StatementVisitor, ExprVisitor {
|
|||
if (stats.reads[index] != 1 || stats.writes[index] != 1) {
|
||||
return;
|
||||
}
|
||||
if (resultSequence.isEmpty()) {
|
||||
int declIndex = variableDecl[index];
|
||||
if (declIndex < 0 || declIndex >= lastMethodCall) {
|
||||
return;
|
||||
}
|
||||
Statement last = resultSequence.get(resultSequence.size() - 1);
|
||||
if (!(last instanceof AssignmentStatement)) {
|
||||
return;
|
||||
if (invocations.get(declIndex)) {
|
||||
for (int i = lastMethodCall - 1; i > declIndex; --i) {
|
||||
if (invocations.get(i)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
AssignmentStatement assignment = (AssignmentStatement)last;
|
||||
if (!(assignment.getLeftValue() instanceof VariableExpr)) {
|
||||
return;
|
||||
}
|
||||
VariableExpr var = (VariableExpr)assignment.getLeftValue();
|
||||
if (var.getIndex() == index) {
|
||||
resultSequence.remove(resultSequence.size() - 1);
|
||||
assignment.getRightValue().acceptVisitor(this);
|
||||
for (int i = declIndex; i < lastMethodCall; ++i) {
|
||||
if (invocations.get(i)) {
|
||||
lastMethodCall = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
AssignmentStatement decl = (AssignmentStatement)resultSequence.get(declIndex);
|
||||
resultSequence.set(declIndex, null);
|
||||
variableDecl[index] = -1;
|
||||
resultExpr = decl.getRightValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -157,6 +166,7 @@ class OptimizingVisitor implements StatementVisitor, ExprVisitor {
|
|||
|
||||
@Override
|
||||
public void visit(InvocationExpr expr) {
|
||||
hasMethodCall = true;
|
||||
Expr[] args = new Expr[expr.getArguments().size()];
|
||||
for (int i = expr.getArguments().size() - 1; i >= 0; --i) {
|
||||
expr.getArguments().get(i).acceptVisitor(this);
|
||||
|
@ -266,6 +276,9 @@ class OptimizingVisitor implements StatementVisitor, ExprVisitor {
|
|||
if (!(statement.getLeftValue() instanceof VariableExpr)) {
|
||||
statement.getLeftValue().acceptVisitor(this);
|
||||
left = resultExpr;
|
||||
} else {
|
||||
VariableExpr var = (VariableExpr)statement.getLeftValue();
|
||||
variableDecl[var.getIndex()] = resultSequence.size();
|
||||
}
|
||||
statement.setLeftValue(left);
|
||||
statement.setRightValue(right);
|
||||
|
@ -273,34 +286,57 @@ class OptimizingVisitor implements StatementVisitor, ExprVisitor {
|
|||
}
|
||||
}
|
||||
|
||||
private List<Statement> processSequence(List<Statement> statements, boolean strict) {
|
||||
private List<Statement> processSequence(List<Statement> statements) {
|
||||
boolean hasMethodCallBackup = hasMethodCall;
|
||||
List<Statement> backup = resultSequence;
|
||||
int[] variableDeclBackup = variableDecl;
|
||||
List<Boolean> invocationsBackup = invocations;
|
||||
invocations = new ArrayList<>();
|
||||
resultSequence = new ArrayList<>();
|
||||
variableDecl = new int[stats.reads.length];
|
||||
Arrays.fill(variableDecl, -1);
|
||||
processSequenceImpl(statements);
|
||||
List<Statement> result = new ArrayList<>();
|
||||
if (strict) {
|
||||
resultSequence = result;
|
||||
}
|
||||
outer: for (int i = 0; i < statements.size(); ++i) {
|
||||
Statement part = statements.get(i);
|
||||
part.acceptVisitor(this);
|
||||
List<Statement> newStatements = new ArrayList<>();
|
||||
if (resultStmt instanceof SequentialStatement) {
|
||||
newStatements.addAll(((SequentialStatement)resultStmt).getSequence());
|
||||
} else {
|
||||
newStatements.add(resultStmt);
|
||||
}
|
||||
for (int j = 0; j < newStatements.size(); ++j) {
|
||||
Statement newStatement = newStatements.get(j);
|
||||
resultSequence = result;
|
||||
result.add(newStatement);
|
||||
if (newStatement instanceof BreakStatement) {
|
||||
break outer;
|
||||
}
|
||||
for (Statement part : resultSequence) {
|
||||
if (part != null) {
|
||||
result.add(part);
|
||||
}
|
||||
}
|
||||
resultSequence = backup;
|
||||
variableDecl = variableDeclBackup;
|
||||
invocations = invocationsBackup;
|
||||
hasMethodCall = hasMethodCallBackup;
|
||||
return result;
|
||||
}
|
||||
|
||||
private boolean processSequenceImpl(List<Statement> statements) {
|
||||
for (int i = 0; i < statements.size(); ++i) {
|
||||
Statement part = statements.get(i);
|
||||
if (part instanceof SequentialStatement) {
|
||||
if (!processSequenceImpl(((SequentialStatement)part).getSequence())) {
|
||||
return false;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
hasMethodCall = false;
|
||||
lastMethodCall = resultSequence.size();
|
||||
part.acceptVisitor(this);
|
||||
invocations.add(hasMethodCall);
|
||||
part = resultStmt;
|
||||
if (part instanceof SequentialStatement) {
|
||||
if (!processSequenceImpl(((SequentialStatement)part).getSequence())) {
|
||||
return false;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
resultSequence.add(part);
|
||||
if (part instanceof BreakStatement) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private void eliminateRedundantBreaks(List<Statement> statements, IdentifiedStatement exit) {
|
||||
if (statements.isEmpty()) {
|
||||
return;
|
||||
|
@ -398,7 +434,7 @@ class OptimizingVisitor implements StatementVisitor, ExprVisitor {
|
|||
|
||||
@Override
|
||||
public void visit(SequentialStatement statement) {
|
||||
List<Statement> statements = processSequence(statement.getSequence(), false);
|
||||
List<Statement> statements = processSequence(statement.getSequence());
|
||||
if (statements.size() == 1) {
|
||||
resultStmt = statements.get(0);
|
||||
} else {
|
||||
|
@ -412,8 +448,8 @@ class OptimizingVisitor implements StatementVisitor, ExprVisitor {
|
|||
public void visit(ConditionalStatement statement) {
|
||||
statement.getCondition().acceptVisitor(this);
|
||||
statement.setCondition(resultExpr);
|
||||
List<Statement> consequent = processSequence(statement.getConsequent(), true);
|
||||
List<Statement> alternative = processSequence(statement.getAlternative(), true);
|
||||
List<Statement> consequent = processSequence(statement.getConsequent());
|
||||
List<Statement> alternative = processSequence(statement.getAlternative());
|
||||
if (consequent.isEmpty()) {
|
||||
consequent.addAll(alternative);
|
||||
alternative.clear();
|
||||
|
@ -428,6 +464,7 @@ class OptimizingVisitor implements StatementVisitor, ExprVisitor {
|
|||
statement.getAlternative().clear();
|
||||
statement.getAlternative().addAll(alternative);
|
||||
resultStmt = statement;
|
||||
hasMethodCall = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -435,14 +472,15 @@ class OptimizingVisitor implements StatementVisitor, ExprVisitor {
|
|||
statement.getValue().acceptVisitor(this);
|
||||
statement.setValue(resultExpr);
|
||||
for (SwitchClause clause : statement.getClauses()) {
|
||||
List<Statement> newBody = processSequence(clause.getBody(), true);
|
||||
List<Statement> newBody = processSequence(clause.getBody());
|
||||
clause.getBody().clear();
|
||||
clause.getBody().addAll(newBody);
|
||||
}
|
||||
List<Statement> newDefault = processSequence(statement.getDefaultClause(), true);
|
||||
List<Statement> newDefault = processSequence(statement.getDefaultClause());
|
||||
statement.getDefaultClause().clear();
|
||||
statement.getDefaultClause().addAll(newDefault);
|
||||
resultStmt = statement;
|
||||
hasMethodCall = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -454,7 +492,7 @@ class OptimizingVisitor implements StatementVisitor, ExprVisitor {
|
|||
statement.getBody().clear();
|
||||
statement.getBody().addAll(innerLoop.getBody());
|
||||
}
|
||||
List<Statement> statements = processSequence(statement.getBody(), true);
|
||||
List<Statement> statements = processSequence(statement.getBody());
|
||||
statement.getBody().clear();
|
||||
statement.getBody().addAll(statements);
|
||||
if (statement.getCondition() != null) {
|
||||
|
@ -481,11 +519,12 @@ class OptimizingVisitor implements StatementVisitor, ExprVisitor {
|
|||
break;
|
||||
}
|
||||
resultStmt = statement;
|
||||
hasMethodCall = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(BlockStatement statement) {
|
||||
List<Statement> statements = processSequence(statement.getBody(), false);
|
||||
List<Statement> statements = processSequence(statement.getBody());
|
||||
eliminateRedundantBreaks(statements, statement);
|
||||
if (referencedStatements.get(statement).equals(0)) {
|
||||
SequentialStatement result = new SequentialStatement();
|
||||
|
@ -505,11 +544,13 @@ class OptimizingVisitor implements StatementVisitor, ExprVisitor {
|
|||
@Override
|
||||
public void visit(BreakStatement statement) {
|
||||
resultStmt = statement;
|
||||
hasMethodCall = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(ContinueStatement statement) {
|
||||
resultStmt = statement;
|
||||
hasMethodCall = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -519,6 +560,7 @@ class OptimizingVisitor implements StatementVisitor, ExprVisitor {
|
|||
statement.setResult(resultExpr);
|
||||
}
|
||||
resultStmt = statement;
|
||||
hasMethodCall = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -526,6 +568,7 @@ class OptimizingVisitor implements StatementVisitor, ExprVisitor {
|
|||
statement.getException().acceptVisitor(this);
|
||||
statement.setException(resultExpr);
|
||||
resultStmt = statement;
|
||||
hasMethodCall = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -0,0 +1,122 @@
|
|||
/*
|
||||
* Copyright 2014 Alexey Andreev.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.teavm.javascript;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import org.teavm.javascript.ast.*;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Alexey Andreev
|
||||
*/
|
||||
class RedundantLabelEliminator implements StatementVisitor {
|
||||
private IdentifiedStatement currentBlock;
|
||||
private Set<IdentifiedStatement> hasRefs = new HashSet<>();
|
||||
|
||||
void visitSequence(List<Statement> statements) {
|
||||
for (Statement statement : statements) {
|
||||
statement.acceptVisitor(this);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(AssignmentStatement statement) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(SequentialStatement statement) {
|
||||
visitSequence(statement.getSequence());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(ConditionalStatement statement) {
|
||||
visitSequence(statement.getConsequent());
|
||||
visitSequence(statement.getAlternative());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(SwitchStatement statement) {
|
||||
IdentifiedStatement currentBlockBackup = currentBlock;
|
||||
currentBlock = statement;
|
||||
for (SwitchClause clause : statement.getClauses()) {
|
||||
visitSequence(clause.getBody());
|
||||
}
|
||||
visitSequence(statement.getDefaultClause());
|
||||
if (!hasRefs.contains(currentBlock)) {
|
||||
currentBlock.setId(null);
|
||||
}
|
||||
currentBlock = currentBlockBackup;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(WhileStatement statement) {
|
||||
IdentifiedStatement currentBlockBackup = currentBlock;
|
||||
currentBlock = statement;
|
||||
visitSequence(statement.getBody());
|
||||
if (!hasRefs.contains(currentBlock)) {
|
||||
currentBlock.setId(null);
|
||||
}
|
||||
currentBlock = currentBlockBackup;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(BlockStatement statement) {
|
||||
IdentifiedStatement currentBlockBackup = currentBlock;
|
||||
currentBlock = null;
|
||||
visitSequence(statement.getBody());
|
||||
currentBlock = currentBlockBackup;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(ForStatement statement) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(BreakStatement statement) {
|
||||
if (statement.getTarget() == currentBlock) {
|
||||
statement.setTarget(null);
|
||||
} else {
|
||||
hasRefs.add(statement.getTarget());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(ContinueStatement statement) {
|
||||
if (statement.getTarget() == currentBlock) {
|
||||
statement.setTarget(null);
|
||||
} else {
|
||||
hasRefs.add(statement.getTarget());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(ReturnStatement statement) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(ThrowStatement statement) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(IncrementStatement statement) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(InitClassStatement statement) {
|
||||
}
|
||||
}
|
|
@ -150,11 +150,13 @@ public class Renderer implements ExprVisitor, StatementVisitor {
|
|||
.append(constantToString(value)).append(";").softNewLine();
|
||||
}
|
||||
|
||||
writer.appendClass(cls.getName()).append(".prototype").ws().append("=").ws().append("new ")
|
||||
.append(cls.getParentName() != null ? naming.getNameFor(cls.getParentName()) :
|
||||
"Object").append("();").softNewLine();
|
||||
writer.appendClass(cls.getName()).append(".prototype.constructor").ws().append("=").ws()
|
||||
.appendClass(cls.getName()).append(';').softNewLine();
|
||||
if (!cls.getModifiers().contains(NodeModifier.INTERFACE)) {
|
||||
writer.appendClass(cls.getName()).append(".prototype").ws().append("=").ws().append("new ")
|
||||
.append(cls.getParentName() != null ? naming.getNameFor(cls.getParentName()) :
|
||||
"Object").append("();").softNewLine();
|
||||
writer.appendClass(cls.getName()).append(".prototype.constructor").ws().append("=").ws()
|
||||
.appendClass(cls.getName()).append(';').softNewLine();
|
||||
}
|
||||
writer.appendClass(cls.getName()).append(".$meta").ws().append("=").ws().append("{").ws();
|
||||
writer.append("name").ws().append(":").ws().append("\"").append(cls.getName()).append("\",").ws();
|
||||
writer.append("primitive").ws().append(":").ws().append("false,").ws();
|
||||
|
@ -173,37 +175,39 @@ public class Renderer implements ExprVisitor, StatementVisitor {
|
|||
}
|
||||
writer.append("]");
|
||||
writer.ws().append("};").softNewLine();
|
||||
writer.appendClass(cls.getName()).append("_$clinit").ws().append("=").ws().append("function()").ws()
|
||||
.append("{").softNewLine().indent();
|
||||
writer.appendClass(cls.getName()).append("_$clinit").ws().append("=").ws()
|
||||
.append("function(){};").newLine();
|
||||
List<String> stubNames = new ArrayList<>();
|
||||
for (MethodNode method : cls.getMethods()) {
|
||||
renderBody(method);
|
||||
stubNames.add(naming.getFullNameFor(method.getReference()));
|
||||
}
|
||||
MethodHolder methodHolder = classSource.getClassHolder(cls.getName()).getMethod(
|
||||
new MethodDescriptor("<clinit>", ValueType.VOID));
|
||||
if (methodHolder != null) {
|
||||
writer.appendMethodBody(new MethodReference(cls.getName(), methodHolder.getDescriptor()))
|
||||
.append("();").softNewLine();
|
||||
}
|
||||
writer.outdent().append("}").newLine();
|
||||
for (MethodNode method : cls.getMethods()) {
|
||||
if (!method.getModifiers().contains(NodeModifier.STATIC)) {
|
||||
renderDeclaration(method);
|
||||
if (!cls.getModifiers().contains(NodeModifier.INTERFACE)) {
|
||||
writer.appendClass(cls.getName()).append("_$clinit").ws().append("=").ws().append("function()").ws()
|
||||
.append("{").softNewLine().indent();
|
||||
writer.appendClass(cls.getName()).append("_$clinit").ws().append("=").ws()
|
||||
.append("function(){};").newLine();
|
||||
List<String> stubNames = new ArrayList<>();
|
||||
for (MethodNode method : cls.getMethods()) {
|
||||
renderBody(method);
|
||||
stubNames.add(naming.getFullNameFor(method.getReference()));
|
||||
}
|
||||
}
|
||||
if (stubNames.size() > 0) {
|
||||
writer.append("$rt_methodStubs(").appendClass(cls.getName()).append("_$clinit")
|
||||
.append(",").ws().append("[");
|
||||
for (int i = 0; i < stubNames.size(); ++i) {
|
||||
if (i > 0) {
|
||||
writer.append(",").ws();
|
||||
MethodHolder methodHolder = classSource.getClassHolder(cls.getName()).getMethod(
|
||||
new MethodDescriptor("<clinit>", ValueType.VOID));
|
||||
if (methodHolder != null) {
|
||||
writer.appendMethodBody(new MethodReference(cls.getName(), methodHolder.getDescriptor()))
|
||||
.append("();").softNewLine();
|
||||
}
|
||||
writer.outdent().append("}").newLine();
|
||||
for (MethodNode method : cls.getMethods()) {
|
||||
if (!method.getModifiers().contains(NodeModifier.STATIC)) {
|
||||
renderDeclaration(method);
|
||||
}
|
||||
writer.append("'").append(stubNames.get(i)).append("'");
|
||||
}
|
||||
writer.append("]);").newLine();
|
||||
if (stubNames.size() > 0) {
|
||||
writer.append("$rt_methodStubs(").appendClass(cls.getName()).append("_$clinit")
|
||||
.append(",").ws().append("[");
|
||||
for (int i = 0; i < stubNames.size(); ++i) {
|
||||
if (i > 0) {
|
||||
writer.append(",").ws();
|
||||
}
|
||||
writer.append("'").append(stubNames.get(i)).append("'");
|
||||
}
|
||||
writer.append("]);").newLine();
|
||||
}
|
||||
}
|
||||
} catch (NamingException e) {
|
||||
throw new RenderingException("Error rendering class " + cls.getName() + ". See a cause for details", e);
|
||||
|
@ -489,7 +493,11 @@ public class Renderer implements ExprVisitor, StatementVisitor {
|
|||
@Override
|
||||
public void visit(BreakStatement statement) {
|
||||
try {
|
||||
writer.append("break ").append(statement.getTarget().getId()).append(";").softNewLine();
|
||||
writer.append("break");
|
||||
if (statement.getTarget() != null) {
|
||||
writer.append(' ').append(statement.getTarget().getId());
|
||||
}
|
||||
writer.append(";").softNewLine();
|
||||
} catch (IOException e) {
|
||||
throw new RenderingException("IO error occured", e);
|
||||
}
|
||||
|
@ -498,7 +506,11 @@ public class Renderer implements ExprVisitor, StatementVisitor {
|
|||
@Override
|
||||
public void visit(ContinueStatement statement) {
|
||||
try {
|
||||
writer.append("continue ").append(statement.getTarget().getId()).append(";").softNewLine();
|
||||
writer.append("continue");
|
||||
if (statement.getTarget() != null) {
|
||||
writer.append(' ').append(statement.getTarget().getId());
|
||||
}
|
||||
writer.append(";").softNewLine();
|
||||
} catch (IOException e) {
|
||||
throw new RenderingException("IO error occured", e);
|
||||
}
|
||||
|
|
|
@ -16,7 +16,9 @@
|
|||
package org.teavm.javascript.ast;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.EnumSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
*
|
||||
|
@ -25,6 +27,7 @@ import java.util.List;
|
|||
public class ClassNode {
|
||||
private String name;
|
||||
private String parentName;
|
||||
private Set<NodeModifier> modifiers = EnumSet.noneOf(NodeModifier.class);
|
||||
private List<FieldNode> fields = new ArrayList<>();
|
||||
private List<MethodNode> methods = new ArrayList<>();
|
||||
private List<String> interfaces = new ArrayList<>();
|
||||
|
@ -53,4 +56,8 @@ public class ClassNode {
|
|||
public List<String> getInterfaces() {
|
||||
return interfaces;
|
||||
}
|
||||
|
||||
public Set<NodeModifier> getModifiers() {
|
||||
return modifiers;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,5 +20,6 @@ package org.teavm.javascript.ast;
|
|||
* @author Alexey Andreev <konsoletyper@gmail.com>
|
||||
*/
|
||||
public enum NodeModifier {
|
||||
STATIC
|
||||
STATIC,
|
||||
INTERFACE
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user