mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2025-01-07 07:24:11 -08:00
AST optimizations and output code minification
This commit is contained in:
parent
bc68602dae
commit
ce0859beac
teavm-core/src/main/java/org/teavm/javascript
|
@ -120,6 +120,7 @@ public class Decompiler {
|
||||||
clsNode.getMethods().add(decompile(method));
|
clsNode.getMethods().add(decompile(method));
|
||||||
}
|
}
|
||||||
clsNode.getInterfaces().addAll(cls.getInterfaces());
|
clsNode.getInterfaces().addAll(cls.getInterfaces());
|
||||||
|
clsNode.getModifiers().addAll(mapModifiers(cls.getModifiers()));
|
||||||
return clsNode;
|
return clsNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -213,6 +214,7 @@ public class Decompiler {
|
||||||
}
|
}
|
||||||
Optimizer optimizer = new Optimizer();
|
Optimizer optimizer = new Optimizer();
|
||||||
optimizer.optimize(methodNode, method.getProgram());
|
optimizer.optimize(methodNode, method.getProgram());
|
||||||
|
methodNode.getModifiers().addAll(mapModifiers(method.getModifiers()));
|
||||||
return methodNode;
|
return methodNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -220,6 +222,8 @@ public class Decompiler {
|
||||||
Set<NodeModifier> result = EnumSet.noneOf(NodeModifier.class);
|
Set<NodeModifier> result = EnumSet.noneOf(NodeModifier.class);
|
||||||
if (modifiers.contains(ElementModifier.STATIC)) {
|
if (modifiers.contains(ElementModifier.STATIC)) {
|
||||||
result.add(NodeModifier.STATIC);
|
result.add(NodeModifier.STATIC);
|
||||||
|
} else if (modifiers.contains(ElementModifier.INTERFACE)) {
|
||||||
|
result.add(NodeModifier.INTERFACE);
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,6 +37,8 @@ public class Optimizer {
|
||||||
UnusedVariableEliminator unusedEliminator = new UnusedVariableEliminator(paramCount, method.getVariables());
|
UnusedVariableEliminator unusedEliminator = new UnusedVariableEliminator(paramCount, method.getVariables());
|
||||||
method.getBody().acceptVisitor(unusedEliminator);
|
method.getBody().acceptVisitor(unusedEliminator);
|
||||||
method.getVariables().subList(unusedEliminator.lastIndex, method.getVariables().size()).clear();
|
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) {
|
for (int i = 0; i < method.getVariables().size(); ++i) {
|
||||||
method.getVariables().set(i, i);
|
method.getVariables().set(i, i);
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,6 +28,10 @@ class OptimizingVisitor implements StatementVisitor, ExprVisitor {
|
||||||
private ReadWriteStatsBuilder stats;
|
private ReadWriteStatsBuilder stats;
|
||||||
Map<IdentifiedStatement, Integer> referencedStatements = new HashMap<>();
|
Map<IdentifiedStatement, Integer> referencedStatements = new HashMap<>();
|
||||||
private List<Statement> resultSequence;
|
private List<Statement> resultSequence;
|
||||||
|
private int[] variableDecl;
|
||||||
|
private List<Boolean> invocations;
|
||||||
|
private int lastMethodCall;
|
||||||
|
private boolean hasMethodCall;
|
||||||
|
|
||||||
public OptimizingVisitor(ReadWriteStatsBuilder stats) {
|
public OptimizingVisitor(ReadWriteStatsBuilder stats) {
|
||||||
this.stats = stats;
|
this.stats = stats;
|
||||||
|
@ -118,22 +122,27 @@ class OptimizingVisitor implements StatementVisitor, ExprVisitor {
|
||||||
if (stats.reads[index] != 1 || stats.writes[index] != 1) {
|
if (stats.reads[index] != 1 || stats.writes[index] != 1) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (resultSequence.isEmpty()) {
|
int declIndex = variableDecl[index];
|
||||||
|
if (declIndex < 0 || declIndex >= lastMethodCall) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Statement last = resultSequence.get(resultSequence.size() - 1);
|
if (invocations.get(declIndex)) {
|
||||||
if (!(last instanceof AssignmentStatement)) {
|
for (int i = lastMethodCall - 1; i > declIndex; --i) {
|
||||||
return;
|
if (invocations.get(i)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
AssignmentStatement assignment = (AssignmentStatement)last;
|
for (int i = declIndex; i < lastMethodCall; ++i) {
|
||||||
if (!(assignment.getLeftValue() instanceof VariableExpr)) {
|
if (invocations.get(i)) {
|
||||||
return;
|
lastMethodCall = i;
|
||||||
}
|
break;
|
||||||
VariableExpr var = (VariableExpr)assignment.getLeftValue();
|
}
|
||||||
if (var.getIndex() == index) {
|
|
||||||
resultSequence.remove(resultSequence.size() - 1);
|
|
||||||
assignment.getRightValue().acceptVisitor(this);
|
|
||||||
}
|
}
|
||||||
|
AssignmentStatement decl = (AssignmentStatement)resultSequence.get(declIndex);
|
||||||
|
resultSequence.set(declIndex, null);
|
||||||
|
variableDecl[index] = -1;
|
||||||
|
resultExpr = decl.getRightValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -157,6 +166,7 @@ class OptimizingVisitor implements StatementVisitor, ExprVisitor {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(InvocationExpr expr) {
|
public void visit(InvocationExpr expr) {
|
||||||
|
hasMethodCall = true;
|
||||||
Expr[] args = new Expr[expr.getArguments().size()];
|
Expr[] args = new Expr[expr.getArguments().size()];
|
||||||
for (int i = expr.getArguments().size() - 1; i >= 0; --i) {
|
for (int i = expr.getArguments().size() - 1; i >= 0; --i) {
|
||||||
expr.getArguments().get(i).acceptVisitor(this);
|
expr.getArguments().get(i).acceptVisitor(this);
|
||||||
|
@ -266,6 +276,9 @@ class OptimizingVisitor implements StatementVisitor, ExprVisitor {
|
||||||
if (!(statement.getLeftValue() instanceof VariableExpr)) {
|
if (!(statement.getLeftValue() instanceof VariableExpr)) {
|
||||||
statement.getLeftValue().acceptVisitor(this);
|
statement.getLeftValue().acceptVisitor(this);
|
||||||
left = resultExpr;
|
left = resultExpr;
|
||||||
|
} else {
|
||||||
|
VariableExpr var = (VariableExpr)statement.getLeftValue();
|
||||||
|
variableDecl[var.getIndex()] = resultSequence.size();
|
||||||
}
|
}
|
||||||
statement.setLeftValue(left);
|
statement.setLeftValue(left);
|
||||||
statement.setRightValue(right);
|
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;
|
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<>();
|
List<Statement> result = new ArrayList<>();
|
||||||
if (strict) {
|
for (Statement part : resultSequence) {
|
||||||
resultSequence = result;
|
if (part != null) {
|
||||||
}
|
result.add(part);
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
resultSequence = backup;
|
resultSequence = backup;
|
||||||
|
variableDecl = variableDeclBackup;
|
||||||
|
invocations = invocationsBackup;
|
||||||
|
hasMethodCall = hasMethodCallBackup;
|
||||||
return result;
|
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) {
|
private void eliminateRedundantBreaks(List<Statement> statements, IdentifiedStatement exit) {
|
||||||
if (statements.isEmpty()) {
|
if (statements.isEmpty()) {
|
||||||
return;
|
return;
|
||||||
|
@ -398,7 +434,7 @@ class OptimizingVisitor implements StatementVisitor, ExprVisitor {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(SequentialStatement statement) {
|
public void visit(SequentialStatement statement) {
|
||||||
List<Statement> statements = processSequence(statement.getSequence(), false);
|
List<Statement> statements = processSequence(statement.getSequence());
|
||||||
if (statements.size() == 1) {
|
if (statements.size() == 1) {
|
||||||
resultStmt = statements.get(0);
|
resultStmt = statements.get(0);
|
||||||
} else {
|
} else {
|
||||||
|
@ -412,8 +448,8 @@ class OptimizingVisitor implements StatementVisitor, ExprVisitor {
|
||||||
public void visit(ConditionalStatement statement) {
|
public void visit(ConditionalStatement statement) {
|
||||||
statement.getCondition().acceptVisitor(this);
|
statement.getCondition().acceptVisitor(this);
|
||||||
statement.setCondition(resultExpr);
|
statement.setCondition(resultExpr);
|
||||||
List<Statement> consequent = processSequence(statement.getConsequent(), true);
|
List<Statement> consequent = processSequence(statement.getConsequent());
|
||||||
List<Statement> alternative = processSequence(statement.getAlternative(), true);
|
List<Statement> alternative = processSequence(statement.getAlternative());
|
||||||
if (consequent.isEmpty()) {
|
if (consequent.isEmpty()) {
|
||||||
consequent.addAll(alternative);
|
consequent.addAll(alternative);
|
||||||
alternative.clear();
|
alternative.clear();
|
||||||
|
@ -428,6 +464,7 @@ class OptimizingVisitor implements StatementVisitor, ExprVisitor {
|
||||||
statement.getAlternative().clear();
|
statement.getAlternative().clear();
|
||||||
statement.getAlternative().addAll(alternative);
|
statement.getAlternative().addAll(alternative);
|
||||||
resultStmt = statement;
|
resultStmt = statement;
|
||||||
|
hasMethodCall = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -435,14 +472,15 @@ class OptimizingVisitor implements StatementVisitor, ExprVisitor {
|
||||||
statement.getValue().acceptVisitor(this);
|
statement.getValue().acceptVisitor(this);
|
||||||
statement.setValue(resultExpr);
|
statement.setValue(resultExpr);
|
||||||
for (SwitchClause clause : statement.getClauses()) {
|
for (SwitchClause clause : statement.getClauses()) {
|
||||||
List<Statement> newBody = processSequence(clause.getBody(), true);
|
List<Statement> newBody = processSequence(clause.getBody());
|
||||||
clause.getBody().clear();
|
clause.getBody().clear();
|
||||||
clause.getBody().addAll(newBody);
|
clause.getBody().addAll(newBody);
|
||||||
}
|
}
|
||||||
List<Statement> newDefault = processSequence(statement.getDefaultClause(), true);
|
List<Statement> newDefault = processSequence(statement.getDefaultClause());
|
||||||
statement.getDefaultClause().clear();
|
statement.getDefaultClause().clear();
|
||||||
statement.getDefaultClause().addAll(newDefault);
|
statement.getDefaultClause().addAll(newDefault);
|
||||||
resultStmt = statement;
|
resultStmt = statement;
|
||||||
|
hasMethodCall = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -454,7 +492,7 @@ class OptimizingVisitor implements StatementVisitor, ExprVisitor {
|
||||||
statement.getBody().clear();
|
statement.getBody().clear();
|
||||||
statement.getBody().addAll(innerLoop.getBody());
|
statement.getBody().addAll(innerLoop.getBody());
|
||||||
}
|
}
|
||||||
List<Statement> statements = processSequence(statement.getBody(), true);
|
List<Statement> statements = processSequence(statement.getBody());
|
||||||
statement.getBody().clear();
|
statement.getBody().clear();
|
||||||
statement.getBody().addAll(statements);
|
statement.getBody().addAll(statements);
|
||||||
if (statement.getCondition() != null) {
|
if (statement.getCondition() != null) {
|
||||||
|
@ -481,11 +519,12 @@ class OptimizingVisitor implements StatementVisitor, ExprVisitor {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
resultStmt = statement;
|
resultStmt = statement;
|
||||||
|
hasMethodCall = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(BlockStatement statement) {
|
public void visit(BlockStatement statement) {
|
||||||
List<Statement> statements = processSequence(statement.getBody(), false);
|
List<Statement> statements = processSequence(statement.getBody());
|
||||||
eliminateRedundantBreaks(statements, statement);
|
eliminateRedundantBreaks(statements, statement);
|
||||||
if (referencedStatements.get(statement).equals(0)) {
|
if (referencedStatements.get(statement).equals(0)) {
|
||||||
SequentialStatement result = new SequentialStatement();
|
SequentialStatement result = new SequentialStatement();
|
||||||
|
@ -505,11 +544,13 @@ class OptimizingVisitor implements StatementVisitor, ExprVisitor {
|
||||||
@Override
|
@Override
|
||||||
public void visit(BreakStatement statement) {
|
public void visit(BreakStatement statement) {
|
||||||
resultStmt = statement;
|
resultStmt = statement;
|
||||||
|
hasMethodCall = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(ContinueStatement statement) {
|
public void visit(ContinueStatement statement) {
|
||||||
resultStmt = statement;
|
resultStmt = statement;
|
||||||
|
hasMethodCall = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -519,6 +560,7 @@ class OptimizingVisitor implements StatementVisitor, ExprVisitor {
|
||||||
statement.setResult(resultExpr);
|
statement.setResult(resultExpr);
|
||||||
}
|
}
|
||||||
resultStmt = statement;
|
resultStmt = statement;
|
||||||
|
hasMethodCall = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -526,6 +568,7 @@ class OptimizingVisitor implements StatementVisitor, ExprVisitor {
|
||||||
statement.getException().acceptVisitor(this);
|
statement.getException().acceptVisitor(this);
|
||||||
statement.setException(resultExpr);
|
statement.setException(resultExpr);
|
||||||
resultStmt = statement;
|
resultStmt = statement;
|
||||||
|
hasMethodCall = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@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();
|
.append(constantToString(value)).append(";").softNewLine();
|
||||||
}
|
}
|
||||||
|
|
||||||
writer.appendClass(cls.getName()).append(".prototype").ws().append("=").ws().append("new ")
|
if (!cls.getModifiers().contains(NodeModifier.INTERFACE)) {
|
||||||
.append(cls.getParentName() != null ? naming.getNameFor(cls.getParentName()) :
|
writer.appendClass(cls.getName()).append(".prototype").ws().append("=").ws().append("new ")
|
||||||
"Object").append("();").softNewLine();
|
.append(cls.getParentName() != null ? naming.getNameFor(cls.getParentName()) :
|
||||||
writer.appendClass(cls.getName()).append(".prototype.constructor").ws().append("=").ws()
|
"Object").append("();").softNewLine();
|
||||||
.appendClass(cls.getName()).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.appendClass(cls.getName()).append(".$meta").ws().append("=").ws().append("{").ws();
|
||||||
writer.append("name").ws().append(":").ws().append("\"").append(cls.getName()).append("\",").ws();
|
writer.append("name").ws().append(":").ws().append("\"").append(cls.getName()).append("\",").ws();
|
||||||
writer.append("primitive").ws().append(":").ws().append("false,").ws();
|
writer.append("primitive").ws().append(":").ws().append("false,").ws();
|
||||||
|
@ -173,37 +175,39 @@ public class Renderer implements ExprVisitor, StatementVisitor {
|
||||||
}
|
}
|
||||||
writer.append("]");
|
writer.append("]");
|
||||||
writer.ws().append("};").softNewLine();
|
writer.ws().append("};").softNewLine();
|
||||||
writer.appendClass(cls.getName()).append("_$clinit").ws().append("=").ws().append("function()").ws()
|
if (!cls.getModifiers().contains(NodeModifier.INTERFACE)) {
|
||||||
.append("{").softNewLine().indent();
|
writer.appendClass(cls.getName()).append("_$clinit").ws().append("=").ws().append("function()").ws()
|
||||||
writer.appendClass(cls.getName()).append("_$clinit").ws().append("=").ws()
|
.append("{").softNewLine().indent();
|
||||||
.append("function(){};").newLine();
|
writer.appendClass(cls.getName()).append("_$clinit").ws().append("=").ws()
|
||||||
List<String> stubNames = new ArrayList<>();
|
.append("function(){};").newLine();
|
||||||
for (MethodNode method : cls.getMethods()) {
|
List<String> stubNames = new ArrayList<>();
|
||||||
renderBody(method);
|
for (MethodNode method : cls.getMethods()) {
|
||||||
stubNames.add(naming.getFullNameFor(method.getReference()));
|
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);
|
|
||||||
}
|
}
|
||||||
}
|
MethodHolder methodHolder = classSource.getClassHolder(cls.getName()).getMethod(
|
||||||
if (stubNames.size() > 0) {
|
new MethodDescriptor("<clinit>", ValueType.VOID));
|
||||||
writer.append("$rt_methodStubs(").appendClass(cls.getName()).append("_$clinit")
|
if (methodHolder != null) {
|
||||||
.append(",").ws().append("[");
|
writer.appendMethodBody(new MethodReference(cls.getName(), methodHolder.getDescriptor()))
|
||||||
for (int i = 0; i < stubNames.size(); ++i) {
|
.append("();").softNewLine();
|
||||||
if (i > 0) {
|
}
|
||||||
writer.append(",").ws();
|
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) {
|
} catch (NamingException e) {
|
||||||
throw new RenderingException("Error rendering class " + cls.getName() + ". See a cause for details", 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
|
@Override
|
||||||
public void visit(BreakStatement statement) {
|
public void visit(BreakStatement statement) {
|
||||||
try {
|
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) {
|
} catch (IOException e) {
|
||||||
throw new RenderingException("IO error occured", e);
|
throw new RenderingException("IO error occured", e);
|
||||||
}
|
}
|
||||||
|
@ -498,7 +506,11 @@ public class Renderer implements ExprVisitor, StatementVisitor {
|
||||||
@Override
|
@Override
|
||||||
public void visit(ContinueStatement statement) {
|
public void visit(ContinueStatement statement) {
|
||||||
try {
|
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) {
|
} catch (IOException e) {
|
||||||
throw new RenderingException("IO error occured", e);
|
throw new RenderingException("IO error occured", e);
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,7 +16,9 @@
|
||||||
package org.teavm.javascript.ast;
|
package org.teavm.javascript.ast;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.EnumSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
|
@ -25,6 +27,7 @@ import java.util.List;
|
||||||
public class ClassNode {
|
public class ClassNode {
|
||||||
private String name;
|
private String name;
|
||||||
private String parentName;
|
private String parentName;
|
||||||
|
private Set<NodeModifier> modifiers = EnumSet.noneOf(NodeModifier.class);
|
||||||
private List<FieldNode> fields = new ArrayList<>();
|
private List<FieldNode> fields = new ArrayList<>();
|
||||||
private List<MethodNode> methods = new ArrayList<>();
|
private List<MethodNode> methods = new ArrayList<>();
|
||||||
private List<String> interfaces = new ArrayList<>();
|
private List<String> interfaces = new ArrayList<>();
|
||||||
|
@ -53,4 +56,8 @@ public class ClassNode {
|
||||||
public List<String> getInterfaces() {
|
public List<String> getInterfaces() {
|
||||||
return interfaces;
|
return interfaces;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Set<NodeModifier> getModifiers() {
|
||||||
|
return modifiers;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,5 +20,6 @@ package org.teavm.javascript.ast;
|
||||||
* @author Alexey Andreev <konsoletyper@gmail.com>
|
* @author Alexey Andreev <konsoletyper@gmail.com>
|
||||||
*/
|
*/
|
||||||
public enum NodeModifier {
|
public enum NodeModifier {
|
||||||
STATIC
|
STATIC,
|
||||||
|
INTERFACE
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user