js: refactor and simplify AstWriter, properly fix case with variable in catch block

This commit is contained in:
Alexey Andreev 2024-03-06 20:24:35 +01:00
parent e4452152b7
commit ccfe19994b
8 changed files with 111 additions and 147 deletions

View File

@ -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;
} }
} }

View File

@ -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);
} }
} }

View File

@ -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);
} }

View File

@ -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);
} }

View File

@ -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);

View File

@ -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;
} }
} }

View File

@ -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

View File

@ -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) {