mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2024-12-22 08:14:09 -08:00
js: refactor and simplify AstWriter, properly fix case with variable in catch block
This commit is contained in:
parent
e4452152b7
commit
ccfe19994b
|
@ -15,10 +15,9 @@
|
||||||
*/
|
*/
|
||||||
package org.teavm.backend.javascript.rendering;
|
package org.teavm.backend.javascript.rendering;
|
||||||
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
@ -97,9 +96,9 @@ public class AstWriter {
|
||||||
protected boolean rootScope = true;
|
protected boolean rootScope = true;
|
||||||
private Set<String> aliases = new HashSet<>();
|
private Set<String> aliases = new HashSet<>();
|
||||||
private Function<String, NameEmitter> globalNameWriter;
|
private Function<String, NameEmitter> globalNameWriter;
|
||||||
public final Map<String, Scope> currentScopes = new HashMap<>();
|
private Set<String> nonTopLevels = new HashSet<>();
|
||||||
protected final Set<Scope> topLevelScopes = new HashSet<>();
|
|
||||||
private boolean inFunction;
|
private boolean inFunction;
|
||||||
|
private int scopeLevel;
|
||||||
|
|
||||||
public AstWriter(SourceWriter writer, Function<String, NameEmitter> globalNameWriter) {
|
public AstWriter(SourceWriter writer, Function<String, NameEmitter> globalNameWriter) {
|
||||||
this.writer = writer;
|
this.writer = writer;
|
||||||
|
@ -115,13 +114,13 @@ public class AstWriter {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (aliases.add(name)) {
|
if (aliases.add(name)) {
|
||||||
nameMap.put(name, p -> writer.append(name));
|
nameMap.put(name, (w, p) -> w.append(name));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
for (int i = 0;; ++i) {
|
for (int i = 0;; ++i) {
|
||||||
String alias = name + "_" + i;
|
String alias = name + "_" + i;
|
||||||
if (aliases.add(alias)) {
|
if (aliases.add(alias)) {
|
||||||
nameMap.put(name, p -> writer.append(alias));
|
nameMap.put(name, (w, p) -> w.append(alias));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -202,7 +201,7 @@ public class AstWriter {
|
||||||
break;
|
break;
|
||||||
case Token.THIS:
|
case Token.THIS:
|
||||||
if (nameMap.containsKey("this")) {
|
if (nameMap.containsKey("this")) {
|
||||||
nameMap.get("this").emit(precedence);
|
nameMap.get("this").emit(writer, precedence);
|
||||||
} else {
|
} else {
|
||||||
writer.append("this");
|
writer.append("this");
|
||||||
}
|
}
|
||||||
|
@ -324,7 +323,7 @@ public class AstWriter {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void print(Scope node) {
|
private void print(Scope node) {
|
||||||
var scope = enterScope(node);
|
var scope = enterScope(node, false);
|
||||||
writer.append('{').softNewLine().indent();
|
writer.append('{').softNewLine().indent();
|
||||||
for (Node child = node.getFirstChild(); child != null; child = child.getNext()) {
|
for (Node child = node.getFirstChild(); child != null; child = child.getNext()) {
|
||||||
if (!print((AstNode) child)) {
|
if (!print((AstNode) child)) {
|
||||||
|
@ -332,7 +331,7 @@ public class AstWriter {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
writer.outdent().append('}');
|
writer.outdent().append('}');
|
||||||
leaveScope(scope, node);
|
leaveScope(scope);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void print(LabeledStatement node) {
|
private void print(LabeledStatement node) {
|
||||||
|
@ -374,17 +373,17 @@ public class AstWriter {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void print(DoLoop node) {
|
private void print(DoLoop node) {
|
||||||
var scope = enterScope(node);
|
var scope = enterScope(node, false);
|
||||||
writer.append("do ").ws();
|
writer.append("do ").ws();
|
||||||
print(node.getBody());
|
print(node.getBody());
|
||||||
writer.append("while").ws().append('(');
|
writer.append("while").ws().append('(');
|
||||||
print(node.getCondition());
|
print(node.getCondition());
|
||||||
writer.append(");");
|
writer.append(");");
|
||||||
leaveScope(scope, node);
|
leaveScope(scope);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void print(ForInLoop node) {
|
private void print(ForInLoop node) {
|
||||||
var scope = enterScope(node);
|
var scope = enterScope(node, false);
|
||||||
writer.append("for");
|
writer.append("for");
|
||||||
if (node.isForEach()) {
|
if (node.isForEach()) {
|
||||||
writer.append(" each");
|
writer.append(" each");
|
||||||
|
@ -395,11 +394,11 @@ public class AstWriter {
|
||||||
print(node.getIteratedObject());
|
print(node.getIteratedObject());
|
||||||
writer.append(')').ws();
|
writer.append(')').ws();
|
||||||
print(node.getBody());
|
print(node.getBody());
|
||||||
leaveScope(scope, node);
|
leaveScope(scope);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void print(ForLoop node) {
|
private void print(ForLoop node) {
|
||||||
var scope = enterScope(node);
|
var scope = enterScope(node, false);
|
||||||
writer.append("for").ws().append('(');
|
writer.append("for").ws().append('(');
|
||||||
print(node.getInitializer());
|
print(node.getInitializer());
|
||||||
writer.append(';');
|
writer.append(';');
|
||||||
|
@ -408,16 +407,16 @@ public class AstWriter {
|
||||||
print(node.getIncrement());
|
print(node.getIncrement());
|
||||||
writer.append(')').ws();
|
writer.append(')').ws();
|
||||||
print(node.getBody());
|
print(node.getBody());
|
||||||
leaveScope(scope, node);
|
leaveScope(scope);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void print(WhileLoop node) {
|
private void print(WhileLoop node) {
|
||||||
var scope = enterScope(node);
|
var scope = enterScope(node, false);
|
||||||
writer.append("while").ws().append('(');
|
writer.append("while").ws().append('(');
|
||||||
print(node.getCondition());
|
print(node.getCondition());
|
||||||
writer.append(')').ws();
|
writer.append(')').ws();
|
||||||
print(node.getBody());
|
print(node.getBody());
|
||||||
leaveScope(scope, node);
|
leaveScope(scope);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void print(IfStatement node) {
|
private void print(IfStatement node) {
|
||||||
|
@ -458,8 +457,10 @@ public class AstWriter {
|
||||||
private void print(TryStatement node) {
|
private void print(TryStatement node) {
|
||||||
writer.append("try ");
|
writer.append("try ");
|
||||||
print(node.getTryBlock());
|
print(node.getTryBlock());
|
||||||
for (CatchClause cc : node.getCatchClauses()) {
|
for (var cc : node.getCatchClauses()) {
|
||||||
writer.ws().append("catch").ws().append('(');
|
writer.ws().append("catch").ws().append('(');
|
||||||
|
var scope = enterScope(false);
|
||||||
|
includeInScope(scope, cc.getVarName().getIdentifier());
|
||||||
print(cc.getVarName());
|
print(cc.getVarName());
|
||||||
if (cc.getCatchCondition() != null) {
|
if (cc.getCatchCondition() != null) {
|
||||||
writer.append(" if ");
|
writer.append(" if ");
|
||||||
|
@ -467,6 +468,7 @@ public class AstWriter {
|
||||||
}
|
}
|
||||||
writer.append(')');
|
writer.append(')');
|
||||||
print(cc.getBody());
|
print(cc.getBody());
|
||||||
|
leaveScope(scope);
|
||||||
}
|
}
|
||||||
if (node.getFinallyBlock() != null) {
|
if (node.getFinallyBlock() != null) {
|
||||||
writer.ws().append("finally ");
|
writer.ws().append("finally ");
|
||||||
|
@ -475,10 +477,9 @@ public class AstWriter {
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean print(VariableDeclaration node) {
|
private boolean print(VariableDeclaration node) {
|
||||||
if (isTopLevel() && node.getVariables().get(0).getTarget() instanceof Name) {
|
if (isTopLevelOutput() && node.getVariables().get(0).getTarget() instanceof Name) {
|
||||||
var name = (Name) node.getVariables().get(0).getTarget();
|
var name = (Name) node.getVariables().get(0).getTarget();
|
||||||
var definingScope = scopeOfId(name.getIdentifier());
|
if (isTopLevelIdentifier(name.getIdentifier())) {
|
||||||
if (definingScope == null || topLevelScopes.contains(definingScope)) {
|
|
||||||
printTopLevel(node);
|
printTopLevel(node);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -647,7 +648,7 @@ public class AstWriter {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void print(ArrayComprehension node) {
|
private void print(ArrayComprehension node) {
|
||||||
var scope = enterScope(node);
|
var scope = enterScope(node, false);
|
||||||
writer.append("[");
|
writer.append("[");
|
||||||
for (ArrayComprehensionLoop loop : node.getLoops()) {
|
for (ArrayComprehensionLoop loop : node.getLoops()) {
|
||||||
writer.append("for").ws().append("(");
|
writer.append("for").ws().append("(");
|
||||||
|
@ -663,11 +664,11 @@ public class AstWriter {
|
||||||
}
|
}
|
||||||
print(node.getResult());
|
print(node.getResult());
|
||||||
writer.append(']');
|
writer.append(']');
|
||||||
leaveScope(scope, node);
|
leaveScope(scope);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void print(GeneratorExpression node) {
|
private void print(GeneratorExpression node) {
|
||||||
var scope = enterScope(node);
|
var scope = enterScope(node, false);
|
||||||
writer.append("(");
|
writer.append("(");
|
||||||
for (GeneratorExpressionLoop loop : node.getLoops()) {
|
for (GeneratorExpressionLoop loop : node.getLoops()) {
|
||||||
writer.append("for").ws().append("(");
|
writer.append("for").ws().append("(");
|
||||||
|
@ -683,7 +684,7 @@ public class AstWriter {
|
||||||
}
|
}
|
||||||
print(node.getResult());
|
print(node.getResult());
|
||||||
writer.append(')');
|
writer.append(')');
|
||||||
leaveScope(scope, node);
|
leaveScope(scope);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void print(NumberLiteral node) {
|
private void print(NumberLiteral node) {
|
||||||
|
@ -697,17 +698,16 @@ public class AstWriter {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void print(Name node, int precedence) {
|
public void print(Name node, int precedence) {
|
||||||
var definingScope = scopeOfId(node.getIdentifier());
|
if (rootScope && isTopLevelIdentifier(node.getIdentifier())) {
|
||||||
if (rootScope && definingScope == null) {
|
|
||||||
var alias = nameMap.get(node.getIdentifier());
|
var alias = nameMap.get(node.getIdentifier());
|
||||||
if (alias == null) {
|
if (alias == null) {
|
||||||
if (globalNameWriter != null) {
|
if (globalNameWriter != null) {
|
||||||
alias = globalNameWriter.apply(node.getIdentifier());
|
alias = globalNameWriter.apply(node.getIdentifier());
|
||||||
} else {
|
} else {
|
||||||
alias = prec -> writer.append(node.getIdentifier());
|
alias = (w, prec) -> w.append(node.getIdentifier());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
alias.emit(precedence);
|
alias.emit(writer, precedence);
|
||||||
} else {
|
} else {
|
||||||
writer.append(node.getIdentifier());
|
writer.append(node.getIdentifier());
|
||||||
}
|
}
|
||||||
|
@ -753,18 +753,16 @@ public class AstWriter {
|
||||||
|
|
||||||
protected boolean print(FunctionNode node) {
|
protected boolean print(FunctionNode node) {
|
||||||
var isArrow = node.getFunctionType() == FunctionNode.ARROW_FUNCTION;
|
var isArrow = node.getFunctionType() == FunctionNode.ARROW_FUNCTION;
|
||||||
if (isTopLevel() && !isArrow && node.getFunctionName() != null) {
|
if (isTopLevelOutput() && !isArrow && node.getFunctionName() != null
|
||||||
var definingScope = scopeOfId(node.getFunctionName().getIdentifier());
|
&& isTopLevelIdentifier(node.getFunctionName().getIdentifier())) {
|
||||||
if (definingScope == null || topLevelScopes.contains(definingScope)) {
|
printTopLevel(node);
|
||||||
printTopLevel(node);
|
return true;
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
var wasInFunction = inFunction;
|
var wasInFunction = inFunction;
|
||||||
inFunction = true;
|
inFunction = true;
|
||||||
var scope = enterScope(node);
|
var scope = enterScope(node, true);
|
||||||
if (!isArrow) {
|
if (!isArrow) {
|
||||||
currentScopes.put("arguments", node);
|
includeInScope(scope, "arguments");
|
||||||
}
|
}
|
||||||
if (!node.isMethod() && !isArrow) {
|
if (!node.isMethod() && !isArrow) {
|
||||||
writer.append("function");
|
writer.append("function");
|
||||||
|
@ -797,7 +795,7 @@ public class AstWriter {
|
||||||
print(node.getBody());
|
print(node.getBody());
|
||||||
}
|
}
|
||||||
|
|
||||||
leaveScope(scope, node);
|
leaveScope(scope);
|
||||||
inFunction = wasInFunction;
|
inFunction = wasInFunction;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -805,25 +803,25 @@ public class AstWriter {
|
||||||
private void printTopLevel(FunctionNode node) {
|
private void printTopLevel(FunctionNode node) {
|
||||||
var wasInFunction = inFunction;
|
var wasInFunction = inFunction;
|
||||||
inFunction = true;
|
inFunction = true;
|
||||||
var scope = enterScope(node);
|
var scope = enterScope(node, true);
|
||||||
currentScopes.put("arguments", node);
|
includeInScope(scope, "arguments");
|
||||||
writer.startFunctionDeclaration().appendFunction(node.getFunctionName().getIdentifier());
|
writer.startFunctionDeclaration().appendFunction(node.getFunctionName().getIdentifier());
|
||||||
writer.append('(');
|
writer.append('(');
|
||||||
printList(node.getParams());
|
printList(node.getParams());
|
||||||
writer.append(')').ws();
|
writer.append(')').ws();
|
||||||
print(node.getBody());
|
print(node.getBody());
|
||||||
writer.endDeclaration();
|
writer.endDeclaration();
|
||||||
leaveScope(scope, node);
|
leaveScope(scope);
|
||||||
inFunction = wasInFunction;
|
inFunction = wasInFunction;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void print(LetNode node) {
|
private void print(LetNode node) {
|
||||||
var scope = enterScope(node);
|
var scope = enterScope(node, false);
|
||||||
writer.append("let").ws().append('(');
|
writer.append("let").ws().append('(');
|
||||||
printList(node.getVariables().getVariables());
|
printList(node.getVariables().getVariables());
|
||||||
writer.append(')');
|
writer.append(')');
|
||||||
print(node.getBody());
|
print(node.getBody());
|
||||||
leaveScope(scope, node);
|
leaveScope(scope);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void print(ParenthesizedExpression node, int precedence) {
|
private void print(ParenthesizedExpression node, int precedence) {
|
||||||
|
@ -1021,47 +1019,45 @@ public class AstWriter {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Map<String, Scope> enterScope(Scope scope) {
|
private Set<String> enterScope(Scope scope, boolean nesting) {
|
||||||
if (scope.getSymbolTable() == null) {
|
var set = enterScope(nesting);
|
||||||
return Collections.emptyMap();
|
if (scope.getSymbolTable() != null) {
|
||||||
}
|
for (var name : scope.getSymbolTable().keySet()) {
|
||||||
var map = new LinkedHashMap<String, Scope>();
|
includeInScope(set, name);
|
||||||
for (var name : scope.getSymbolTable().keySet()) {
|
|
||||||
map.put(name, currentScopes.get(name));
|
|
||||||
currentScopes.put(name, scope);
|
|
||||||
}
|
|
||||||
onEnterScope(scope);
|
|
||||||
return map;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void onEnterScope(Scope scope) {
|
|
||||||
if (isTopLevel() && !inFunction()) {
|
|
||||||
topLevelScopes.add(scope);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void leaveScope(Map<String, Scope> backup, Scope scope) {
|
|
||||||
for (var entry : backup.entrySet()) {
|
|
||||||
if (entry.getValue() == null) {
|
|
||||||
currentScopes.remove(entry.getKey());
|
|
||||||
} else {
|
|
||||||
currentScopes.put(entry.getKey(), entry.getValue());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
onLeaveScope(scope);
|
return set;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void onLeaveScope(Scope scope) {
|
public Set<String> enterScope(boolean nesting) {
|
||||||
if (isTopLevel() && !inFunction()) {
|
if (scopeLevel > 0 || nesting) {
|
||||||
topLevelScopes.remove(scope);
|
++scopeLevel;
|
||||||
|
}
|
||||||
|
return new LinkedHashSet<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public final void includeInScope(Set<String> scope, String name) {
|
||||||
|
if (nonTopLevels.add(name)) {
|
||||||
|
scope.add(name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Scope scopeOfId(String id) {
|
public void leaveScope(Set<String> backup) {
|
||||||
return currentScopes.get(id);
|
nonTopLevels.removeAll(backup);
|
||||||
|
if (scopeLevel > 0) {
|
||||||
|
--scopeLevel;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected boolean isTopLevel() {
|
protected boolean isTopLevelIdentifier(String id) {
|
||||||
|
return !nonTopLevels.contains(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected boolean isInTopLevelScope() {
|
||||||
|
return scopeLevel == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected boolean isTopLevelOutput() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,20 +16,13 @@
|
||||||
package org.teavm.backend.javascript.rendering;
|
package org.teavm.backend.javascript.rendering;
|
||||||
|
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
import org.teavm.backend.javascript.codegen.SourceWriter;
|
|
||||||
|
|
||||||
public class DefaultGlobalNameWriter implements Function<String, NameEmitter> {
|
public class DefaultGlobalNameWriter implements Function<String, NameEmitter> {
|
||||||
private SourceWriter writer;
|
|
||||||
|
|
||||||
public DefaultGlobalNameWriter(SourceWriter writer) {
|
|
||||||
this.writer = writer;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public NameEmitter apply(String s) {
|
public NameEmitter apply(String s) {
|
||||||
if (s.startsWith("$rt_") || s.startsWith("Long_") || s.equals("Long")) {
|
if (s.startsWith("$rt_") || s.startsWith("Long_") || s.equals("Long")) {
|
||||||
return prec -> writer.appendFunction(s);
|
return (w, intprec) -> w.appendFunction(s);
|
||||||
}
|
}
|
||||||
return prec -> writer.appendGlobal(s);
|
return (w, prec) -> w.appendGlobal(s);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,6 +15,8 @@
|
||||||
*/
|
*/
|
||||||
package org.teavm.backend.javascript.rendering;
|
package org.teavm.backend.javascript.rendering;
|
||||||
|
|
||||||
|
import org.teavm.backend.javascript.codegen.SourceWriter;
|
||||||
|
|
||||||
public interface NameEmitter {
|
public interface NameEmitter {
|
||||||
void emit(int precedence);
|
void emit(SourceWriter writer, int precedence);
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,7 +21,9 @@ import java.io.InputStreamReader;
|
||||||
import java.io.Reader;
|
import java.io.Reader;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
import org.mozilla.javascript.CompilerEnvirons;
|
import org.mozilla.javascript.CompilerEnvirons;
|
||||||
import org.mozilla.javascript.Context;
|
import org.mozilla.javascript.Context;
|
||||||
import org.mozilla.javascript.ast.AstRoot;
|
import org.mozilla.javascript.ast.AstRoot;
|
||||||
|
@ -42,6 +44,7 @@ public class RuntimeRenderer {
|
||||||
private final ClassReaderSource classSource;
|
private final ClassReaderSource classSource;
|
||||||
private final SourceWriter writer;
|
private final SourceWriter writer;
|
||||||
private final ClassInitializerInfo classInitializerInfo;
|
private final ClassInitializerInfo classInitializerInfo;
|
||||||
|
private final Set<String> topLevelNames = new HashSet<>();
|
||||||
|
|
||||||
public RuntimeRenderer(ClassReaderSource classSource, SourceWriter writer,
|
public RuntimeRenderer(ClassReaderSource classSource, SourceWriter writer,
|
||||||
ClassInitializerInfo classInitializerInfo) {
|
ClassInitializerInfo classInitializerInfo) {
|
||||||
|
@ -83,12 +86,15 @@ public class RuntimeRenderer {
|
||||||
ast.visit(new StringConstantElimination());
|
ast.visit(new StringConstantElimination());
|
||||||
new TemplatingAstTransformer(classSource).visit(ast);
|
new TemplatingAstTransformer(classSource).visit(ast);
|
||||||
removablePartsFinder.visit(ast);
|
removablePartsFinder.visit(ast);
|
||||||
|
topLevelNames.addAll(ast.getSymbolTable().keySet());
|
||||||
return ast;
|
return ast;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void renderRuntimePart(AstRoot ast) {
|
private void renderRuntimePart(AstRoot ast) {
|
||||||
var astWriter = new TemplatingAstWriter(writer, null, null, classInitializerInfo);
|
var astWriter = new TemplatingAstWriter(writer, classInitializerInfo, true);
|
||||||
astWriter.hoist(ast);
|
for (var name : topLevelNames) {
|
||||||
|
astWriter.declareNameEmitter(name, (w, prec) -> w.appendFunction(name));
|
||||||
|
}
|
||||||
astWriter.print(ast);
|
astWriter.print(ast);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -21,6 +21,7 @@ import java.util.function.IntFunction;
|
||||||
import org.mozilla.javascript.ast.AstNode;
|
import org.mozilla.javascript.ast.AstNode;
|
||||||
import org.mozilla.javascript.ast.FunctionNode;
|
import org.mozilla.javascript.ast.FunctionNode;
|
||||||
import org.mozilla.javascript.ast.Name;
|
import org.mozilla.javascript.ast.Name;
|
||||||
|
import org.teavm.backend.javascript.rendering.NameEmitter;
|
||||||
import org.teavm.backend.javascript.spi.GeneratorContext;
|
import org.teavm.backend.javascript.spi.GeneratorContext;
|
||||||
import org.teavm.model.ClassReaderSource;
|
import org.teavm.model.ClassReaderSource;
|
||||||
|
|
||||||
|
@ -65,27 +66,26 @@ public class JavaScriptTemplate {
|
||||||
|
|
||||||
public SourceFragment build() {
|
public SourceFragment build() {
|
||||||
var intParameters = parameters;
|
var intParameters = parameters;
|
||||||
var nameParameters = new HashMap<String, SourceFragment>();
|
var nameParameters = new HashMap<String, NameEmitter>();
|
||||||
for (var i = 0; i < node.getParams().size(); ++i) {
|
for (var i = 0; i < node.getParams().size(); ++i) {
|
||||||
var param = node.getParams().get(i);
|
var param = node.getParams().get(i);
|
||||||
if (param instanceof Name) {
|
if (param instanceof Name) {
|
||||||
nameParameters.put(((Name) param).getIdentifier(), intParameters.apply(i + 1));
|
var sourceFragment = intParameters.apply(i + 1);
|
||||||
|
nameParameters.put(((Name) param).getIdentifier(), sourceFragment::write);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var thisFragment = parameters.apply(0);
|
var thisFragment = parameters.apply(0);
|
||||||
var body = node.getBody();
|
var body = node.getBody();
|
||||||
return (writer, precedence) -> {
|
return (writer, precedence) -> {
|
||||||
var astWriter = new TemplatingAstWriter(writer, nameParameters, node, null);
|
var astWriter = new TemplatingAstWriter(writer, null, false);
|
||||||
|
for (var entry : nameParameters.entrySet()) {
|
||||||
|
astWriter.declareNameEmitter(entry.getKey(), entry.getValue());
|
||||||
|
}
|
||||||
for (var entry : fragments.entrySet()) {
|
for (var entry : fragments.entrySet()) {
|
||||||
astWriter.setFragment(entry.getKey(), entry.getValue());
|
astWriter.setFragment(entry.getKey(), entry.getValue());
|
||||||
}
|
}
|
||||||
if (node.getSymbolTable() != null) {
|
|
||||||
for (var name : node.getSymbolTable().keySet()) {
|
|
||||||
astWriter.currentScopes.put(name, node);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (thisFragment != null) {
|
if (thisFragment != null) {
|
||||||
astWriter.declareNameEmitter("this", thisPrecedence -> thisFragment.write(writer, thisPrecedence));
|
astWriter.declareNameEmitter("this", thisFragment::write);
|
||||||
}
|
}
|
||||||
for (var child = body.getFirstChild(); child != null; child = child.getNext()) {
|
for (var child = body.getFirstChild(); child != null; child = child.getNext()) {
|
||||||
astWriter.print((AstNode) child);
|
astWriter.print((AstNode) child);
|
||||||
|
|
|
@ -19,10 +19,8 @@ import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import org.mozilla.javascript.ast.ElementGet;
|
import org.mozilla.javascript.ast.ElementGet;
|
||||||
import org.mozilla.javascript.ast.FunctionCall;
|
import org.mozilla.javascript.ast.FunctionCall;
|
||||||
import org.mozilla.javascript.ast.FunctionNode;
|
|
||||||
import org.mozilla.javascript.ast.Name;
|
import org.mozilla.javascript.ast.Name;
|
||||||
import org.mozilla.javascript.ast.PropertyGet;
|
import org.mozilla.javascript.ast.PropertyGet;
|
||||||
import org.mozilla.javascript.ast.Scope;
|
|
||||||
import org.mozilla.javascript.ast.StringLiteral;
|
import org.mozilla.javascript.ast.StringLiteral;
|
||||||
import org.teavm.backend.javascript.codegen.SourceWriter;
|
import org.teavm.backend.javascript.codegen.SourceWriter;
|
||||||
import org.teavm.backend.javascript.rendering.AstWriter;
|
import org.teavm.backend.javascript.rendering.AstWriter;
|
||||||
|
@ -33,25 +31,14 @@ import org.teavm.model.MethodReference;
|
||||||
import org.teavm.model.analysis.ClassInitializerInfo;
|
import org.teavm.model.analysis.ClassInitializerInfo;
|
||||||
|
|
||||||
public class TemplatingAstWriter extends AstWriter {
|
public class TemplatingAstWriter extends AstWriter {
|
||||||
private Map<String, SourceFragment> names;
|
|
||||||
private Scope scope;
|
|
||||||
private Map<String, SourceFragment> fragments = new HashMap<>();
|
private Map<String, SourceFragment> fragments = new HashMap<>();
|
||||||
private ClassInitializerInfo classInitializerInfo;
|
private ClassInitializerInfo classInitializerInfo;
|
||||||
|
private boolean topLevelOutput;
|
||||||
|
|
||||||
public TemplatingAstWriter(SourceWriter writer, Map<String, SourceFragment> names, Scope scope,
|
public TemplatingAstWriter(SourceWriter writer, ClassInitializerInfo classInitializerInfo, boolean topLevelOutput) {
|
||||||
ClassInitializerInfo classInitializerInfo) {
|
super(writer, new DefaultGlobalNameWriter());
|
||||||
super(writer, new DefaultGlobalNameWriter(writer));
|
|
||||||
this.classInitializerInfo = classInitializerInfo;
|
this.classInitializerInfo = classInitializerInfo;
|
||||||
this.names = names;
|
this.topLevelOutput = topLevelOutput;
|
||||||
this.scope = scope;
|
|
||||||
if (names != null) {
|
|
||||||
for (var name : names.keySet()) {
|
|
||||||
currentScopes.put(name, scope);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (scope instanceof FunctionNode) {
|
|
||||||
currentScopes.put("arguments", scope);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setFragment(String name, SourceFragment fragment) {
|
public void setFragment(String name, SourceFragment fragment) {
|
||||||
|
@ -62,7 +49,7 @@ public class TemplatingAstWriter extends AstWriter {
|
||||||
protected boolean intrinsic(FunctionCall node, int precedence) {
|
protected boolean intrinsic(FunctionCall node, int precedence) {
|
||||||
if (node.getTarget() instanceof Name) {
|
if (node.getTarget() instanceof Name) {
|
||||||
var name = (Name) node.getTarget();
|
var name = (Name) node.getTarget();
|
||||||
if (scopeOfId(name.getIdentifier()) == null) {
|
if (isTopLevelIdentifier(name.getIdentifier())) {
|
||||||
return tryIntrinsicName(node, name.getIdentifier());
|
return tryIntrinsicName(node, name.getIdentifier());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -164,7 +151,7 @@ public class TemplatingAstWriter extends AstWriter {
|
||||||
var call = (FunctionCall) node.getElement();
|
var call = (FunctionCall) node.getElement();
|
||||||
if (call.getTarget() instanceof Name) {
|
if (call.getTarget() instanceof Name) {
|
||||||
var name = (Name) call.getTarget();
|
var name = (Name) call.getTarget();
|
||||||
if (scopeOfId(name.getIdentifier()) == null) {
|
if (isTopLevelIdentifier(name.getIdentifier())) {
|
||||||
switch (name.getIdentifier()) {
|
switch (name.getIdentifier()) {
|
||||||
case "teavm_javaVirtualMethod":
|
case "teavm_javaVirtualMethod":
|
||||||
if (writeJavaVirtualMethod(node, call)) {
|
if (writeJavaVirtualMethod(node, call)) {
|
||||||
|
@ -187,8 +174,7 @@ public class TemplatingAstWriter extends AstWriter {
|
||||||
public void print(PropertyGet node) {
|
public void print(PropertyGet node) {
|
||||||
if (node.getTarget() instanceof Name) {
|
if (node.getTarget() instanceof Name) {
|
||||||
var name = (Name) node.getTarget();
|
var name = (Name) node.getTarget();
|
||||||
var scope = scopeOfId(name.getIdentifier());
|
if (isTopLevelIdentifier(name.getIdentifier()) && name.getIdentifier().equals("teavm_globals")) {
|
||||||
if (scope == null && name.getIdentifier().equals("teavm_globals")) {
|
|
||||||
var oldRootScope = rootScope;
|
var oldRootScope = rootScope;
|
||||||
rootScope = false;
|
rootScope = false;
|
||||||
writer.appendGlobal(node.getProperty().getIdentifier());
|
writer.appendGlobal(node.getProperty().getIdentifier());
|
||||||
|
@ -227,26 +213,7 @@ public class TemplatingAstWriter extends AstWriter {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void print(Name node, int precedence) {
|
public boolean isTopLevelOutput() {
|
||||||
var definingScope = scopeOfId(node.getIdentifier());
|
return topLevelOutput;
|
||||||
if (rootScope) {
|
|
||||||
if (names != null && definingScope == scope) {
|
|
||||||
var fragment = names.get(node.getIdentifier());
|
|
||||||
if (fragment != null) {
|
|
||||||
fragment.write(writer, precedence);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (definingScope == null || topLevelScopes.contains(definingScope)) {
|
|
||||||
writer.appendFunction(node.getIdentifier());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
super.print(node, precedence);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected boolean isTopLevel() {
|
|
||||||
return names == null;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,7 +35,7 @@ public class AstWriterTest {
|
||||||
builder.setMinified(true);
|
builder.setMinified(true);
|
||||||
sourceWriter = builder.build(sb);
|
sourceWriter = builder.build(sb);
|
||||||
writer = new AstWriter(sourceWriter, null);
|
writer = new AstWriter(sourceWriter, null);
|
||||||
writerWithGlobals = new AstWriter(sourceWriter, name -> prec -> sourceWriter.append("globals.").append(name));
|
writerWithGlobals = new AstWriter(sourceWriter, name -> (w, prec) -> w.append("globals.").append(name));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
|
@ -44,21 +44,21 @@ class JSBodyAstEmitter implements JSBodyEmitter {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void emit(InjectorContext context) {
|
public void emit(InjectorContext context) {
|
||||||
var astWriter = new AstWriter(context.getWriter(), new DefaultGlobalNameWriter(context.getWriter()));
|
var astWriter = new AstWriter(context.getWriter(), new DefaultGlobalNameWriter());
|
||||||
int paramIndex = 0;
|
int paramIndex = 0;
|
||||||
if (!isStatic) {
|
if (!isStatic) {
|
||||||
int index = paramIndex++;
|
int index = paramIndex++;
|
||||||
astWriter.declareNameEmitter("this", prec -> context.writeExpr(context.getArgument(index),
|
astWriter.declareNameEmitter("this", (w, prec) -> context.writeExpr(context.getArgument(index),
|
||||||
convert(prec)));
|
convert(prec)));
|
||||||
}
|
}
|
||||||
for (int i = 0; i < parameterNames.length; ++i) {
|
for (int i = 0; i < parameterNames.length; ++i) {
|
||||||
int index = paramIndex++;
|
int index = paramIndex++;
|
||||||
astWriter.declareNameEmitter(parameterNames[i],
|
astWriter.declareNameEmitter(parameterNames[i],
|
||||||
prec -> context.writeExpr(context.getArgument(index), convert(prec)));
|
(w, prec) -> context.writeExpr(context.getArgument(index), convert(prec)));
|
||||||
}
|
}
|
||||||
for (var importInfo : imports) {
|
for (var importInfo : imports) {
|
||||||
astWriter.declareNameEmitter(importInfo.alias,
|
astWriter.declareNameEmitter(importInfo.alias,
|
||||||
prec -> context.getWriter().appendFunction(context.importModule(importInfo.fromModule)));
|
(w, prec) -> context.getWriter().appendFunction(context.importModule(importInfo.fromModule)));
|
||||||
}
|
}
|
||||||
astWriter.hoist(rootAst);
|
astWriter.hoist(rootAst);
|
||||||
astWriter.print(ast, convert(context.getPrecedence()));
|
astWriter.print(ast, convert(context.getPrecedence()));
|
||||||
|
@ -148,19 +148,19 @@ class JSBodyAstEmitter implements JSBodyEmitter {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void emit(GeneratorContext context, SourceWriter writer, MethodReference methodRef) {
|
public void emit(GeneratorContext context, SourceWriter writer, MethodReference methodRef) {
|
||||||
var astWriter = new AstWriter(writer, new DefaultGlobalNameWriter(writer));
|
var astWriter = new AstWriter(writer, new DefaultGlobalNameWriter());
|
||||||
int paramIndex = 1;
|
int paramIndex = 1;
|
||||||
if (!isStatic) {
|
if (!isStatic) {
|
||||||
int index = paramIndex++;
|
int index = paramIndex++;
|
||||||
astWriter.declareNameEmitter("this", prec -> writer.append(context.getParameterName(index)));
|
astWriter.declareNameEmitter("this", (w, prec) -> w.append(context.getParameterName(index)));
|
||||||
}
|
}
|
||||||
for (var parameterName : parameterNames) {
|
for (var parameterName : parameterNames) {
|
||||||
int index = paramIndex++;
|
int index = paramIndex++;
|
||||||
astWriter.declareNameEmitter(parameterName, prec -> writer.append(context.getParameterName(index)));
|
astWriter.declareNameEmitter(parameterName, (w, prec) -> w.append(context.getParameterName(index)));
|
||||||
}
|
}
|
||||||
for (var importInfo : imports) {
|
for (var importInfo : imports) {
|
||||||
astWriter.declareNameEmitter(importInfo.alias,
|
astWriter.declareNameEmitter(importInfo.alias,
|
||||||
prec -> writer.appendFunction(context.importModule(importInfo.fromModule)));
|
(w, prec) -> w.appendFunction(context.importModule(importInfo.fromModule)));
|
||||||
}
|
}
|
||||||
astWriter.hoist(rootAst);
|
astWriter.hoist(rootAst);
|
||||||
if (ast instanceof Block) {
|
if (ast instanceof Block) {
|
||||||
|
|
Loading…
Reference in New Issue
Block a user