mirror of
https://github.com/konsoletyper/teavm.git
synced 2024-11-21 01:00:54 +08:00
JS: split SourceWriter into interface and implementation part
This commit is contained in:
parent
23ad999bbd
commit
8024d84ed5
@ -50,8 +50,8 @@ import org.teavm.backend.javascript.codegen.AliasProvider;
|
||||
import org.teavm.backend.javascript.codegen.DefaultAliasProvider;
|
||||
import org.teavm.backend.javascript.codegen.DefaultNamingStrategy;
|
||||
import org.teavm.backend.javascript.codegen.MinifyingAliasProvider;
|
||||
import org.teavm.backend.javascript.codegen.OutputSourceWriterBuilder;
|
||||
import org.teavm.backend.javascript.codegen.SourceWriter;
|
||||
import org.teavm.backend.javascript.codegen.SourceWriterBuilder;
|
||||
import org.teavm.backend.javascript.decompile.PreparedClass;
|
||||
import org.teavm.backend.javascript.decompile.PreparedMethod;
|
||||
import org.teavm.backend.javascript.intrinsics.ref.ReferenceQueueGenerator;
|
||||
@ -414,14 +414,16 @@ public class JavaScriptTarget implements TeaVMTarget, TeaVMJavaScriptHost {
|
||||
? new MinifyingAliasProvider(topLevelNameLimit)
|
||||
: new DefaultAliasProvider(topLevelNameLimit);
|
||||
DefaultNamingStrategy naming = new DefaultNamingStrategy(aliasProvider, controller.getUnprocessedClassSource());
|
||||
SourceWriterBuilder builder = new SourceWriterBuilder(naming);
|
||||
OutputSourceWriterBuilder builder = new OutputSourceWriterBuilder(naming);
|
||||
builder.setMinified(obfuscated);
|
||||
SourceWriter sourceWriter = builder.build(writer);
|
||||
var sourceWriter = builder.build(writer);
|
||||
|
||||
DebugInformationEmitter debugEmitterToUse = debugEmitter;
|
||||
if (debugEmitterToUse == null) {
|
||||
debugEmitterToUse = new DummyDebugInformationEmitter();
|
||||
}
|
||||
sourceWriter.setDebugInformationEmitter(debugEmitterToUse);
|
||||
|
||||
var virtualMethodContributorContext = new VirtualMethodContributorContextImpl(classes);
|
||||
RenderingContext renderingContext = new RenderingContext(debugEmitterToUse,
|
||||
controller.getUnprocessedClassSource(), classes,
|
||||
@ -454,7 +456,6 @@ public class JavaScriptTarget implements TeaVMTarget, TeaVMJavaScriptHost {
|
||||
}
|
||||
renderer.setDebugEmitter(debugEmitter);
|
||||
}
|
||||
renderer.getDebugEmitter().setLocationProvider(sourceWriter);
|
||||
for (var entry : methodInjectors.entrySet()) {
|
||||
renderingContext.addInjector(entry.getKey(), entry.getValue());
|
||||
}
|
||||
|
@ -0,0 +1,279 @@
|
||||
/*
|
||||
* Copyright 2023 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.backend.javascript.codegen;
|
||||
|
||||
import java.io.IOException;
|
||||
import org.teavm.debugging.information.DebugInformationEmitter;
|
||||
import org.teavm.debugging.information.DummyDebugInformationEmitter;
|
||||
import org.teavm.model.FieldReference;
|
||||
import org.teavm.model.MethodDescriptor;
|
||||
import org.teavm.model.MethodReference;
|
||||
|
||||
public class OutputSourceWriter extends SourceWriter implements LocationProvider {
|
||||
private final Appendable innerWriter;
|
||||
private int indentSize;
|
||||
private final NamingStrategy naming;
|
||||
private boolean lineStart;
|
||||
private boolean minified;
|
||||
private final int lineWidth;
|
||||
private int column;
|
||||
private int line;
|
||||
private int offset;
|
||||
private DebugInformationEmitter debugInformationEmitter = new DummyDebugInformationEmitter();
|
||||
|
||||
OutputSourceWriter(NamingStrategy naming, Appendable innerWriter, int lineWidth) {
|
||||
this.naming = naming;
|
||||
this.innerWriter = innerWriter;
|
||||
this.lineWidth = lineWidth;
|
||||
}
|
||||
|
||||
public void setDebugInformationEmitter(DebugInformationEmitter debugInformationEmitter) {
|
||||
this.debugInformationEmitter = debugInformationEmitter;
|
||||
debugInformationEmitter.setLocationProvider(this);
|
||||
}
|
||||
|
||||
void setMinified(boolean minified) {
|
||||
this.minified = minified;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SourceWriter append(char value) {
|
||||
appendIndent();
|
||||
try {
|
||||
innerWriter.append(value);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
if (value == '\n') {
|
||||
newLine();
|
||||
} else {
|
||||
column++;
|
||||
offset++;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SourceWriter append(CharSequence csq, int start, int end) {
|
||||
int last = start;
|
||||
for (int i = start; i < end; ++i) {
|
||||
if (csq.charAt(i) == '\n') {
|
||||
appendSingleLine(csq, last, i);
|
||||
newLine();
|
||||
last = i + 1;
|
||||
}
|
||||
}
|
||||
appendSingleLine(csq, last, end);
|
||||
return this;
|
||||
}
|
||||
|
||||
private void appendSingleLine(CharSequence csq, int start, int end) {
|
||||
if (start == end) {
|
||||
return;
|
||||
}
|
||||
appendIndent();
|
||||
column += end - start;
|
||||
offset += end - start;
|
||||
try {
|
||||
innerWriter.append(csq, start, end);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public SourceWriter appendClass(String cls) {
|
||||
return appendName(naming.getNameFor(cls));
|
||||
}
|
||||
|
||||
@Override
|
||||
public SourceWriter appendField(FieldReference field) {
|
||||
return append(naming.getNameFor(field));
|
||||
}
|
||||
|
||||
@Override
|
||||
public SourceWriter appendStaticField(FieldReference field) {
|
||||
return appendName(naming.getFullNameFor(field));
|
||||
}
|
||||
|
||||
@Override
|
||||
public SourceWriter appendMethod(MethodDescriptor method) {
|
||||
return append(naming.getNameFor(method));
|
||||
}
|
||||
|
||||
@Override
|
||||
public SourceWriter appendMethodBody(MethodReference method) {
|
||||
return appendName(naming.getFullNameFor(method));
|
||||
}
|
||||
|
||||
@Override
|
||||
public SourceWriter appendFunction(String name) {
|
||||
return append(naming.getNameForFunction(name));
|
||||
}
|
||||
|
||||
@Override
|
||||
public SourceWriter appendInit(MethodReference method) {
|
||||
return appendName(naming.getNameForInit(method));
|
||||
}
|
||||
|
||||
@Override
|
||||
public SourceWriter appendClassInit(String className) {
|
||||
return appendName(naming.getNameForClassInit(className));
|
||||
}
|
||||
|
||||
private SourceWriter appendName(ScopedName name) {
|
||||
if (name.scoped) {
|
||||
append(naming.getScopeName()).append(".");
|
||||
}
|
||||
append(name.value);
|
||||
return this;
|
||||
}
|
||||
|
||||
private void appendIndent() {
|
||||
if (minified) {
|
||||
return;
|
||||
}
|
||||
if (lineStart) {
|
||||
try {
|
||||
for (int i = 0; i < indentSize; ++i) {
|
||||
innerWriter.append(" ");
|
||||
column += 4;
|
||||
offset += 4;
|
||||
}
|
||||
lineStart = false;
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public SourceWriter newLine() {
|
||||
try {
|
||||
innerWriter.append('\n');
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
column = 0;
|
||||
++line;
|
||||
++offset;
|
||||
lineStart = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SourceWriter ws() {
|
||||
if (column >= lineWidth) {
|
||||
newLine();
|
||||
} else {
|
||||
if (!minified) {
|
||||
try {
|
||||
innerWriter.append(' ');
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
column++;
|
||||
offset++;
|
||||
}
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SourceWriter tokenBoundary() {
|
||||
if (column >= lineWidth) {
|
||||
newLine();
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SourceWriter softNewLine() {
|
||||
if (!minified) {
|
||||
try {
|
||||
innerWriter.append('\n');
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
column = 0;
|
||||
++offset;
|
||||
++line;
|
||||
lineStart = true;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SourceWriter indent() {
|
||||
++indentSize;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SourceWriter outdent() {
|
||||
--indentSize;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SourceWriter emitLocation(String fileName, int line) {
|
||||
debugInformationEmitter.emitLocation(fileName, line);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SourceWriter enterLocation() {
|
||||
debugInformationEmitter.enterLocation();
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SourceWriter exitLocation() {
|
||||
debugInformationEmitter.exitLocation();
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SourceWriter emitStatementStart() {
|
||||
debugInformationEmitter.emitStatementStart();
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void emitMethod(MethodDescriptor method) {
|
||||
debugInformationEmitter.emitMethod(method);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void emitClass(String className) {
|
||||
debugInformationEmitter.emitClass(className);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLine() {
|
||||
return line;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getColumn() {
|
||||
return column;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getOffset() {
|
||||
return offset;
|
||||
}
|
||||
}
|
@ -15,12 +15,12 @@
|
||||
*/
|
||||
package org.teavm.backend.javascript.codegen;
|
||||
|
||||
public class SourceWriterBuilder {
|
||||
public class OutputSourceWriterBuilder {
|
||||
private NamingStrategy naming;
|
||||
private boolean minified;
|
||||
private int lineWidth = 512;
|
||||
|
||||
public SourceWriterBuilder(NamingStrategy naming) {
|
||||
public OutputSourceWriterBuilder(NamingStrategy naming) {
|
||||
this.naming = naming;
|
||||
}
|
||||
|
||||
@ -36,8 +36,8 @@ public class SourceWriterBuilder {
|
||||
this.lineWidth = lineWidth;
|
||||
}
|
||||
|
||||
public SourceWriter build(Appendable innerWriter) {
|
||||
SourceWriter writer = new SourceWriter(naming, innerWriter, lineWidth);
|
||||
public OutputSourceWriter build(Appendable innerWriter) {
|
||||
var writer = new OutputSourceWriter(naming, innerWriter, lineWidth);
|
||||
writer.setMinified(minified);
|
||||
return writer;
|
||||
}
|
@ -15,33 +15,12 @@
|
||||
*/
|
||||
package org.teavm.backend.javascript.codegen;
|
||||
|
||||
import java.io.IOException;
|
||||
import org.teavm.model.FieldReference;
|
||||
import org.teavm.model.MethodDescriptor;
|
||||
import org.teavm.model.MethodReference;
|
||||
import org.teavm.model.ValueType;
|
||||
|
||||
public class SourceWriter implements Appendable, LocationProvider {
|
||||
private final Appendable innerWriter;
|
||||
private int indentSize;
|
||||
private final NamingStrategy naming;
|
||||
private boolean lineStart;
|
||||
private boolean minified;
|
||||
private final int lineWidth;
|
||||
private int column;
|
||||
private int line;
|
||||
private int offset;
|
||||
|
||||
SourceWriter(NamingStrategy naming, Appendable innerWriter, int lineWidth) {
|
||||
this.naming = naming;
|
||||
this.innerWriter = innerWriter;
|
||||
this.lineWidth = lineWidth;
|
||||
}
|
||||
|
||||
void setMinified(boolean minified) {
|
||||
this.minified = minified;
|
||||
}
|
||||
|
||||
public abstract class SourceWriter implements Appendable {
|
||||
public SourceWriter append(String value) {
|
||||
append((CharSequence) value);
|
||||
return this;
|
||||
@ -72,21 +51,7 @@ public class SourceWriter implements Appendable, LocationProvider {
|
||||
}
|
||||
|
||||
@Override
|
||||
public SourceWriter append(char value) {
|
||||
appendIndent();
|
||||
try {
|
||||
innerWriter.append(value);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
if (value == '\n') {
|
||||
newLine();
|
||||
} else {
|
||||
column++;
|
||||
offset++;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
public abstract SourceWriter append(char value);
|
||||
|
||||
@Override
|
||||
public SourceWriter append(CharSequence csq) {
|
||||
@ -95,60 +60,25 @@ public class SourceWriter implements Appendable, LocationProvider {
|
||||
}
|
||||
|
||||
@Override
|
||||
public SourceWriter append(CharSequence csq, int start, int end) {
|
||||
int last = start;
|
||||
for (int i = start; i < end; ++i) {
|
||||
if (csq.charAt(i) == '\n') {
|
||||
appendSingleLine(csq, last, i);
|
||||
newLine();
|
||||
last = i + 1;
|
||||
}
|
||||
}
|
||||
appendSingleLine(csq, last, end);
|
||||
return this;
|
||||
}
|
||||
public abstract SourceWriter append(CharSequence csq, int start, int end);
|
||||
|
||||
private void appendSingleLine(CharSequence csq, int start, int end) {
|
||||
if (start == end) {
|
||||
return;
|
||||
}
|
||||
appendIndent();
|
||||
column += end - start;
|
||||
offset += end - start;
|
||||
try {
|
||||
innerWriter.append(csq, start, end);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public SourceWriter appendClass(String cls) {
|
||||
return appendName(naming.getNameFor(cls));
|
||||
}
|
||||
public abstract SourceWriter appendClass(String cls);
|
||||
|
||||
public SourceWriter appendClass(Class<?> cls) {
|
||||
return appendClass(cls.getName());
|
||||
}
|
||||
|
||||
public SourceWriter appendField(FieldReference field) {
|
||||
return append(naming.getNameFor(field));
|
||||
}
|
||||
public abstract SourceWriter appendField(FieldReference field);
|
||||
|
||||
public SourceWriter appendStaticField(FieldReference field) {
|
||||
return appendName(naming.getFullNameFor(field));
|
||||
}
|
||||
public abstract SourceWriter appendStaticField(FieldReference field);
|
||||
|
||||
public SourceWriter appendMethod(MethodDescriptor method) {
|
||||
return append(naming.getNameFor(method));
|
||||
}
|
||||
public abstract SourceWriter appendMethod(MethodDescriptor method);
|
||||
|
||||
public SourceWriter appendMethod(String name, Class<?>... params) {
|
||||
return append(naming.getNameFor(new MethodDescriptor(name, params)));
|
||||
return appendMethod(new MethodDescriptor(name, params));
|
||||
}
|
||||
|
||||
public SourceWriter appendMethodBody(MethodReference method) {
|
||||
return appendName(naming.getFullNameFor(method));
|
||||
}
|
||||
public abstract SourceWriter appendMethodBody(MethodReference method);
|
||||
|
||||
public SourceWriter appendMethodBody(String className, String name, ValueType... params) {
|
||||
return appendMethodBody(new MethodReference(className, new MethodDescriptor(name, params)));
|
||||
@ -158,122 +88,33 @@ public class SourceWriter implements Appendable, LocationProvider {
|
||||
return appendMethodBody(new MethodReference(cls, name, params));
|
||||
}
|
||||
|
||||
public SourceWriter appendFunction(String name) {
|
||||
return append(naming.getNameForFunction(name));
|
||||
}
|
||||
public abstract SourceWriter appendFunction(String name);
|
||||
|
||||
public SourceWriter appendInit(MethodReference method) {
|
||||
return appendName(naming.getNameForInit(method));
|
||||
}
|
||||
public abstract SourceWriter appendInit(MethodReference method);
|
||||
|
||||
public SourceWriter appendClassInit(String className) {
|
||||
return appendName(naming.getNameForClassInit(className));
|
||||
}
|
||||
public abstract SourceWriter appendClassInit(String className);
|
||||
|
||||
private SourceWriter appendName(ScopedName name) {
|
||||
if (name.scoped) {
|
||||
append(naming.getScopeName()).append(".");
|
||||
}
|
||||
append(name.value);
|
||||
return this;
|
||||
}
|
||||
public abstract SourceWriter newLine();
|
||||
|
||||
private void appendIndent() {
|
||||
if (minified) {
|
||||
return;
|
||||
}
|
||||
if (lineStart) {
|
||||
try {
|
||||
for (int i = 0; i < indentSize; ++i) {
|
||||
innerWriter.append(" ");
|
||||
column += 4;
|
||||
offset += 4;
|
||||
}
|
||||
lineStart = false;
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
public abstract SourceWriter ws();
|
||||
|
||||
public SourceWriter newLine() {
|
||||
try {
|
||||
innerWriter.append('\n');
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
column = 0;
|
||||
++line;
|
||||
++offset;
|
||||
lineStart = true;
|
||||
return this;
|
||||
}
|
||||
public abstract SourceWriter tokenBoundary();
|
||||
|
||||
public SourceWriter ws() {
|
||||
if (column >= lineWidth) {
|
||||
newLine();
|
||||
} else {
|
||||
if (!minified) {
|
||||
try {
|
||||
innerWriter.append(' ');
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
column++;
|
||||
offset++;
|
||||
}
|
||||
}
|
||||
return this;
|
||||
}
|
||||
public abstract SourceWriter softNewLine();
|
||||
|
||||
public SourceWriter tokenBoundary() {
|
||||
if (column >= lineWidth) {
|
||||
newLine();
|
||||
}
|
||||
return this;
|
||||
}
|
||||
public abstract SourceWriter indent();
|
||||
|
||||
public SourceWriter softNewLine() {
|
||||
if (!minified) {
|
||||
try {
|
||||
innerWriter.append('\n');
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
column = 0;
|
||||
++offset;
|
||||
++line;
|
||||
lineStart = true;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
public abstract SourceWriter outdent();
|
||||
|
||||
public SourceWriter indent() {
|
||||
++indentSize;
|
||||
return this;
|
||||
}
|
||||
public abstract SourceWriter emitLocation(String fileName, int line);
|
||||
|
||||
public SourceWriter outdent() {
|
||||
--indentSize;
|
||||
return this;
|
||||
}
|
||||
public abstract SourceWriter enterLocation();
|
||||
|
||||
public NamingStrategy getNaming() {
|
||||
return naming;
|
||||
}
|
||||
public abstract SourceWriter exitLocation();
|
||||
|
||||
@Override
|
||||
public int getColumn() {
|
||||
return column;
|
||||
}
|
||||
public abstract SourceWriter emitStatementStart();
|
||||
|
||||
@Override
|
||||
public int getLine() {
|
||||
return line;
|
||||
}
|
||||
public abstract void emitMethod(MethodDescriptor method);
|
||||
|
||||
@Override
|
||||
public int getOffset() {
|
||||
return offset;
|
||||
}
|
||||
public abstract void emitClass(String className);
|
||||
}
|
||||
|
@ -37,6 +37,7 @@ import org.teavm.ast.Statement;
|
||||
import org.teavm.ast.VariableNode;
|
||||
import org.teavm.backend.javascript.codegen.NamingOrderer;
|
||||
import org.teavm.backend.javascript.codegen.NamingStrategy;
|
||||
import org.teavm.backend.javascript.codegen.OutputSourceWriter;
|
||||
import org.teavm.backend.javascript.codegen.ScopedName;
|
||||
import org.teavm.backend.javascript.codegen.SourceWriter;
|
||||
import org.teavm.backend.javascript.decompile.PreparedClass;
|
||||
@ -64,7 +65,7 @@ import org.teavm.vm.TeaVMProgressFeedback;
|
||||
|
||||
public class Renderer implements RenderingManager {
|
||||
private final NamingStrategy naming;
|
||||
private final SourceWriter writer;
|
||||
private final OutputSourceWriter writer;
|
||||
private final ListableClassReaderSource classSource;
|
||||
private final ClassLoader classLoader;
|
||||
private boolean minifying;
|
||||
@ -86,8 +87,8 @@ public class Renderer implements RenderingManager {
|
||||
private boolean longLibraryUsed;
|
||||
private boolean threadLibraryUsed;
|
||||
|
||||
public Renderer(SourceWriter writer, Set<MethodReference> asyncMethods, Set<MethodReference> asyncFamilyMethods,
|
||||
Diagnostics diagnostics, RenderingContext context) {
|
||||
public Renderer(OutputSourceWriter writer, Set<MethodReference> asyncMethods,
|
||||
Set<MethodReference> asyncFamilyMethods, Diagnostics diagnostics, RenderingContext context) {
|
||||
this.naming = context.getNaming();
|
||||
this.writer = writer;
|
||||
this.classSource = context.getClassSource();
|
||||
|
@ -17,14 +17,11 @@ package org.teavm.backend.javascript.rendering;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Deque;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Properties;
|
||||
import java.util.function.Predicate;
|
||||
import org.teavm.backend.javascript.codegen.NamingStrategy;
|
||||
@ -38,11 +35,9 @@ import org.teavm.interop.PlatformMarker;
|
||||
import org.teavm.model.AnnotationReader;
|
||||
import org.teavm.model.ClassReader;
|
||||
import org.teavm.model.ClassReaderSource;
|
||||
import org.teavm.model.InliningInfo;
|
||||
import org.teavm.model.ListableClassReaderSource;
|
||||
import org.teavm.model.MethodReader;
|
||||
import org.teavm.model.MethodReference;
|
||||
import org.teavm.model.TextLocation;
|
||||
import org.teavm.model.ValueType;
|
||||
import org.teavm.model.analysis.ClassInitializerInfo;
|
||||
|
||||
@ -56,14 +51,12 @@ public abstract class RenderingContext {
|
||||
private NamingStrategy naming;
|
||||
private DependencyInfo dependencyInfo;
|
||||
private Predicate<MethodReference> virtualPredicate;
|
||||
private final Deque<LocationStackEntry> locationStack = new ArrayDeque<>();
|
||||
private final Map<String, Integer> stringPoolMap = new HashMap<>();
|
||||
private final List<String> stringPool = new ArrayList<>();
|
||||
private final List<String> readonlyStringPool = Collections.unmodifiableList(stringPool);
|
||||
private final Map<MethodReference, InjectorHolder> injectorMap = new HashMap<>();
|
||||
private boolean minifying;
|
||||
private ClassInitializerInfo classInitializerInfo;
|
||||
private TextLocation lastEmittedLocation = TextLocation.EMPTY;
|
||||
private boolean strict;
|
||||
|
||||
public RenderingContext(DebugInformationEmitter debugEmitter,
|
||||
@ -129,83 +122,6 @@ public abstract class RenderingContext {
|
||||
return classInitializerInfo.isDynamicInitializer(className);
|
||||
}
|
||||
|
||||
public void pushLocation(TextLocation location) {
|
||||
LocationStackEntry prevEntry = locationStack.peek();
|
||||
if (location != null) {
|
||||
if (prevEntry == null || !location.equals(prevEntry.location)) {
|
||||
emitLocation(location);
|
||||
}
|
||||
} else {
|
||||
if (prevEntry != null) {
|
||||
emitLocation(TextLocation.EMPTY);
|
||||
}
|
||||
}
|
||||
locationStack.push(new LocationStackEntry(location));
|
||||
}
|
||||
|
||||
public void popLocation() {
|
||||
LocationStackEntry prevEntry = locationStack.pop();
|
||||
LocationStackEntry entry = locationStack.peek();
|
||||
if (entry != null) {
|
||||
if (!entry.location.equals(prevEntry.location)) {
|
||||
emitLocation(entry.location);
|
||||
}
|
||||
} else {
|
||||
emitLocation(TextLocation.EMPTY);
|
||||
}
|
||||
}
|
||||
|
||||
private void emitLocation(TextLocation location) {
|
||||
if (lastEmittedLocation.equals(location)) {
|
||||
return;
|
||||
}
|
||||
|
||||
String fileName = lastEmittedLocation.getFileName();
|
||||
int lineNumber = lastEmittedLocation.getLine();
|
||||
if (lastEmittedLocation.getInlining() != location.getInlining()) {
|
||||
InliningInfo[] newPath = location.getInliningPath();
|
||||
InliningInfo[] prevPath = lastEmittedLocation.getInliningPath();
|
||||
|
||||
InliningInfo lastCommonInlining = null;
|
||||
int pathIndex = 0;
|
||||
while (pathIndex < prevPath.length && pathIndex < newPath.length
|
||||
&& prevPath[pathIndex].equals(newPath[pathIndex])) {
|
||||
lastCommonInlining = prevPath[pathIndex++];
|
||||
}
|
||||
|
||||
InliningInfo prevInlining = lastEmittedLocation.getInlining();
|
||||
while (prevInlining != lastCommonInlining) {
|
||||
debugEmitter.exitLocation();
|
||||
fileName = prevInlining.getFileName();
|
||||
lineNumber = prevInlining.getLine();
|
||||
prevInlining = prevInlining.getParent();
|
||||
}
|
||||
|
||||
while (pathIndex < newPath.length) {
|
||||
InliningInfo inlining = newPath[pathIndex++];
|
||||
emitSimpleLocation(fileName, lineNumber, inlining.getFileName(), inlining.getLine());
|
||||
fileName = null;
|
||||
lineNumber = -1;
|
||||
|
||||
debugEmitter.enterLocation();
|
||||
debugEmitter.emitClass(inlining.getMethod().getClassName());
|
||||
debugEmitter.emitMethod(inlining.getMethod().getDescriptor());
|
||||
}
|
||||
}
|
||||
|
||||
emitSimpleLocation(fileName, lineNumber, location.getFileName(), location.getLine());
|
||||
lastEmittedLocation = location;
|
||||
}
|
||||
|
||||
|
||||
private void emitSimpleLocation(String fileName, int lineNumber, String newFileName, int newLineNumber) {
|
||||
if (Objects.equals(fileName, newFileName) && lineNumber == newLineNumber) {
|
||||
return;
|
||||
}
|
||||
|
||||
debugEmitter.emitLocation(newFileName, newLineNumber);
|
||||
}
|
||||
|
||||
public boolean isMinifying() {
|
||||
return minifying;
|
||||
}
|
||||
@ -367,14 +283,6 @@ public abstract class RenderingContext {
|
||||
return minifying ? "$T" : "$thread";
|
||||
}
|
||||
|
||||
private static class LocationStackEntry {
|
||||
final TextLocation location;
|
||||
|
||||
LocationStackEntry(TextLocation location) {
|
||||
this.location = location;
|
||||
}
|
||||
}
|
||||
|
||||
public void addInjector(MethodReference method, Injector injector) {
|
||||
injectorMap.put(method, new InjectorHolder(injector));
|
||||
}
|
||||
|
@ -17,11 +17,14 @@ package org.teavm.backend.javascript.rendering;
|
||||
|
||||
import com.carrotsearch.hppc.IntArrayList;
|
||||
import com.carrotsearch.hppc.IntIndexedContainer;
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Deque;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Properties;
|
||||
import org.teavm.ast.ArrayFromDataExpr;
|
||||
import org.teavm.ast.AssignmentStatement;
|
||||
@ -68,11 +71,10 @@ import org.teavm.backend.javascript.codegen.NamingStrategy;
|
||||
import org.teavm.backend.javascript.codegen.SourceWriter;
|
||||
import org.teavm.backend.javascript.spi.Injector;
|
||||
import org.teavm.backend.javascript.spi.InjectorContext;
|
||||
import org.teavm.debugging.information.DebugInformationEmitter;
|
||||
import org.teavm.debugging.information.DeferredCallSite;
|
||||
import org.teavm.model.ClassReader;
|
||||
import org.teavm.model.ClassReaderSource;
|
||||
import org.teavm.model.ElementModifier;
|
||||
import org.teavm.model.InliningInfo;
|
||||
import org.teavm.model.ListableClassReaderSource;
|
||||
import org.teavm.model.MethodDescriptor;
|
||||
import org.teavm.model.MethodReader;
|
||||
@ -88,10 +90,7 @@ public class StatementRenderer implements ExprVisitor, StatementVisitor {
|
||||
private boolean async;
|
||||
private boolean minifying;
|
||||
private Precedence precedence;
|
||||
private DebugInformationEmitter debugEmitter;
|
||||
private NamingStrategy naming;
|
||||
private DeferredCallSite lastCallSite;
|
||||
private DeferredCallSite prevCallSite;
|
||||
private boolean end;
|
||||
private final Map<String, String> blockIdMap = new HashMap<>();
|
||||
private int currentPart;
|
||||
@ -100,6 +99,8 @@ public class StatementRenderer implements ExprVisitor, StatementVisitor {
|
||||
private boolean longLibraryUsed;
|
||||
private static final MethodDescriptor CLINIT_METHOD = new MethodDescriptor("<clinit>", ValueType.VOID);
|
||||
private VariableNameGenerator variableNameGenerator;
|
||||
private final Deque<LocationStackEntry> locationStack = new ArrayDeque<>();
|
||||
private TextLocation lastEmittedLocation = TextLocation.EMPTY;
|
||||
|
||||
public StatementRenderer(RenderingContext context, SourceWriter writer) {
|
||||
this.context = context;
|
||||
@ -107,7 +108,6 @@ public class StatementRenderer implements ExprVisitor, StatementVisitor {
|
||||
this.classSource = context.getClassSource();
|
||||
this.minifying = context.isMinifying();
|
||||
this.naming = context.getNaming();
|
||||
this.debugEmitter = context.getDebugEmitter();
|
||||
variableNameGenerator = new VariableNameGenerator(minifying);
|
||||
}
|
||||
|
||||
@ -135,21 +135,88 @@ public class StatementRenderer implements ExprVisitor, StatementVisitor {
|
||||
this.end = end;
|
||||
}
|
||||
|
||||
private void pushLocation(TextLocation location) {
|
||||
context.pushLocation(location);
|
||||
public void pushLocation(TextLocation location) {
|
||||
var prevEntry = locationStack.peek();
|
||||
if (location != null) {
|
||||
if (prevEntry == null || !location.equals(prevEntry.location)) {
|
||||
emitLocation(location);
|
||||
}
|
||||
} else {
|
||||
if (prevEntry != null) {
|
||||
emitLocation(TextLocation.EMPTY);
|
||||
}
|
||||
}
|
||||
locationStack.push(new LocationStackEntry(location));
|
||||
}
|
||||
|
||||
private void popLocation() {
|
||||
context.popLocation();
|
||||
public void popLocation() {
|
||||
var prevEntry = locationStack.pop();
|
||||
var entry = locationStack.peek();
|
||||
if (entry != null) {
|
||||
if (!entry.location.equals(prevEntry.location)) {
|
||||
emitLocation(entry.location);
|
||||
}
|
||||
} else {
|
||||
emitLocation(TextLocation.EMPTY);
|
||||
}
|
||||
}
|
||||
|
||||
private void emitLocation(TextLocation location) {
|
||||
if (lastEmittedLocation.equals(location)) {
|
||||
return;
|
||||
}
|
||||
|
||||
String fileName = lastEmittedLocation.getFileName();
|
||||
int lineNumber = lastEmittedLocation.getLine();
|
||||
if (lastEmittedLocation.getInlining() != location.getInlining()) {
|
||||
InliningInfo[] newPath = location.getInliningPath();
|
||||
InliningInfo[] prevPath = lastEmittedLocation.getInliningPath();
|
||||
|
||||
InliningInfo lastCommonInlining = null;
|
||||
int pathIndex = 0;
|
||||
while (pathIndex < prevPath.length && pathIndex < newPath.length
|
||||
&& prevPath[pathIndex].equals(newPath[pathIndex])) {
|
||||
lastCommonInlining = prevPath[pathIndex++];
|
||||
}
|
||||
|
||||
InliningInfo prevInlining = lastEmittedLocation.getInlining();
|
||||
while (prevInlining != lastCommonInlining) {
|
||||
writer.exitLocation();
|
||||
fileName = prevInlining.getFileName();
|
||||
lineNumber = prevInlining.getLine();
|
||||
prevInlining = prevInlining.getParent();
|
||||
}
|
||||
|
||||
while (pathIndex < newPath.length) {
|
||||
InliningInfo inlining = newPath[pathIndex++];
|
||||
emitSimpleLocation(fileName, lineNumber, inlining.getFileName(), inlining.getLine());
|
||||
fileName = null;
|
||||
lineNumber = -1;
|
||||
|
||||
writer.enterLocation();
|
||||
writer.emitClass(inlining.getMethod().getClassName());
|
||||
writer.emitMethod(inlining.getMethod().getDescriptor());
|
||||
}
|
||||
}
|
||||
|
||||
emitSimpleLocation(fileName, lineNumber, location.getFileName(), location.getLine());
|
||||
lastEmittedLocation = location;
|
||||
}
|
||||
|
||||
private void emitSimpleLocation(String fileName, int lineNumber, String newFileName, int newLineNumber) {
|
||||
if (Objects.equals(fileName, newFileName) && lineNumber == newLineNumber) {
|
||||
return;
|
||||
}
|
||||
|
||||
writer.emitLocation(newFileName, newLineNumber);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(AssignmentStatement statement) throws RenderingException {
|
||||
debugEmitter.emitStatementStart();
|
||||
writer.emitStatementStart();
|
||||
if (statement.getLocation() != null) {
|
||||
pushLocation(statement.getLocation());
|
||||
}
|
||||
prevCallSite = debugEmitter.emitCallSite();
|
||||
if (statement.getLeftValue() != null) {
|
||||
if (statement.isAsync()) {
|
||||
writer.append(context.tempVarName());
|
||||
@ -161,7 +228,6 @@ public class StatementRenderer implements ExprVisitor, StatementVisitor {
|
||||
}
|
||||
precedence = Precedence.COMMA;
|
||||
statement.getRightValue().acceptVisitor(this);
|
||||
debugEmitter.emitCallSite();
|
||||
writer.append(";").softNewLine();
|
||||
if (statement.isAsync()) {
|
||||
emitSuspendChecker();
|
||||
@ -185,18 +251,16 @@ public class StatementRenderer implements ExprVisitor, StatementVisitor {
|
||||
public void visit(ConditionalStatement statement) {
|
||||
boolean needClosingBracket;
|
||||
while (true) {
|
||||
debugEmitter.emitStatementStart();
|
||||
writer.emitStatementStart();
|
||||
if (statement.getCondition().getLocation() != null) {
|
||||
pushLocation(statement.getCondition().getLocation());
|
||||
}
|
||||
prevCallSite = debugEmitter.emitCallSite();
|
||||
writer.append("if").ws().append("(");
|
||||
precedence = Precedence.COMMA;
|
||||
statement.getCondition().acceptVisitor(this);
|
||||
if (statement.getCondition().getLocation() != null) {
|
||||
popLocation();
|
||||
}
|
||||
debugEmitter.emitCallSite();
|
||||
writer.append(")");
|
||||
if (isSimpleIfContent(statement.getConsequent())) {
|
||||
needClosingBracket = false;
|
||||
@ -250,21 +314,19 @@ public class StatementRenderer implements ExprVisitor, StatementVisitor {
|
||||
|
||||
@Override
|
||||
public void visit(SwitchStatement statement) {
|
||||
debugEmitter.emitStatementStart();
|
||||
writer.emitStatementStart();
|
||||
if (statement.getValue().getLocation() != null) {
|
||||
pushLocation(statement.getValue().getLocation());
|
||||
}
|
||||
if (statement.getId() != null) {
|
||||
writer.append(mapBlockId(statement.getId())).append(":").ws();
|
||||
}
|
||||
prevCallSite = debugEmitter.emitCallSite();
|
||||
writer.append("switch").ws().append("(");
|
||||
precedence = Precedence.min();
|
||||
statement.getValue().acceptVisitor(this);
|
||||
if (statement.getValue().getLocation() != null) {
|
||||
popLocation();
|
||||
}
|
||||
debugEmitter.emitCallSite();
|
||||
writer.append(")").ws().append("{").softNewLine().indent();
|
||||
for (SwitchClause clause : statement.getClauses()) {
|
||||
for (int condition : clause.getConditions()) {
|
||||
@ -294,17 +356,15 @@ public class StatementRenderer implements ExprVisitor, StatementVisitor {
|
||||
|
||||
@Override
|
||||
public void visit(WhileStatement statement) {
|
||||
debugEmitter.emitStatementStart();
|
||||
writer.emitStatementStart();
|
||||
if (statement.getId() != null) {
|
||||
writer.append(mapBlockId(statement.getId())).append(":").ws();
|
||||
}
|
||||
writer.append("while");
|
||||
writer.ws().append("(");
|
||||
if (statement.getCondition() != null) {
|
||||
prevCallSite = debugEmitter.emitCallSite();
|
||||
precedence = Precedence.min();
|
||||
statement.getCondition().acceptVisitor(this);
|
||||
debugEmitter.emitCallSite();
|
||||
} else {
|
||||
writer.append("true");
|
||||
}
|
||||
@ -351,7 +411,7 @@ public class StatementRenderer implements ExprVisitor, StatementVisitor {
|
||||
|
||||
@Override
|
||||
public void visit(BreakStatement statement) {
|
||||
debugEmitter.emitStatementStart();
|
||||
writer.emitStatementStart();
|
||||
if (statement.getLocation() != null) {
|
||||
pushLocation(statement.getLocation());
|
||||
}
|
||||
@ -367,7 +427,7 @@ public class StatementRenderer implements ExprVisitor, StatementVisitor {
|
||||
|
||||
@Override
|
||||
public void visit(ContinueStatement statement) {
|
||||
debugEmitter.emitStatementStart();
|
||||
writer.emitStatementStart();
|
||||
if (statement.getLocation() != null) {
|
||||
pushLocation(statement.getLocation());
|
||||
}
|
||||
@ -383,17 +443,15 @@ public class StatementRenderer implements ExprVisitor, StatementVisitor {
|
||||
|
||||
@Override
|
||||
public void visit(ReturnStatement statement) {
|
||||
debugEmitter.emitStatementStart();
|
||||
writer.emitStatementStart();
|
||||
if (statement.getLocation() != null) {
|
||||
pushLocation(statement.getLocation());
|
||||
}
|
||||
writer.append("return");
|
||||
if (statement.getResult() != null) {
|
||||
writer.append(' ');
|
||||
prevCallSite = debugEmitter.emitCallSite();
|
||||
precedence = Precedence.min();
|
||||
statement.getResult().acceptVisitor(this);
|
||||
debugEmitter.emitCallSite();
|
||||
}
|
||||
writer.append(";").softNewLine();
|
||||
if (statement.getLocation() != null) {
|
||||
@ -403,16 +461,14 @@ public class StatementRenderer implements ExprVisitor, StatementVisitor {
|
||||
|
||||
@Override
|
||||
public void visit(ThrowStatement statement) {
|
||||
debugEmitter.emitStatementStart();
|
||||
writer.emitStatementStart();
|
||||
if (statement.getLocation() != null) {
|
||||
pushLocation(statement.getLocation());
|
||||
}
|
||||
writer.appendFunction("$rt_throw").append("(");
|
||||
prevCallSite = debugEmitter.emitCallSite();
|
||||
precedence = Precedence.min();
|
||||
statement.getException().acceptVisitor(this);
|
||||
writer.append(");").softNewLine();
|
||||
debugEmitter.emitCallSite();
|
||||
if (statement.getLocation() != null) {
|
||||
popLocation();
|
||||
}
|
||||
@ -428,7 +484,7 @@ public class StatementRenderer implements ExprVisitor, StatementVisitor {
|
||||
if (method == null) {
|
||||
return;
|
||||
}
|
||||
debugEmitter.emitStatementStart();
|
||||
writer.emitStatementStart();
|
||||
if (statement.getLocation() != null) {
|
||||
pushLocation(statement.getLocation());
|
||||
}
|
||||
@ -1040,16 +1096,9 @@ public class StatementRenderer implements ExprVisitor, StatementVisitor {
|
||||
}
|
||||
MethodReference method = expr.getMethod();
|
||||
String name = naming.getNameFor(method.getDescriptor());
|
||||
DeferredCallSite callSite = prevCallSite;
|
||||
boolean shouldEraseCallSite = lastCallSite == null;
|
||||
if (lastCallSite == null) {
|
||||
lastCallSite = callSite;
|
||||
}
|
||||
boolean virtual = false;
|
||||
switch (expr.getType()) {
|
||||
case STATIC:
|
||||
writer.appendMethodBody(method).append("(");
|
||||
prevCallSite = debugEmitter.emitCallSite();
|
||||
for (int i = 0; i < expr.getArguments().size(); ++i) {
|
||||
if (i > 0) {
|
||||
writer.append(",").ws();
|
||||
@ -1060,7 +1109,6 @@ public class StatementRenderer implements ExprVisitor, StatementVisitor {
|
||||
break;
|
||||
case SPECIAL:
|
||||
writer.appendMethodBody(method).append("(");
|
||||
prevCallSite = debugEmitter.emitCallSite();
|
||||
precedence = Precedence.min();
|
||||
expr.getArguments().get(0).acceptVisitor(this);
|
||||
for (int i = 1; i < expr.getArguments().size(); ++i) {
|
||||
@ -1071,7 +1119,6 @@ public class StatementRenderer implements ExprVisitor, StatementVisitor {
|
||||
break;
|
||||
case DYNAMIC:
|
||||
writer.append(".").append(name).append("(");
|
||||
prevCallSite = debugEmitter.emitCallSite();
|
||||
for (int i = 1; i < expr.getArguments().size(); ++i) {
|
||||
if (i > 1) {
|
||||
writer.append(",").ws();
|
||||
@ -1079,11 +1126,9 @@ public class StatementRenderer implements ExprVisitor, StatementVisitor {
|
||||
precedence = Precedence.min();
|
||||
expr.getArguments().get(i).acceptVisitor(this);
|
||||
}
|
||||
virtual = true;
|
||||
break;
|
||||
case CONSTRUCTOR:
|
||||
writer.appendInit(expr.getMethod()).append("(");
|
||||
prevCallSite = debugEmitter.emitCallSite();
|
||||
for (int i = 0; i < expr.getArguments().size(); ++i) {
|
||||
if (i > 0) {
|
||||
writer.append(",").ws();
|
||||
@ -1094,17 +1139,6 @@ public class StatementRenderer implements ExprVisitor, StatementVisitor {
|
||||
break;
|
||||
}
|
||||
writer.append(')');
|
||||
if (lastCallSite != null) {
|
||||
if (virtual) {
|
||||
lastCallSite.setVirtualMethod(expr.getMethod());
|
||||
} else {
|
||||
lastCallSite.setStaticMethod(expr.getMethod());
|
||||
}
|
||||
lastCallSite = callSite;
|
||||
}
|
||||
if (shouldEraseCallSite) {
|
||||
lastCallSite = null;
|
||||
}
|
||||
|
||||
if (outerPrecedence.ordinal() > Precedence.FUNCTION_CALL.ordinal()) {
|
||||
writer.append(')');
|
||||
@ -1612,4 +1646,12 @@ public class StatementRenderer implements ExprVisitor, StatementVisitor {
|
||||
return context.importModule(name);
|
||||
}
|
||||
}
|
||||
|
||||
private static class LocationStackEntry {
|
||||
final TextLocation location;
|
||||
|
||||
LocationStackEntry(TextLocation location) {
|
||||
this.location = location;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -21,8 +21,8 @@ import java.io.StringReader;
|
||||
import org.junit.Test;
|
||||
import org.mozilla.javascript.CompilerEnvirons;
|
||||
import org.mozilla.javascript.Context;
|
||||
import org.teavm.backend.javascript.codegen.OutputSourceWriterBuilder;
|
||||
import org.teavm.backend.javascript.codegen.SourceWriter;
|
||||
import org.teavm.backend.javascript.codegen.SourceWriterBuilder;
|
||||
|
||||
public class AstWriterTest {
|
||||
private StringBuilder sb = new StringBuilder();
|
||||
@ -31,7 +31,7 @@ public class AstWriterTest {
|
||||
private AstWriter writerWithGlobals;
|
||||
|
||||
public AstWriterTest() {
|
||||
var builder = new SourceWriterBuilder(null);
|
||||
var builder = new OutputSourceWriterBuilder(null);
|
||||
builder.setMinified(true);
|
||||
sourceWriter = builder.build(sb);
|
||||
writer = new AstWriter(sourceWriter, null);
|
||||
|
Loading…
Reference in New Issue
Block a user