Refactor generator of JS source map
- refactor pipeline for generation of source map - generate "empty" mappings for nodes that impossible to map to something reasonable - generate more accurate locations in source maps for specific JS AST nodes - for binary operation nodes parser now returns location of binary operator tokens instead of location of first operand - change completely how source map remapper works
This commit is contained in:
@@ -12,10 +12,7 @@ import org.jetbrains.kotlin.js.util.TextOutput;
|
|||||||
import gnu.trove.THashSet;
|
import gnu.trove.THashSet;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
import java.util.Iterator;
|
import java.util.*;
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Produces text output from a JavaScript AST.
|
* Produces text output from a JavaScript AST.
|
||||||
@@ -47,6 +44,11 @@ public class JsToStringGenerationVisitor extends JsVisitor {
|
|||||||
private static final char[] CHARS_WHILE = "while".toCharArray();
|
private static final char[] CHARS_WHILE = "while".toCharArray();
|
||||||
private static final char[] HEX_DIGITS = {
|
private static final char[] HEX_DIGITS = {
|
||||||
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
|
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
|
||||||
|
@NotNull
|
||||||
|
private final SourceLocationConsumer sourceLocationConsumer;
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
private final List<Object> sourceInfoStack = new ArrayList<>();
|
||||||
|
|
||||||
public static CharSequence javaScriptString(String value) {
|
public static CharSequence javaScriptString(String value) {
|
||||||
return javaScriptString(value, false);
|
return javaScriptString(value, false);
|
||||||
@@ -60,7 +62,7 @@ public class JsToStringGenerationVisitor extends JsVisitor {
|
|||||||
*/
|
*/
|
||||||
@SuppressWarnings({"ConstantConditions", "UnnecessaryFullyQualifiedName", "JavadocReference"})
|
@SuppressWarnings({"ConstantConditions", "UnnecessaryFullyQualifiedName", "JavadocReference"})
|
||||||
public static CharSequence javaScriptString(CharSequence chars, boolean forceDoubleQuote) {
|
public static CharSequence javaScriptString(CharSequence chars, boolean forceDoubleQuote) {
|
||||||
final int n = chars.length();
|
int n = chars.length();
|
||||||
int quoteCount = 0;
|
int quoteCount = 0;
|
||||||
int aposCount = 0;
|
int aposCount = 0;
|
||||||
|
|
||||||
@@ -174,25 +176,40 @@ public class JsToStringGenerationVisitor extends JsVisitor {
|
|||||||
* those that appear directly within these global blocks.
|
* those that appear directly within these global blocks.
|
||||||
*/
|
*/
|
||||||
private Set<JsBlock> globalBlocks = new THashSet<JsBlock>();
|
private Set<JsBlock> globalBlocks = new THashSet<JsBlock>();
|
||||||
|
|
||||||
|
@NotNull
|
||||||
protected final TextOutput p;
|
protected final TextOutput p;
|
||||||
|
|
||||||
public JsToStringGenerationVisitor(TextOutput out) {
|
public JsToStringGenerationVisitor(@NotNull TextOutput out, @NotNull SourceLocationConsumer sourceLocationConsumer) {
|
||||||
p = out;
|
p = out;
|
||||||
|
this.sourceLocationConsumer = sourceLocationConsumer;
|
||||||
|
}
|
||||||
|
|
||||||
|
public JsToStringGenerationVisitor(@NotNull TextOutput out) {
|
||||||
|
this(out, NoOpSourceLocationConsumer.INSTANCE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visitArrayAccess(@NotNull JsArrayAccess x) {
|
public void visitArrayAccess(@NotNull JsArrayAccess x) {
|
||||||
|
pushSourceInfo(x.getSource());
|
||||||
|
|
||||||
printPair(x, x.getArrayExpression());
|
printPair(x, x.getArrayExpression());
|
||||||
leftSquare();
|
leftSquare();
|
||||||
accept(x.getIndexExpression());
|
accept(x.getIndexExpression());
|
||||||
rightSquare();
|
rightSquare();
|
||||||
|
|
||||||
|
popSourceInfo();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visitArray(@NotNull JsArrayLiteral x) {
|
public void visitArray(@NotNull JsArrayLiteral x) {
|
||||||
|
pushSourceInfo(x.getSource());
|
||||||
|
|
||||||
leftSquare();
|
leftSquare();
|
||||||
printExpressions(x.getExpressions());
|
printExpressions(x.getExpressions());
|
||||||
rightSquare();
|
rightSquare();
|
||||||
|
|
||||||
|
popSourceInfo();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void printExpressions(List<JsExpression> expressions) {
|
private void printExpressions(List<JsExpression> expressions) {
|
||||||
@@ -209,6 +226,8 @@ public class JsToStringGenerationVisitor extends JsVisitor {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visitBinaryExpression(@NotNull JsBinaryOperation binaryOperation) {
|
public void visitBinaryExpression(@NotNull JsBinaryOperation binaryOperation) {
|
||||||
|
pushSourceInfo(binaryOperation.getSource());
|
||||||
|
|
||||||
JsBinaryOperator operator = binaryOperation.getOperator();
|
JsBinaryOperator operator = binaryOperation.getOperator();
|
||||||
JsExpression arg1 = binaryOperation.getArg1();
|
JsExpression arg1 = binaryOperation.getArg1();
|
||||||
boolean isExpressionEnclosed = parenPush(binaryOperation, arg1, !operator.isLeftAssociative());
|
boolean isExpressionEnclosed = parenPush(binaryOperation, arg1, !operator.isLeftAssociative());
|
||||||
@@ -250,6 +269,8 @@ public class JsToStringGenerationVisitor extends JsVisitor {
|
|||||||
if (isParenOpened) {
|
if (isParenOpened) {
|
||||||
rightParen();
|
rightParen();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
popSourceInfo();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -259,29 +280,41 @@ public class JsToStringGenerationVisitor extends JsVisitor {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visitBoolean(@NotNull JsBooleanLiteral x) {
|
public void visitBoolean(@NotNull JsBooleanLiteral x) {
|
||||||
|
pushSourceInfo(x.getSource());
|
||||||
|
|
||||||
if (x.getValue()) {
|
if (x.getValue()) {
|
||||||
p.print(CHARS_TRUE);
|
p.print(CHARS_TRUE);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
p.print(CHARS_FALSE);
|
p.print(CHARS_FALSE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
popSourceInfo();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visitBreak(@NotNull JsBreak x) {
|
public void visitBreak(@NotNull JsBreak x) {
|
||||||
|
pushSourceInfo(x.getSource());
|
||||||
|
|
||||||
p.print(CHARS_BREAK);
|
p.print(CHARS_BREAK);
|
||||||
continueOrBreakLabel(x);
|
continueOrBreakLabel(x);
|
||||||
|
|
||||||
|
popSourceInfo();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visitContinue(@NotNull JsContinue x) {
|
public void visitContinue(@NotNull JsContinue x) {
|
||||||
|
pushSourceInfo(x.getSource());
|
||||||
|
|
||||||
p.print(CHARS_CONTINUE);
|
p.print(CHARS_CONTINUE);
|
||||||
continueOrBreakLabel(x);
|
continueOrBreakLabel(x);
|
||||||
|
|
||||||
|
popSourceInfo();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void continueOrBreakLabel(JsContinue x) {
|
private void continueOrBreakLabel(JsContinue x) {
|
||||||
JsNameRef label = x.getLabel();
|
JsNameRef label = x.getLabel();
|
||||||
if (label != null && label.getIdent() != null) {
|
if (label != null) {
|
||||||
space();
|
space();
|
||||||
p.print(label.getIdent());
|
p.print(label.getIdent());
|
||||||
}
|
}
|
||||||
@@ -289,13 +322,20 @@ public class JsToStringGenerationVisitor extends JsVisitor {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visitCase(@NotNull JsCase x) {
|
public void visitCase(@NotNull JsCase x) {
|
||||||
|
pushSourceInfo(x.getSource());
|
||||||
|
|
||||||
p.print(CHARS_CASE);
|
p.print(CHARS_CASE);
|
||||||
space();
|
space();
|
||||||
accept(x.getCaseExpression());
|
accept(x.getCaseExpression());
|
||||||
_colon();
|
_colon();
|
||||||
|
|
||||||
|
popSourceInfo();
|
||||||
|
|
||||||
newlineOpt();
|
newlineOpt();
|
||||||
|
|
||||||
|
sourceLocationConsumer.pushSourceInfo(null);
|
||||||
printSwitchMemberStatements(x);
|
printSwitchMemberStatements(x);
|
||||||
|
sourceLocationConsumer.popSourceInfo();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void printSwitchMemberStatements(JsSwitchMember x) {
|
private void printSwitchMemberStatements(JsSwitchMember x) {
|
||||||
@@ -314,6 +354,8 @@ public class JsToStringGenerationVisitor extends JsVisitor {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visitCatch(@NotNull JsCatch x) {
|
public void visitCatch(@NotNull JsCatch x) {
|
||||||
|
pushSourceInfo(x.getSource());
|
||||||
|
|
||||||
spaceOpt();
|
spaceOpt();
|
||||||
p.print(CHARS_CATCH);
|
p.print(CHARS_CATCH);
|
||||||
spaceOpt();
|
spaceOpt();
|
||||||
@@ -332,11 +374,18 @@ public class JsToStringGenerationVisitor extends JsVisitor {
|
|||||||
|
|
||||||
rightParen();
|
rightParen();
|
||||||
spaceOpt();
|
spaceOpt();
|
||||||
|
|
||||||
|
popSourceInfo();
|
||||||
|
|
||||||
|
sourceLocationConsumer.pushSourceInfo(null);
|
||||||
accept(x.getBody());
|
accept(x.getBody());
|
||||||
|
sourceLocationConsumer.popSourceInfo();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visitConditional(@NotNull JsConditional x) {
|
public void visitConditional(@NotNull JsConditional x) {
|
||||||
|
pushSourceInfo(x.getSource());
|
||||||
|
|
||||||
// Associativity: for the then and else branches, it is safe to insert
|
// Associativity: for the then and else branches, it is safe to insert
|
||||||
// another
|
// another
|
||||||
// ternary expression, but if the test expression is a ternary, it should
|
// ternary expression, but if the test expression is a ternary, it should
|
||||||
@@ -350,6 +399,8 @@ public class JsToStringGenerationVisitor extends JsVisitor {
|
|||||||
_colon();
|
_colon();
|
||||||
spaceOpt();
|
spaceOpt();
|
||||||
printPair(x, x.getElseExpression());
|
printPair(x, x.getElseExpression());
|
||||||
|
|
||||||
|
popSourceInfo();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void printPair(JsExpression parent, JsExpression expression, boolean wrongAssoc) {
|
private void printPair(JsExpression parent, JsExpression expression, boolean wrongAssoc) {
|
||||||
@@ -369,35 +420,57 @@ public class JsToStringGenerationVisitor extends JsVisitor {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visitDebugger(@NotNull JsDebugger x) {
|
public void visitDebugger(@NotNull JsDebugger x) {
|
||||||
|
pushSourceInfo(x.getSource());
|
||||||
|
|
||||||
p.print(CHARS_DEBUGGER);
|
p.print(CHARS_DEBUGGER);
|
||||||
|
|
||||||
|
popSourceInfo();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visitDefault(@NotNull JsDefault x) {
|
public void visitDefault(@NotNull JsDefault x) {
|
||||||
|
pushSourceInfo(x.getSource());
|
||||||
|
|
||||||
p.print(CHARS_DEFAULT);
|
p.print(CHARS_DEFAULT);
|
||||||
_colon();
|
_colon();
|
||||||
|
|
||||||
|
popSourceInfo();
|
||||||
|
|
||||||
|
sourceLocationConsumer.pushSourceInfo(null);
|
||||||
printSwitchMemberStatements(x);
|
printSwitchMemberStatements(x);
|
||||||
|
sourceLocationConsumer.popSourceInfo();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visitWhile(@NotNull JsWhile x) {
|
public void visitWhile(@NotNull JsWhile x) {
|
||||||
|
pushSourceInfo(x.getSource());
|
||||||
|
|
||||||
_while();
|
_while();
|
||||||
spaceOpt();
|
spaceOpt();
|
||||||
leftParen();
|
leftParen();
|
||||||
accept(x.getCondition());
|
accept(x.getCondition());
|
||||||
rightParen();
|
rightParen();
|
||||||
|
|
||||||
|
popSourceInfo();
|
||||||
|
|
||||||
nestedPush(x.getBody());
|
nestedPush(x.getBody());
|
||||||
|
sourceLocationConsumer.pushSourceInfo(null);
|
||||||
accept(x.getBody());
|
accept(x.getBody());
|
||||||
|
sourceLocationConsumer.popSourceInfo();
|
||||||
nestedPop(x.getBody());
|
nestedPop(x.getBody());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visitDoWhile(@NotNull JsDoWhile x) {
|
public void visitDoWhile(@NotNull JsDoWhile x) {
|
||||||
|
sourceLocationConsumer.pushSourceInfo(null);
|
||||||
|
|
||||||
p.print(CHARS_DO);
|
p.print(CHARS_DO);
|
||||||
nestedPush(x.getBody());
|
nestedPush(x.getBody());
|
||||||
accept(x.getBody());
|
accept(x.getBody());
|
||||||
|
sourceLocationConsumer.popSourceInfo();
|
||||||
nestedPop(x.getBody());
|
nestedPop(x.getBody());
|
||||||
|
|
||||||
|
pushSourceInfo(x.getCondition().getSource());
|
||||||
if (needSemi) {
|
if (needSemi) {
|
||||||
semi();
|
semi();
|
||||||
newlineOpt();
|
newlineOpt();
|
||||||
@@ -406,11 +479,14 @@ public class JsToStringGenerationVisitor extends JsVisitor {
|
|||||||
spaceOpt();
|
spaceOpt();
|
||||||
needSemi = true;
|
needSemi = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
_while();
|
_while();
|
||||||
spaceOpt();
|
spaceOpt();
|
||||||
leftParen();
|
leftParen();
|
||||||
accept(x.getCondition());
|
accept(x.getCondition());
|
||||||
rightParen();
|
rightParen();
|
||||||
|
|
||||||
|
popSourceInfo();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -419,6 +495,12 @@ public class JsToStringGenerationVisitor extends JsVisitor {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visitExpressionStatement(@NotNull JsExpressionStatement x) {
|
public void visitExpressionStatement(@NotNull JsExpressionStatement x) {
|
||||||
|
Object source = x.getSource();
|
||||||
|
if (source == null) {
|
||||||
|
source = x.getExpression().getSource();
|
||||||
|
}
|
||||||
|
pushSourceInfo(source);
|
||||||
|
|
||||||
boolean surroundWithParentheses = JsFirstExpressionVisitor.exec(x);
|
boolean surroundWithParentheses = JsFirstExpressionVisitor.exec(x);
|
||||||
if (surroundWithParentheses) {
|
if (surroundWithParentheses) {
|
||||||
leftParen();
|
leftParen();
|
||||||
@@ -427,10 +509,14 @@ public class JsToStringGenerationVisitor extends JsVisitor {
|
|||||||
if (surroundWithParentheses) {
|
if (surroundWithParentheses) {
|
||||||
rightParen();
|
rightParen();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
popSourceInfo();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visitFor(@NotNull JsFor x) {
|
public void visitFor(@NotNull JsFor x) {
|
||||||
|
pushSourceInfo(x.getSource());
|
||||||
|
|
||||||
_for();
|
_for();
|
||||||
spaceOpt();
|
spaceOpt();
|
||||||
leftParen();
|
leftParen();
|
||||||
@@ -463,15 +549,22 @@ public class JsToStringGenerationVisitor extends JsVisitor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
rightParen();
|
rightParen();
|
||||||
|
|
||||||
|
popSourceInfo();
|
||||||
|
|
||||||
nestedPush(x.getBody());
|
nestedPush(x.getBody());
|
||||||
if (x.getBody() != null) {
|
if (x.getBody() != null) {
|
||||||
|
sourceLocationConsumer.pushSourceInfo(null);
|
||||||
accept(x.getBody());
|
accept(x.getBody());
|
||||||
|
sourceLocationConsumer.popSourceInfo();
|
||||||
}
|
}
|
||||||
nestedPop(x.getBody());
|
nestedPop(x.getBody());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visitForIn(@NotNull JsForIn x) {
|
public void visitForIn(@NotNull JsForIn x) {
|
||||||
|
pushSourceInfo(x.getSource());
|
||||||
|
|
||||||
_for();
|
_for();
|
||||||
spaceOpt();
|
spaceOpt();
|
||||||
leftParen();
|
leftParen();
|
||||||
@@ -500,13 +593,20 @@ public class JsToStringGenerationVisitor extends JsVisitor {
|
|||||||
accept(x.getObjectExpression());
|
accept(x.getObjectExpression());
|
||||||
|
|
||||||
rightParen();
|
rightParen();
|
||||||
|
|
||||||
|
popSourceInfo();
|
||||||
|
|
||||||
nestedPush(x.getBody());
|
nestedPush(x.getBody());
|
||||||
|
sourceLocationConsumer.pushSourceInfo(null);
|
||||||
accept(x.getBody());
|
accept(x.getBody());
|
||||||
|
sourceLocationConsumer.popSourceInfo();
|
||||||
nestedPop(x.getBody());
|
nestedPop(x.getBody());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visitFunction(@NotNull JsFunction x) {
|
public void visitFunction(@NotNull JsFunction x) {
|
||||||
|
pushSourceInfo(x.getSource());
|
||||||
|
|
||||||
p.print(CHARS_FUNCTION);
|
p.print(CHARS_FUNCTION);
|
||||||
space();
|
space();
|
||||||
if (x.getName() != null) {
|
if (x.getName() != null) {
|
||||||
@@ -524,24 +624,39 @@ public class JsToStringGenerationVisitor extends JsVisitor {
|
|||||||
space();
|
space();
|
||||||
|
|
||||||
lineBreakAfterBlock = false;
|
lineBreakAfterBlock = false;
|
||||||
|
|
||||||
|
sourceLocationConsumer.pushSourceInfo(null);
|
||||||
accept(x.getBody());
|
accept(x.getBody());
|
||||||
|
sourceLocationConsumer.popSourceInfo();
|
||||||
|
|
||||||
needSemi = true;
|
needSemi = true;
|
||||||
|
|
||||||
|
popSourceInfo();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visitIf(@NotNull JsIf x) {
|
public void visitIf(@NotNull JsIf x) {
|
||||||
|
pushSourceInfo(x.getSource());
|
||||||
|
|
||||||
_if();
|
_if();
|
||||||
spaceOpt();
|
spaceOpt();
|
||||||
leftParen();
|
leftParen();
|
||||||
accept(x.getIfExpression());
|
accept(x.getIfExpression());
|
||||||
rightParen();
|
rightParen();
|
||||||
|
|
||||||
|
popSourceInfo();
|
||||||
|
|
||||||
JsStatement thenStmt = x.getThenStatement();
|
JsStatement thenStmt = x.getThenStatement();
|
||||||
JsStatement elseStatement = x.getElseStatement();
|
JsStatement elseStatement = x.getElseStatement();
|
||||||
if (elseStatement != null && thenStmt instanceof JsIf && ((JsIf)thenStmt).getElseStatement() == null) {
|
if (elseStatement != null && thenStmt instanceof JsIf && ((JsIf)thenStmt).getElseStatement() == null) {
|
||||||
thenStmt = new JsBlock(thenStmt);
|
thenStmt = new JsBlock(thenStmt);
|
||||||
}
|
}
|
||||||
nestedPush(thenStmt);
|
nestedPush(thenStmt);
|
||||||
|
|
||||||
|
sourceLocationConsumer.pushSourceInfo(null);
|
||||||
accept(thenStmt);
|
accept(thenStmt);
|
||||||
|
sourceLocationConsumer.popSourceInfo();
|
||||||
|
|
||||||
nestedPop(thenStmt);
|
nestedPop(thenStmt);
|
||||||
if (elseStatement != null) {
|
if (elseStatement != null) {
|
||||||
if (needSemi) {
|
if (needSemi) {
|
||||||
@@ -560,7 +675,9 @@ public class JsToStringGenerationVisitor extends JsVisitor {
|
|||||||
else {
|
else {
|
||||||
space();
|
space();
|
||||||
}
|
}
|
||||||
|
sourceLocationConsumer.pushSourceInfo(null);
|
||||||
accept(elseStatement);
|
accept(elseStatement);
|
||||||
|
sourceLocationConsumer.popSourceInfo();
|
||||||
if (!elseIf) {
|
if (!elseIf) {
|
||||||
nestedPop(elseStatement);
|
nestedPop(elseStatement);
|
||||||
}
|
}
|
||||||
@@ -569,11 +686,15 @@ public class JsToStringGenerationVisitor extends JsVisitor {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visitInvocation(@NotNull JsInvocation invocation) {
|
public void visitInvocation(@NotNull JsInvocation invocation) {
|
||||||
|
pushSourceInfo(invocation.getSource());
|
||||||
|
|
||||||
printPair(invocation, invocation.getQualifier());
|
printPair(invocation, invocation.getQualifier());
|
||||||
|
|
||||||
leftParen();
|
leftParen();
|
||||||
printExpressions(invocation.getArguments());
|
printExpressions(invocation.getArguments());
|
||||||
rightParen();
|
rightParen();
|
||||||
|
|
||||||
|
popSourceInfo();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -581,14 +702,19 @@ public class JsToStringGenerationVisitor extends JsVisitor {
|
|||||||
nameOf(x);
|
nameOf(x);
|
||||||
_colon();
|
_colon();
|
||||||
spaceOpt();
|
spaceOpt();
|
||||||
|
|
||||||
|
sourceLocationConsumer.pushSourceInfo(null);
|
||||||
accept(x.getStatement());
|
accept(x.getStatement());
|
||||||
|
sourceLocationConsumer.popSourceInfo();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visitNameRef(@NotNull JsNameRef nameRef) {
|
public void visitNameRef(@NotNull JsNameRef nameRef) {
|
||||||
|
pushSourceInfo(nameRef.getSource());
|
||||||
|
|
||||||
JsExpression qualifier = nameRef.getQualifier();
|
JsExpression qualifier = nameRef.getQualifier();
|
||||||
if (qualifier != null) {
|
if (qualifier != null) {
|
||||||
final boolean enclose;
|
boolean enclose;
|
||||||
if (qualifier instanceof JsLiteral.JsValueLiteral) {
|
if (qualifier instanceof JsLiteral.JsValueLiteral) {
|
||||||
// "42.foo" is not allowed, but "(42).foo" is.
|
// "42.foo" is not allowed, but "(42).foo" is.
|
||||||
enclose = qualifier instanceof JsNumberLiteral;
|
enclose = qualifier instanceof JsNumberLiteral;
|
||||||
@@ -609,10 +735,14 @@ public class JsToStringGenerationVisitor extends JsVisitor {
|
|||||||
|
|
||||||
p.maybeIndent();
|
p.maybeIndent();
|
||||||
p.print(nameRef.getIdent());
|
p.print(nameRef.getIdent());
|
||||||
|
|
||||||
|
popSourceInfo();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visitNew(@NotNull JsNew x) {
|
public void visitNew(@NotNull JsNew x) {
|
||||||
|
pushSourceInfo(x.getSource());
|
||||||
|
|
||||||
p.print(CHARS_NEW);
|
p.print(CHARS_NEW);
|
||||||
space();
|
space();
|
||||||
|
|
||||||
@@ -629,26 +759,43 @@ public class JsToStringGenerationVisitor extends JsVisitor {
|
|||||||
leftParen();
|
leftParen();
|
||||||
printExpressions(x.getArguments());
|
printExpressions(x.getArguments());
|
||||||
rightParen();
|
rightParen();
|
||||||
|
|
||||||
|
popSourceInfo();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visitNull(@NotNull JsNullLiteral x) {
|
public void visitNull(@NotNull JsNullLiteral x) {
|
||||||
|
pushSourceInfo(x.getSource());
|
||||||
|
|
||||||
p.print(CHARS_NULL);
|
p.print(CHARS_NULL);
|
||||||
|
|
||||||
|
popSourceInfo();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visitInt(@NotNull JsIntLiteral x) {
|
public void visitInt(@NotNull JsIntLiteral x) {
|
||||||
|
pushSourceInfo(x.getSource());
|
||||||
|
|
||||||
p.print(x.value);
|
p.print(x.value);
|
||||||
|
|
||||||
|
popSourceInfo();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visitDouble(@NotNull JsDoubleLiteral x) {
|
public void visitDouble(@NotNull JsDoubleLiteral x) {
|
||||||
|
pushSourceInfo(x.getSource());
|
||||||
|
|
||||||
p.print(x.value);
|
p.print(x.value);
|
||||||
|
|
||||||
|
popSourceInfo();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visitObjectLiteral(@NotNull JsObjectLiteral objectLiteral) {
|
public void visitObjectLiteral(@NotNull JsObjectLiteral objectLiteral) {
|
||||||
|
pushSourceInfo(objectLiteral.getSource());
|
||||||
|
|
||||||
p.print('{');
|
p.print('{');
|
||||||
|
|
||||||
if (objectLiteral.isMultiline()) {
|
if (objectLiteral.isMultiline()) {
|
||||||
p.indentIn();
|
p.indentIn();
|
||||||
}
|
}
|
||||||
@@ -668,6 +815,8 @@ public class JsToStringGenerationVisitor extends JsVisitor {
|
|||||||
|
|
||||||
notFirst = true;
|
notFirst = true;
|
||||||
|
|
||||||
|
pushSourceInfo(item.getSource());
|
||||||
|
|
||||||
JsExpression labelExpr = item.getLabelExpr();
|
JsExpression labelExpr = item.getLabelExpr();
|
||||||
// labels can be either string, integral, or decimal literals
|
// labels can be either string, integral, or decimal literals
|
||||||
if (labelExpr instanceof JsNameRef) {
|
if (labelExpr instanceof JsNameRef) {
|
||||||
@@ -688,6 +837,8 @@ public class JsToStringGenerationVisitor extends JsVisitor {
|
|||||||
if (wasEnclosed) {
|
if (wasEnclosed) {
|
||||||
rightParen();
|
rightParen();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
popSourceInfo();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (objectLiteral.isMultiline()) {
|
if (objectLiteral.isMultiline()) {
|
||||||
@@ -696,6 +847,7 @@ public class JsToStringGenerationVisitor extends JsVisitor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
p.print('}');
|
p.print('}');
|
||||||
|
popSourceInfo();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -705,15 +857,21 @@ public class JsToStringGenerationVisitor extends JsVisitor {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visitPostfixOperation(@NotNull JsPostfixOperation x) {
|
public void visitPostfixOperation(@NotNull JsPostfixOperation x) {
|
||||||
|
pushSourceInfo(x.getSource());
|
||||||
|
|
||||||
JsUnaryOperator op = x.getOperator();
|
JsUnaryOperator op = x.getOperator();
|
||||||
JsExpression arg = x.getArg();
|
JsExpression arg = x.getArg();
|
||||||
// unary operators always associate correctly (I think)
|
// unary operators always associate correctly (I think)
|
||||||
printPair(x, arg);
|
printPair(x, arg);
|
||||||
p.print(op.getSymbol());
|
p.print(op.getSymbol());
|
||||||
|
|
||||||
|
popSourceInfo();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visitPrefixOperation(@NotNull JsPrefixOperation x) {
|
public void visitPrefixOperation(@NotNull JsPrefixOperation x) {
|
||||||
|
pushSourceInfo(x.getSource());
|
||||||
|
|
||||||
JsUnaryOperator op = x.getOperator();
|
JsUnaryOperator op = x.getOperator();
|
||||||
p.print(op.getSymbol());
|
p.print(op.getSymbol());
|
||||||
JsExpression arg = x.getArg();
|
JsExpression arg = x.getArg();
|
||||||
@@ -722,15 +880,19 @@ public class JsToStringGenerationVisitor extends JsVisitor {
|
|||||||
}
|
}
|
||||||
// unary operators always associate correctly (I think)
|
// unary operators always associate correctly (I think)
|
||||||
printPair(x, arg);
|
printPair(x, arg);
|
||||||
|
|
||||||
|
popSourceInfo();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visitProgram(@NotNull JsProgram x) {
|
public void visitProgram(@NotNull JsProgram x) {
|
||||||
p.print("<JsProgram>");
|
x.acceptChildren(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visitRegExp(@NotNull JsRegExp x) {
|
public void visitRegExp(@NotNull JsRegExp x) {
|
||||||
|
pushSourceInfo(x.getSource());
|
||||||
|
|
||||||
slash();
|
slash();
|
||||||
p.print(x.getPattern());
|
p.print(x.getPattern());
|
||||||
slash();
|
slash();
|
||||||
@@ -738,46 +900,72 @@ public class JsToStringGenerationVisitor extends JsVisitor {
|
|||||||
if (flags != null) {
|
if (flags != null) {
|
||||||
p.print(flags);
|
p.print(flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
popSourceInfo();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visitReturn(@NotNull JsReturn x) {
|
public void visitReturn(@NotNull JsReturn x) {
|
||||||
|
pushSourceInfo(x.getSource());
|
||||||
|
|
||||||
p.print(CHARS_RETURN);
|
p.print(CHARS_RETURN);
|
||||||
JsExpression expr = x.getExpression();
|
JsExpression expr = x.getExpression();
|
||||||
if (expr != null) {
|
if (expr != null) {
|
||||||
space();
|
space();
|
||||||
accept(expr);
|
accept(expr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
popSourceInfo();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visitString(@NotNull JsStringLiteral x) {
|
public void visitString(@NotNull JsStringLiteral x) {
|
||||||
|
pushSourceInfo(x.getSource());
|
||||||
|
|
||||||
p.print(javaScriptString(x.getValue()));
|
p.print(javaScriptString(x.getValue()));
|
||||||
|
|
||||||
|
popSourceInfo();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(@NotNull JsSwitch x) {
|
public void visit(@NotNull JsSwitch x) {
|
||||||
|
pushSourceInfo(x.getSource());
|
||||||
|
|
||||||
p.print(CHARS_SWITCH);
|
p.print(CHARS_SWITCH);
|
||||||
spaceOpt();
|
spaceOpt();
|
||||||
leftParen();
|
leftParen();
|
||||||
accept(x.getExpression());
|
accept(x.getExpression());
|
||||||
rightParen();
|
rightParen();
|
||||||
|
|
||||||
|
popSourceInfo();
|
||||||
|
|
||||||
|
|
||||||
|
sourceLocationConsumer.pushSourceInfo(null);
|
||||||
spaceOpt();
|
spaceOpt();
|
||||||
blockOpen();
|
blockOpen();
|
||||||
acceptList(x.getCases());
|
acceptList(x.getCases());
|
||||||
blockClose();
|
blockClose();
|
||||||
|
sourceLocationConsumer.popSourceInfo();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visitThis(@NotNull JsThisRef x) {
|
public void visitThis(@NotNull JsThisRef x) {
|
||||||
|
pushSourceInfo(x.getSource());
|
||||||
|
|
||||||
p.print(CHARS_THIS);
|
p.print(CHARS_THIS);
|
||||||
|
|
||||||
|
popSourceInfo();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visitThrow(@NotNull JsThrow x) {
|
public void visitThrow(@NotNull JsThrow x) {
|
||||||
|
pushSourceInfo(x.getSource());
|
||||||
|
|
||||||
p.print(CHARS_THROW);
|
p.print(CHARS_THROW);
|
||||||
space();
|
space();
|
||||||
accept(x.getExpression());
|
accept(x.getExpression());
|
||||||
|
|
||||||
|
popSourceInfo();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -798,6 +986,8 @@ public class JsToStringGenerationVisitor extends JsVisitor {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visit(@NotNull JsVar var) {
|
public void visit(@NotNull JsVar var) {
|
||||||
|
pushSourceInfo(var.getSource());
|
||||||
|
|
||||||
nameOf(var);
|
nameOf(var);
|
||||||
JsExpression initExpr = var.getInitExpression();
|
JsExpression initExpr = var.getInitExpression();
|
||||||
if (initExpr != null) {
|
if (initExpr != null) {
|
||||||
@@ -810,10 +1000,14 @@ public class JsToStringGenerationVisitor extends JsVisitor {
|
|||||||
rightParen();
|
rightParen();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
popSourceInfo();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visitVars(@NotNull JsVars vars) {
|
public void visitVars(@NotNull JsVars vars) {
|
||||||
|
pushSourceInfo(vars.getSource());
|
||||||
|
|
||||||
var();
|
var();
|
||||||
space();
|
space();
|
||||||
boolean sep = false;
|
boolean sep = false;
|
||||||
@@ -831,6 +1025,8 @@ public class JsToStringGenerationVisitor extends JsVisitor {
|
|||||||
|
|
||||||
accept(var);
|
accept(var);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
popSourceInfo();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -844,13 +1040,13 @@ public class JsToStringGenerationVisitor extends JsVisitor {
|
|||||||
space();
|
space();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
p.newline();
|
newline();
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean notFirst = false;
|
boolean notFirst = false;
|
||||||
for (Map.Entry<String, Object> entry : comment.getTags().entrySet()) {
|
for (Map.Entry<String, Object> entry : comment.getTags().entrySet()) {
|
||||||
if (notFirst) {
|
if (notFirst) {
|
||||||
p.newline();
|
newline();
|
||||||
p.print(' ');
|
p.print(' ');
|
||||||
p.print('*');
|
p.print('*');
|
||||||
}
|
}
|
||||||
@@ -872,7 +1068,7 @@ public class JsToStringGenerationVisitor extends JsVisitor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!asSingleLine) {
|
if (!asSingleLine) {
|
||||||
p.newline();
|
newline();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -890,18 +1086,39 @@ public class JsToStringGenerationVisitor extends JsVisitor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected final void newlineOpt() {
|
private void newlineOpt() {
|
||||||
if (!p.isCompact()) {
|
if (!p.isCompact()) {
|
||||||
p.newline();
|
newline();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void printJsBlock(JsBlock x, boolean finalNewline) {
|
private void newline() {
|
||||||
|
p.newline();
|
||||||
|
sourceLocationConsumer.newLine();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void pushSourceInfo(Object location) {
|
||||||
|
p.maybeIndent();
|
||||||
|
sourceInfoStack.add(location);
|
||||||
|
if (location != null) {
|
||||||
|
sourceLocationConsumer.pushSourceInfo(location);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void popSourceInfo() {
|
||||||
|
if (!sourceInfoStack.isEmpty() && sourceInfoStack.remove(sourceInfoStack.size() - 1) != null) {
|
||||||
|
sourceLocationConsumer.popSourceInfo();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void printJsBlock(JsBlock x, boolean finalNewline) {
|
||||||
if (!lineBreakAfterBlock) {
|
if (!lineBreakAfterBlock) {
|
||||||
finalNewline = false;
|
finalNewline = false;
|
||||||
lineBreakAfterBlock = true;
|
lineBreakAfterBlock = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sourceLocationConsumer.pushSourceInfo(null);
|
||||||
|
|
||||||
boolean needBraces = !x.isGlobalBlock();
|
boolean needBraces = !x.isGlobalBlock();
|
||||||
if (needBraces) {
|
if (needBraces) {
|
||||||
blockOpen();
|
blockOpen();
|
||||||
@@ -949,7 +1166,7 @@ public class JsToStringGenerationVisitor extends JsVisitor {
|
|||||||
newlineOpt();
|
newlineOpt();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
p.newline();
|
newline();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@@ -973,6 +1190,8 @@ public class JsToStringGenerationVisitor extends JsVisitor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
needSemi = false;
|
needSemi = false;
|
||||||
|
|
||||||
|
sourceLocationConsumer.popSourceInfo();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void assignment() {
|
private void assignment() {
|
||||||
|
|||||||
@@ -0,0 +1,25 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2017 JetBrains s.r.o.
|
||||||
|
*
|
||||||
|
* 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.jetbrains.kotlin.js.backend
|
||||||
|
|
||||||
|
object NoOpSourceLocationConsumer : SourceLocationConsumer {
|
||||||
|
override fun newLine() {}
|
||||||
|
|
||||||
|
override fun pushSourceInfo(info: Any?) {}
|
||||||
|
|
||||||
|
override fun popSourceInfo() {}
|
||||||
|
}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2017 JetBrains s.r.o.
|
||||||
|
*
|
||||||
|
* 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.jetbrains.kotlin.js.backend
|
||||||
|
|
||||||
|
interface SourceLocationConsumer {
|
||||||
|
fun newLine()
|
||||||
|
|
||||||
|
fun pushSourceInfo(info: Any?)
|
||||||
|
|
||||||
|
fun popSourceInfo()
|
||||||
|
}
|
||||||
@@ -32,21 +32,7 @@ public interface TextOutput {
|
|||||||
|
|
||||||
void printOpt(char c);
|
void printOpt(char c);
|
||||||
|
|
||||||
void printOpt(char[] s);
|
|
||||||
|
|
||||||
void printOpt(String s);
|
|
||||||
|
|
||||||
boolean isCompact();
|
boolean isCompact();
|
||||||
|
|
||||||
boolean isJustNewlined();
|
|
||||||
|
|
||||||
void setOutListener(OutListener outListener);
|
|
||||||
|
|
||||||
void maybeIndent();
|
void maybeIndent();
|
||||||
|
|
||||||
public interface OutListener {
|
|
||||||
void newLined();
|
|
||||||
|
|
||||||
void indentedAfterNewLine();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,8 +17,6 @@ public class TextOutputImpl implements TextOutput {
|
|||||||
private int line = 0;
|
private int line = 0;
|
||||||
private int column = 0;
|
private int column = 0;
|
||||||
|
|
||||||
private OutListener outListener;
|
|
||||||
|
|
||||||
public TextOutputImpl() {
|
public TextOutputImpl() {
|
||||||
this(false);
|
this(false);
|
||||||
}
|
}
|
||||||
@@ -78,9 +76,6 @@ public class TextOutputImpl implements TextOutput {
|
|||||||
line++;
|
line++;
|
||||||
column = 0;
|
column = 0;
|
||||||
justNewlined = true;
|
justNewlined = true;
|
||||||
if (outListener != null) {
|
|
||||||
outListener.newLined();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -151,9 +146,6 @@ public class TextOutputImpl implements TextOutput {
|
|||||||
if (justNewlined && !compact) {
|
if (justNewlined && !compact) {
|
||||||
printAndCount(indents[identLevel]);
|
printAndCount(indents[identLevel]);
|
||||||
justNewlined = false;
|
justNewlined = false;
|
||||||
if (outListener != null) {
|
|
||||||
outListener.indentedAfterNewLine();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -173,9 +165,4 @@ public class TextOutputImpl implements TextOutput {
|
|||||||
public boolean isJustNewlined() {
|
public boolean isJustNewlined() {
|
||||||
return justNewlined && !compact;
|
return justNewlined && !compact;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setOutListener(OutListener outListener) {
|
|
||||||
this.outListener = outListener;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -194,7 +194,7 @@ class FunctionReader(
|
|||||||
|
|
||||||
val sourceMap = info.sourceMap
|
val sourceMap = info.sourceMap
|
||||||
if (sourceMap != null) {
|
if (sourceMap != null) {
|
||||||
val remapper = SourceMapLocationRemapper(mapOf(info.filePath to sourceMap))
|
val remapper = SourceMapLocationRemapper(sourceMap)
|
||||||
remapper.remap(function)
|
remapper.remap(function)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1115,7 +1115,10 @@ public class JsAstMapper {
|
|||||||
astNode.setSource(jsLocation);
|
astNode.setSource(jsLocation);
|
||||||
}
|
}
|
||||||
else if (astNode instanceof JsExpressionStatement) {
|
else if (astNode instanceof JsExpressionStatement) {
|
||||||
((JsExpressionStatement) astNode).getExpression().setSource(jsLocation);
|
JsExpression expression = ((JsExpressionStatement) astNode).getExpression();
|
||||||
|
if (expression.getSource() == null) {
|
||||||
|
expression.setSource(jsLocation);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return astNode;
|
return astNode;
|
||||||
|
|||||||
@@ -180,7 +180,7 @@ public class Parser extends Observable {
|
|||||||
// by '(', assume <name> starts memberExpr
|
// by '(', assume <name> starts memberExpr
|
||||||
Node memberExprHead = nameNode;
|
Node memberExprHead = nameNode;
|
||||||
nameNode = null;
|
nameNode = null;
|
||||||
memberExprNode = memberExprTail(ts, false, memberExprHead, basePosition);
|
memberExprNode = memberExprTail(ts, false, memberExprHead);
|
||||||
}
|
}
|
||||||
mustMatchToken(ts, TokenStream.LP, "msg.no.paren.parms");
|
mustMatchToken(ts, TokenStream.LP, "msg.no.paren.parms");
|
||||||
}
|
}
|
||||||
@@ -708,20 +708,20 @@ public class Parser extends Observable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private Node expr(TokenStream ts, boolean inForInit) throws IOException, JavaScriptException {
|
private Node expr(TokenStream ts, boolean inForInit) throws IOException, JavaScriptException {
|
||||||
CodePosition position = getNextTokenPosition(ts);
|
|
||||||
Node pn = assignExpr(ts, inForInit);
|
Node pn = assignExpr(ts, inForInit);
|
||||||
while (ts.matchToken(TokenStream.COMMA)) {
|
while (ts.matchToken(TokenStream.COMMA)) {
|
||||||
|
CodePosition position = ts.tokenPosition;
|
||||||
pn = nf.createBinary(TokenStream.COMMA, pn, assignExpr(ts, inForInit), position);
|
pn = nf.createBinary(TokenStream.COMMA, pn, assignExpr(ts, inForInit), position);
|
||||||
}
|
}
|
||||||
return pn;
|
return pn;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Node assignExpr(TokenStream ts, boolean inForInit) throws IOException, JavaScriptException {
|
private Node assignExpr(TokenStream ts, boolean inForInit) throws IOException, JavaScriptException {
|
||||||
CodePosition position = getNextTokenPosition(ts);
|
|
||||||
Node pn = condExpr(ts, inForInit);
|
Node pn = condExpr(ts, inForInit);
|
||||||
|
|
||||||
if (ts.matchToken(TokenStream.ASSIGN)) {
|
if (ts.matchToken(TokenStream.ASSIGN)) {
|
||||||
// omitted: "invalid assignment left-hand side" check.
|
// omitted: "invalid assignment left-hand side" check.
|
||||||
|
CodePosition position = ts.tokenPosition;
|
||||||
pn = nf.createBinary(TokenStream.ASSIGN, ts.getOp(), pn, assignExpr(ts, inForInit), position);
|
pn = nf.createBinary(TokenStream.ASSIGN, ts.getOp(), pn, assignExpr(ts, inForInit), position);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -729,10 +729,10 @@ public class Parser extends Observable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private Node condExpr(TokenStream ts, boolean inForInit) throws IOException, JavaScriptException {
|
private Node condExpr(TokenStream ts, boolean inForInit) throws IOException, JavaScriptException {
|
||||||
CodePosition position = getNextTokenPosition(ts);
|
|
||||||
Node pn = orExpr(ts, inForInit);
|
Node pn = orExpr(ts, inForInit);
|
||||||
|
|
||||||
if (ts.matchToken(TokenStream.HOOK)) {
|
if (ts.matchToken(TokenStream.HOOK)) {
|
||||||
|
CodePosition position = ts.tokenPosition;
|
||||||
Node ifTrue = assignExpr(ts, false);
|
Node ifTrue = assignExpr(ts, false);
|
||||||
mustMatchToken(ts, TokenStream.COLON, "msg.no.colon.cond");
|
mustMatchToken(ts, TokenStream.COLON, "msg.no.colon.cond");
|
||||||
Node ifFalse = assignExpr(ts, inForInit);
|
Node ifFalse = assignExpr(ts, inForInit);
|
||||||
@@ -743,9 +743,9 @@ public class Parser extends Observable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private Node orExpr(TokenStream ts, boolean inForInit) throws IOException, JavaScriptException {
|
private Node orExpr(TokenStream ts, boolean inForInit) throws IOException, JavaScriptException {
|
||||||
CodePosition position = getNextTokenPosition(ts);
|
|
||||||
Node pn = andExpr(ts, inForInit);
|
Node pn = andExpr(ts, inForInit);
|
||||||
while (ts.matchToken(TokenStream.OR)) {
|
while (ts.matchToken(TokenStream.OR)) {
|
||||||
|
CodePosition position = ts.tokenPosition;
|
||||||
pn = nf.createBinary(TokenStream.OR, pn, andExpr(ts, inForInit), position);
|
pn = nf.createBinary(TokenStream.OR, pn, andExpr(ts, inForInit), position);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -753,9 +753,9 @@ public class Parser extends Observable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private Node andExpr(TokenStream ts, boolean inForInit) throws IOException, JavaScriptException {
|
private Node andExpr(TokenStream ts, boolean inForInit) throws IOException, JavaScriptException {
|
||||||
CodePosition position = getNextTokenPosition(ts);
|
|
||||||
Node pn = bitOrExpr(ts, inForInit);
|
Node pn = bitOrExpr(ts, inForInit);
|
||||||
while (ts.matchToken(TokenStream.AND)) {
|
while (ts.matchToken(TokenStream.AND)) {
|
||||||
|
CodePosition position = ts.tokenPosition;
|
||||||
pn = nf.createBinary(TokenStream.AND, pn, bitOrExpr(ts, inForInit), position);
|
pn = nf.createBinary(TokenStream.AND, pn, bitOrExpr(ts, inForInit), position);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -763,44 +763,46 @@ public class Parser extends Observable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private Node bitOrExpr(TokenStream ts, boolean inForInit) throws IOException, JavaScriptException {
|
private Node bitOrExpr(TokenStream ts, boolean inForInit) throws IOException, JavaScriptException {
|
||||||
CodePosition position = getNextTokenPosition(ts);
|
|
||||||
Node pn = bitXorExpr(ts, inForInit);
|
Node pn = bitXorExpr(ts, inForInit);
|
||||||
while (ts.matchToken(TokenStream.BITOR)) {
|
while (ts.matchToken(TokenStream.BITOR)) {
|
||||||
|
CodePosition position = ts.tokenPosition;
|
||||||
pn = nf.createBinary(TokenStream.BITOR, pn, bitXorExpr(ts, inForInit), position);
|
pn = nf.createBinary(TokenStream.BITOR, pn, bitXorExpr(ts, inForInit), position);
|
||||||
}
|
}
|
||||||
return pn;
|
return pn;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Node bitXorExpr(TokenStream ts, boolean inForInit) throws IOException, JavaScriptException {
|
private Node bitXorExpr(TokenStream ts, boolean inForInit) throws IOException, JavaScriptException {
|
||||||
CodePosition position = getNextTokenPosition(ts);
|
|
||||||
Node pn = bitAndExpr(ts, inForInit);
|
Node pn = bitAndExpr(ts, inForInit);
|
||||||
while (ts.matchToken(TokenStream.BITXOR)) {
|
while (ts.matchToken(TokenStream.BITXOR)) {
|
||||||
|
CodePosition position = ts.tokenPosition;
|
||||||
pn = nf.createBinary(TokenStream.BITXOR, pn, bitAndExpr(ts, inForInit), position);
|
pn = nf.createBinary(TokenStream.BITXOR, pn, bitAndExpr(ts, inForInit), position);
|
||||||
}
|
}
|
||||||
return pn;
|
return pn;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Node bitAndExpr(TokenStream ts, boolean inForInit) throws IOException, JavaScriptException {
|
private Node bitAndExpr(TokenStream ts, boolean inForInit) throws IOException, JavaScriptException {
|
||||||
CodePosition position = getNextTokenPosition(ts);
|
|
||||||
Node pn = eqExpr(ts, inForInit);
|
Node pn = eqExpr(ts, inForInit);
|
||||||
while (ts.matchToken(TokenStream.BITAND)) {
|
while (ts.matchToken(TokenStream.BITAND)) {
|
||||||
|
CodePosition position = ts.tokenPosition;
|
||||||
pn = nf.createBinary(TokenStream.BITAND, pn, eqExpr(ts, inForInit), position);
|
pn = nf.createBinary(TokenStream.BITAND, pn, eqExpr(ts, inForInit), position);
|
||||||
}
|
}
|
||||||
return pn;
|
return pn;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Node eqExpr(TokenStream ts, boolean inForInit) throws IOException, JavaScriptException {
|
private Node eqExpr(TokenStream ts, boolean inForInit) throws IOException, JavaScriptException {
|
||||||
CodePosition position = getNextTokenPosition(ts);
|
|
||||||
Node pn = relExpr(ts, inForInit);
|
Node pn = relExpr(ts, inForInit);
|
||||||
|
|
||||||
while (ts.matchToken(TokenStream.EQOP)) {
|
while (ts.matchToken(TokenStream.EQOP)) {
|
||||||
|
CodePosition position = ts.tokenPosition;
|
||||||
pn = nf.createBinary(TokenStream.EQOP, ts.getOp(), pn, relExpr(ts, inForInit), position);
|
pn = nf.createBinary(TokenStream.EQOP, ts.getOp(), pn, relExpr(ts, inForInit), position);
|
||||||
}
|
}
|
||||||
return pn;
|
return pn;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Node relExpr(TokenStream ts, boolean inForInit) throws IOException, JavaScriptException {
|
private Node relExpr(TokenStream ts, boolean inForInit) throws IOException, JavaScriptException {
|
||||||
CodePosition position = getNextTokenPosition(ts);
|
|
||||||
Node pn = shiftExpr(ts);
|
Node pn = shiftExpr(ts);
|
||||||
|
CodePosition position = ts.tokenPosition;
|
||||||
|
|
||||||
while (ts.matchToken(TokenStream.RELOP)) {
|
while (ts.matchToken(TokenStream.RELOP)) {
|
||||||
int op = ts.getOp();
|
int op = ts.getOp();
|
||||||
if (inForInit && op == TokenStream.IN) {
|
if (inForInit && op == TokenStream.IN) {
|
||||||
@@ -809,26 +811,26 @@ public class Parser extends Observable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pn = nf.createBinary(TokenStream.RELOP, op, pn, shiftExpr(ts), position);
|
pn = nf.createBinary(TokenStream.RELOP, op, pn, shiftExpr(ts), position);
|
||||||
|
position = ts.tokenPosition;
|
||||||
}
|
}
|
||||||
return pn;
|
return pn;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Node shiftExpr(TokenStream ts) throws IOException, JavaScriptException {
|
private Node shiftExpr(TokenStream ts) throws IOException, JavaScriptException {
|
||||||
CodePosition position = getNextTokenPosition(ts);
|
|
||||||
Node pn = addExpr(ts);
|
Node pn = addExpr(ts);
|
||||||
while (ts.matchToken(TokenStream.SHOP)) {
|
while (ts.matchToken(TokenStream.SHOP)) {
|
||||||
|
CodePosition position = ts.tokenPosition;
|
||||||
pn = nf.createBinary(TokenStream.SHOP, ts.getOp(), pn, addExpr(ts), position);
|
pn = nf.createBinary(TokenStream.SHOP, ts.getOp(), pn, addExpr(ts), position);
|
||||||
}
|
}
|
||||||
return pn;
|
return pn;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Node addExpr(TokenStream ts) throws IOException, JavaScriptException {
|
private Node addExpr(TokenStream ts) throws IOException, JavaScriptException {
|
||||||
CodePosition position = getNextTokenPosition(ts);
|
|
||||||
int tt;
|
int tt;
|
||||||
Node pn = mulExpr(ts);
|
Node pn = mulExpr(ts);
|
||||||
|
|
||||||
while ((tt = ts.getToken()) == TokenStream.ADD || tt == TokenStream.SUB) {
|
while ((tt = ts.getToken()) == TokenStream.ADD || tt == TokenStream.SUB) {
|
||||||
// flushNewLines
|
CodePosition position = ts.tokenPosition;
|
||||||
pn = nf.createBinary(tt, pn, mulExpr(ts), position);
|
pn = nf.createBinary(tt, pn, mulExpr(ts), position);
|
||||||
}
|
}
|
||||||
ts.ungetToken(tt);
|
ts.ungetToken(tt);
|
||||||
@@ -837,13 +839,13 @@ public class Parser extends Observable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private Node mulExpr(TokenStream ts) throws IOException, JavaScriptException {
|
private Node mulExpr(TokenStream ts) throws IOException, JavaScriptException {
|
||||||
CodePosition position = getNextTokenPosition(ts);
|
|
||||||
int tt;
|
int tt;
|
||||||
|
|
||||||
Node pn = unaryExpr(ts);
|
Node pn = unaryExpr(ts);
|
||||||
|
|
||||||
while ((tt = ts.peekToken()) == TokenStream.MUL || tt == TokenStream.DIV || tt == TokenStream.MOD) {
|
while ((tt = ts.peekToken()) == TokenStream.MUL || tt == TokenStream.DIV || tt == TokenStream.MOD) {
|
||||||
tt = ts.getToken();
|
tt = ts.getToken();
|
||||||
|
CodePosition position = ts.tokenPosition;
|
||||||
pn = nf.createBinary(tt, pn, unaryExpr(ts), position);
|
pn = nf.createBinary(tt, pn, unaryExpr(ts), position);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -894,6 +896,7 @@ public class Parser extends Observable {
|
|||||||
if (((peeked = ts.peekToken()) == TokenStream.INC || peeked == TokenStream.DEC)
|
if (((peeked = ts.peekToken()) == TokenStream.INC || peeked == TokenStream.DEC)
|
||||||
&& ts.getLineno() == lineno) {
|
&& ts.getLineno() == lineno) {
|
||||||
int pf = ts.getToken();
|
int pf = ts.getToken();
|
||||||
|
position = ts.tokenPosition;
|
||||||
return nf.createUnary(pf, TokenStream.POST, pn, position);
|
return nf.createUnary(pf, TokenStream.POST, pn, position);
|
||||||
}
|
}
|
||||||
return pn;
|
return pn;
|
||||||
@@ -960,16 +963,17 @@ public class Parser extends Observable {
|
|||||||
pn = primaryExpr(ts);
|
pn = primaryExpr(ts);
|
||||||
}
|
}
|
||||||
|
|
||||||
return memberExprTail(ts, allowCallSyntax, pn, position);
|
return memberExprTail(ts, allowCallSyntax, pn);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Node memberExprTail(
|
private Node memberExprTail(
|
||||||
TokenStream ts, boolean allowCallSyntax,
|
TokenStream ts, boolean allowCallSyntax,
|
||||||
Node pn, CodePosition position
|
Node pn
|
||||||
) throws IOException, JavaScriptException {
|
) throws IOException, JavaScriptException {
|
||||||
lastExprEndLine = ts.getLineno();
|
lastExprEndLine = ts.getLineno();
|
||||||
int tt;
|
int tt;
|
||||||
while ((tt = ts.getToken()) > TokenStream.EOF) {
|
while ((tt = ts.getToken()) > TokenStream.EOF) {
|
||||||
|
CodePosition position = ts.tokenPosition;
|
||||||
if (tt == TokenStream.DOT) {
|
if (tt == TokenStream.DOT) {
|
||||||
ts.treatKeywordAsIdentifier = true;
|
ts.treatKeywordAsIdentifier = true;
|
||||||
mustMatchToken(ts, TokenStream.NAME, "msg.no.name.after.dot");
|
mustMatchToken(ts, TokenStream.NAME, "msg.no.name.after.dot");
|
||||||
@@ -1144,13 +1148,6 @@ public class Parser extends Observable {
|
|||||||
return null; // should never reach here
|
return null; // should never reach here
|
||||||
}
|
}
|
||||||
|
|
||||||
private static CodePosition getNextTokenPosition(TokenStream ts) throws IOException, JavaScriptException {
|
|
||||||
int tt = ts.getToken();
|
|
||||||
CodePosition result = ts.tokenPosition;
|
|
||||||
ts.ungetToken(tt);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
private int lastExprEndLine; // Hack to handle function expr termination.
|
private int lastExprEndLine; // Hack to handle function expr termination.
|
||||||
private final IRFactory nf;
|
private final IRFactory nf;
|
||||||
private boolean ok; // Did the parse encounter an error?
|
private boolean ok; // Did the parse encounter an error?
|
||||||
|
|||||||
@@ -16,15 +16,26 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.js.parser.sourcemaps
|
package org.jetbrains.kotlin.js.parser.sourcemaps
|
||||||
|
|
||||||
|
import java.io.PrintStream
|
||||||
import java.io.Reader
|
import java.io.Reader
|
||||||
|
|
||||||
class SourceMap(val sourceContentResolver: (String) -> Reader?) {
|
class SourceMap(val sourceContentResolver: (String) -> Reader?) {
|
||||||
val groups = mutableListOf<SourceMapGroup>()
|
val groups = mutableListOf<SourceMapGroup>()
|
||||||
|
|
||||||
|
fun debug(writer: PrintStream = System.out) {
|
||||||
|
for ((index, group) in groups.withIndex()) {
|
||||||
|
writer.print("${index + 1}:")
|
||||||
|
for (segment in group.segments) {
|
||||||
|
writer.print(" ${segment.generatedColumnNumber + 1}:${segment.sourceLineNumber + 1},${segment.sourceColumnNumber + 1}")
|
||||||
|
}
|
||||||
|
writer.println()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class SourceMapSegment(
|
class SourceMapSegment(
|
||||||
val generatedColumnNumber: Int,
|
val generatedColumnNumber: Int,
|
||||||
val sourceFileName: String,
|
val sourceFileName: String?,
|
||||||
val sourceLineNumber: Int,
|
val sourceLineNumber: Int,
|
||||||
val sourceColumnNumber: Int
|
val sourceColumnNumber: Int
|
||||||
)
|
)
|
||||||
|
|||||||
+98
-31
@@ -18,51 +18,118 @@ package org.jetbrains.kotlin.js.parser.sourcemaps
|
|||||||
|
|
||||||
import org.jetbrains.kotlin.js.backend.ast.*
|
import org.jetbrains.kotlin.js.backend.ast.*
|
||||||
|
|
||||||
class SourceMapLocationRemapper(val sourceMaps: Map<String, SourceMap>) {
|
class SourceMapLocationRemapper(private val sourceMap: SourceMap) {
|
||||||
fun remap(node: JsNode) {
|
fun remap(node: JsNode) {
|
||||||
node.accept(visitor)
|
val listCollector = JsNodeFlatListCollector()
|
||||||
|
node.accept(listCollector)
|
||||||
|
applySourceMap(listCollector.nodeList)
|
||||||
}
|
}
|
||||||
|
|
||||||
private val visitor = object : RecursiveJsVisitor() {
|
private fun applySourceMap(nodes: List<JsNode>) {
|
||||||
private var lastSourceMap: SourceMap? = null
|
var lastGroup: SourceMapGroup? = null
|
||||||
private var lastGroup: SourceMapGroup? = null
|
var lastGroupIndex = 0
|
||||||
private var lastSegmentIndex = 0
|
var lastSegment: SourceMapSegment? = null
|
||||||
|
var lastSegmentIndex = 0
|
||||||
|
|
||||||
override fun visitElement(node: JsNode) {
|
fun findCorrespondingSegment(node: SourceInfoAwareJsNode): SourceMapSegment? {
|
||||||
if (node is SourceInfoAwareJsNode) {
|
val source = node.source as? JsLocation ?: return null
|
||||||
if (!remapNode(node)) {
|
val group = sourceMap.groups.getOrElse(source.startLine) { return null }
|
||||||
node.source = null
|
|
||||||
|
if (lastGroup != group) {
|
||||||
|
if (lastGroup != null) {
|
||||||
|
val segmentsToSkip = lastGroup!!.segments.drop(lastSegmentIndex).toMutableList()
|
||||||
|
if (lastGroupIndex + 1 < source.startLine) {
|
||||||
|
segmentsToSkip += sourceMap.groups.subList((lastGroupIndex + 1), source.startLine).flatMap { it.segments }
|
||||||
|
}
|
||||||
|
|
||||||
|
segmentsToSkip.lastOrNull()?.let { lastSegment = it }
|
||||||
}
|
}
|
||||||
|
lastGroup = group
|
||||||
|
lastGroupIndex = source.startLine
|
||||||
|
lastSegmentIndex = 0
|
||||||
}
|
}
|
||||||
super.visitElement(node)
|
|
||||||
|
while (lastSegmentIndex < group.segments.size) {
|
||||||
|
val segment = group.segments[lastSegmentIndex]
|
||||||
|
if (segment.generatedColumnNumber > source.startChar) break
|
||||||
|
|
||||||
|
lastSegment = segment
|
||||||
|
lastSegmentIndex++
|
||||||
|
}
|
||||||
|
|
||||||
|
return lastSegment
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun remapNode(node: SourceInfoAwareJsNode): Boolean {
|
|
||||||
val source = node.source as? JsLocation ?: return false
|
|
||||||
|
|
||||||
val sourceMap = sourceMaps[source.file] ?: return false
|
for (node in nodes.asSequence().filterIsInstance<SourceInfoAwareJsNode>()) {
|
||||||
val group = sourceMap.groups.getOrElse(source.startLine) { return false }
|
val segment = findCorrespondingSegment(node)
|
||||||
if (group.segments.isEmpty()) return false
|
val sourceFileName = segment?.sourceFileName
|
||||||
|
node.source = if (sourceFileName != null) {
|
||||||
if (lastSourceMap != sourceMap || lastGroup != group) {
|
val location = JsLocation(segment.sourceFileName, segment.sourceLineNumber, segment.sourceColumnNumber)
|
||||||
lastSegmentIndex = 0
|
JsLocationWithEmbeddedSource(location, sourceMap) { sourceMap.sourceContentResolver(segment.sourceFileName) }
|
||||||
}
|
}
|
||||||
if (group.segments[lastSegmentIndex].generatedColumnNumber > source.startChar) {
|
else {
|
||||||
if (lastSegmentIndex == 0) return false
|
null
|
||||||
lastSegmentIndex = 0
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
while (lastSegmentIndex + 1 < group.segments.size) {
|
internal class JsNodeFlatListCollector : RecursiveJsVisitor() {
|
||||||
val nextIndex = lastSegmentIndex + 1
|
val nodeList = mutableListOf<JsNode>()
|
||||||
if (group.segments[nextIndex].generatedColumnNumber > source.startChar) break
|
|
||||||
lastSegmentIndex = nextIndex
|
override fun visitDoWhile(x: JsDoWhile) {
|
||||||
|
nodeList += x
|
||||||
|
accept(x.body)
|
||||||
|
accept(x.condition)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitBinaryExpression(x: JsBinaryOperation) = handleNode(x, x.arg1, x.arg2)
|
||||||
|
|
||||||
|
override fun visitConditional(x: JsConditional) = handleNode(x, x.testExpression, x.thenExpression, x.elseExpression)
|
||||||
|
|
||||||
|
override fun visitArrayAccess(x: JsArrayAccess) = handleNode(x, x.arrayExpression, x.indexExpression)
|
||||||
|
|
||||||
|
override fun visitArray(x: JsArrayLiteral) = handleNode(x, *x.expressions.toTypedArray())
|
||||||
|
|
||||||
|
override fun visitPrefixOperation(x: JsPrefixOperation) = handleNode(x, x.arg)
|
||||||
|
|
||||||
|
override fun visitPostfixOperation(x: JsPostfixOperation) = handleNode(x, x.arg)
|
||||||
|
|
||||||
|
override fun visitNameRef(nameRef: JsNameRef) = handleNode(nameRef, nameRef.qualifier)
|
||||||
|
|
||||||
|
override fun visitInvocation(invocation: JsInvocation) =
|
||||||
|
handleNode(invocation, invocation.qualifier, *invocation.arguments.toTypedArray())
|
||||||
|
|
||||||
|
override fun visitElement(node: JsNode) {
|
||||||
|
nodeList += node
|
||||||
|
node.acceptChildren(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun handleNode(node: JsNode, vararg children: JsNode?) {
|
||||||
|
val nonNullChildren = children.mapNotNull { it }
|
||||||
|
|
||||||
|
if (nonNullChildren.isEmpty()) {
|
||||||
|
nodeList += node
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
val firstChild = nonNullChildren.first()
|
||||||
|
if (node.isNotBefore(firstChild)) {
|
||||||
|
accept(firstChild)
|
||||||
|
nodeList += node
|
||||||
|
nonNullChildren.drop(1).forEach { accept(it) }
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
nodeList += node
|
||||||
|
nonNullChildren.forEach { accept(it) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
val segment = group.segments[lastSegmentIndex]
|
private fun JsNode.isNotBefore(other: JsNode): Boolean {
|
||||||
val location = JsLocation(segment.sourceFileName, segment.sourceLineNumber, segment.sourceColumnNumber)
|
val first = (source as? JsLocation ?: return false)
|
||||||
node.source = JsLocationWithEmbeddedSource(location, sourceMap) { sourceMap.sourceContentResolver(segment.sourceFileName) }
|
val second = (other.source as? JsLocation ?: return false)
|
||||||
|
if (first.file != second.file) return false
|
||||||
return true
|
return first.startLine > second.startLine || (first.startLine == second.startLine && first.startChar >= second.startChar)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -14,22 +14,6 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
|
||||||
* Copyright 2010-2017 JetBrains s.r.o.
|
|
||||||
*
|
|
||||||
* 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.jetbrains.kotlin.js.parser.sourcemaps
|
package org.jetbrains.kotlin.js.parser.sourcemaps
|
||||||
|
|
||||||
import org.json.JSONArray
|
import org.json.JSONArray
|
||||||
@@ -115,13 +99,15 @@ object SourceMapParser {
|
|||||||
if (stream.isEncodedInt) {
|
if (stream.isEncodedInt) {
|
||||||
stream.readInt() ?: return stream.createError("VLQ-encoded name index expected")
|
stream.readInt() ?: return stream.createError("VLQ-encoded name index expected")
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (sourceIndex !in sources.indices) {
|
if (sourceIndex !in sources.indices) {
|
||||||
return stream.createError("Source index $sourceIndex is out of bounds ${sources.indices}")
|
return stream.createError("Source index $sourceIndex is out of bounds ${sources.indices}")
|
||||||
|
}
|
||||||
|
currentGroup.segments += SourceMapSegment(jsColumn, sourceRoot + sources[sourceIndex], sourceLine, sourceColumn)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
currentGroup.segments += SourceMapSegment(jsColumn, null, -1, -1)
|
||||||
}
|
}
|
||||||
|
|
||||||
currentGroup.segments += SourceMapSegment(jsColumn, sourceRoot + sources[sourceIndex], sourceLine, sourceColumn)
|
|
||||||
|
|
||||||
when {
|
when {
|
||||||
stream.isEof -> return stream.createError("Unexpected EOF, ',' or ';' expected")
|
stream.isEof -> return stream.createError("Unexpected EOF, ',' or ';' expected")
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
|
|||||||
import org.jetbrains.kotlin.config.*
|
import org.jetbrains.kotlin.config.*
|
||||||
import org.jetbrains.kotlin.idea.KotlinFileType
|
import org.jetbrains.kotlin.idea.KotlinFileType
|
||||||
import org.jetbrains.kotlin.js.JavaScript
|
import org.jetbrains.kotlin.js.JavaScript
|
||||||
|
import org.jetbrains.kotlin.js.backend.JsToStringGenerationVisitor
|
||||||
import org.jetbrains.kotlin.js.backend.ast.*
|
import org.jetbrains.kotlin.js.backend.ast.*
|
||||||
import org.jetbrains.kotlin.js.config.EcmaVersion
|
import org.jetbrains.kotlin.js.config.EcmaVersion
|
||||||
import org.jetbrains.kotlin.js.config.JSConfigurationKeys
|
import org.jetbrains.kotlin.js.config.JSConfigurationKeys
|
||||||
@@ -42,7 +43,6 @@ import org.jetbrains.kotlin.js.dce.InputFile
|
|||||||
import org.jetbrains.kotlin.js.facade.*
|
import org.jetbrains.kotlin.js.facade.*
|
||||||
import org.jetbrains.kotlin.js.parser.parse
|
import org.jetbrains.kotlin.js.parser.parse
|
||||||
import org.jetbrains.kotlin.js.parser.sourcemaps.*
|
import org.jetbrains.kotlin.js.parser.sourcemaps.*
|
||||||
import org.jetbrains.kotlin.js.sourceMap.JsSourceGenerationVisitor
|
|
||||||
import org.jetbrains.kotlin.js.sourceMap.SourceFilePathResolver
|
import org.jetbrains.kotlin.js.sourceMap.SourceFilePathResolver
|
||||||
import org.jetbrains.kotlin.js.sourceMap.SourceMap3Builder
|
import org.jetbrains.kotlin.js.sourceMap.SourceMap3Builder
|
||||||
import org.jetbrains.kotlin.js.test.utils.*
|
import org.jetbrains.kotlin.js.test.utils.*
|
||||||
@@ -430,8 +430,8 @@ abstract class BasicBoxTest(
|
|||||||
|
|
||||||
val output = TextOutputImpl()
|
val output = TextOutputImpl()
|
||||||
val pathResolver = SourceFilePathResolver(mutableListOf(File(".")))
|
val pathResolver = SourceFilePathResolver(mutableListOf(File(".")))
|
||||||
val sourceMapBuilder = SourceMap3Builder(outputFile, output, "", SourceMapBuilderConsumer(pathResolver, false, false))
|
val sourceMapBuilder = SourceMap3Builder(outputFile, output, "")
|
||||||
generatedProgram.accept(JsSourceGenerationVisitor(output, sourceMapBuilder))
|
generatedProgram.accept(JsToStringGenerationVisitor(output, SourceMapBuilderConsumer(sourceMapBuilder, pathResolver, false, false)))
|
||||||
val code = output.toString()
|
val code = output.toString()
|
||||||
val generatedSourceMap = sourceMapBuilder.build()
|
val generatedSourceMap = sourceMapBuilder.build()
|
||||||
|
|
||||||
@@ -446,7 +446,7 @@ abstract class BasicBoxTest(
|
|||||||
is SourceMapError -> error("Could not parse source map: ${sourceMapParseResult.message}")
|
is SourceMapError -> error("Could not parse source map: ${sourceMapParseResult.message}")
|
||||||
}
|
}
|
||||||
|
|
||||||
val remapper = SourceMapLocationRemapper(mapOf(outputFile.path to sourceMap))
|
val remapper = SourceMapLocationRemapper(sourceMap)
|
||||||
remapper.remap(parsedProgram)
|
remapper.remap(parsedProgram)
|
||||||
|
|
||||||
val codeWithRemappedLines = parsedProgram.toStringWithLineNumbers()
|
val codeWithRemappedLines = parsedProgram.toStringWithLineNumbers()
|
||||||
|
|||||||
@@ -16,15 +16,14 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.js.test.optimizer
|
package org.jetbrains.kotlin.js.test.optimizer
|
||||||
|
|
||||||
|
|
||||||
import com.google.gwt.dev.js.rhino.CodePosition
|
import com.google.gwt.dev.js.rhino.CodePosition
|
||||||
import com.google.gwt.dev.js.rhino.ErrorReporter
|
import com.google.gwt.dev.js.rhino.ErrorReporter
|
||||||
import com.intellij.openapi.util.io.FileUtil
|
import com.intellij.openapi.util.io.FileUtil
|
||||||
|
import org.jetbrains.kotlin.js.backend.JsToStringGenerationVisitor
|
||||||
import org.jetbrains.kotlin.js.backend.ast.*
|
import org.jetbrains.kotlin.js.backend.ast.*
|
||||||
import org.jetbrains.kotlin.js.backend.ast.metadata.synthetic
|
import org.jetbrains.kotlin.js.backend.ast.metadata.synthetic
|
||||||
import org.jetbrains.kotlin.js.inline.clean.FunctionPostProcessor
|
import org.jetbrains.kotlin.js.inline.clean.FunctionPostProcessor
|
||||||
import org.jetbrains.kotlin.js.parser.parse
|
import org.jetbrains.kotlin.js.parser.parse
|
||||||
import org.jetbrains.kotlin.js.sourceMap.JsSourceGenerationVisitor
|
|
||||||
import org.jetbrains.kotlin.js.test.BasicBoxTest
|
import org.jetbrains.kotlin.js.test.BasicBoxTest
|
||||||
import org.jetbrains.kotlin.js.test.createScriptEngine
|
import org.jetbrains.kotlin.js.test.createScriptEngine
|
||||||
import org.jetbrains.kotlin.js.translate.utils.JsAstUtils
|
import org.jetbrains.kotlin.js.translate.utils.JsAstUtils
|
||||||
@@ -120,7 +119,7 @@ abstract class BasicOptimizerTest(private var basePath: String) {
|
|||||||
|
|
||||||
private fun astToString(ast: List<JsStatement>): String {
|
private fun astToString(ast: List<JsStatement>): String {
|
||||||
val output = TextOutputImpl()
|
val output = TextOutputImpl()
|
||||||
val visitor = JsSourceGenerationVisitor(output, null)
|
val visitor = JsToStringGenerationVisitor(output)
|
||||||
for (stmt in ast) {
|
for (stmt in ast) {
|
||||||
stmt.accept(visitor)
|
stmt.accept(visitor)
|
||||||
}
|
}
|
||||||
|
|||||||
+8
-52
@@ -16,64 +16,20 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.js.test.utils
|
package org.jetbrains.kotlin.js.test.utils
|
||||||
|
|
||||||
import com.intellij.psi.PsiElement
|
|
||||||
import org.jetbrains.kotlin.js.backend.ast.*
|
import org.jetbrains.kotlin.js.backend.ast.*
|
||||||
|
|
||||||
class AmbiguousAstSourcePropagation : RecursiveJsVisitor() {
|
class AmbiguousAstSourcePropagation : RecursiveJsVisitor() {
|
||||||
private var sourceDefined = false
|
private var lastSource: Any? = null
|
||||||
|
|
||||||
override fun visitConditional(x: JsConditional) = acceptAll(x, x.testExpression, x.thenExpression, x.elseExpression)
|
|
||||||
|
|
||||||
override fun visitBinaryExpression(x: JsBinaryOperation) = acceptAll(x, x.arg1, x.arg2)
|
|
||||||
|
|
||||||
override fun visitPostfixOperation(x: JsPostfixOperation) = acceptAll(x, x.arg)
|
|
||||||
|
|
||||||
override fun visitArrayAccess(x: JsArrayAccess) = acceptAll(x, x.arrayExpression, x.indexExpression)
|
|
||||||
|
|
||||||
override fun visitPropertyInitializer(x: JsPropertyInitializer) = acceptAll(x, x.labelExpr, x.valueExpr)
|
|
||||||
|
|
||||||
override fun visitInvocation(invocation: JsInvocation) = acceptAll(invocation, invocation.qualifier,
|
|
||||||
*invocation.arguments.toTypedArray())
|
|
||||||
|
|
||||||
override fun visitNameRef(nameRef: JsNameRef) {
|
|
||||||
val qualifier = nameRef.qualifier
|
|
||||||
if (qualifier != null) {
|
|
||||||
acceptAll(nameRef, qualifier)
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
super.visitNameRef(nameRef)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun visitElement(node: JsNode) {
|
override fun visitElement(node: JsNode) {
|
||||||
val old = sourceDefined
|
val source = node.source
|
||||||
propagate(node)
|
if (source == null && node is JsExpression) {
|
||||||
|
node.source = lastSource
|
||||||
|
}
|
||||||
|
|
||||||
sourceDefined = false
|
val oldLastSource = lastSource
|
||||||
|
lastSource = node.source
|
||||||
super.visitElement(node)
|
super.visitElement(node)
|
||||||
sourceDefined = old
|
lastSource = oldLastSource
|
||||||
}
|
|
||||||
|
|
||||||
private fun acceptAll(node: JsNode, first: JsNode, vararg remaining: JsNode) {
|
|
||||||
val old = sourceDefined
|
|
||||||
propagate(node)
|
|
||||||
|
|
||||||
accept(first)
|
|
||||||
|
|
||||||
sourceDefined = false
|
|
||||||
remaining.forEach { accept(it) }
|
|
||||||
sourceDefined = old
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun propagate(node: JsNode) {
|
|
||||||
if (!sourceDefined) {
|
|
||||||
val source = node.source
|
|
||||||
if (source is JsLocationWithSource || source is PsiElement) {
|
|
||||||
sourceDefined = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (node !is JsExpressionStatement) {
|
|
||||||
node.source = null
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -87,10 +87,9 @@ class LineCollector : RecursiveJsVisitor() {
|
|||||||
|
|
||||||
override fun visitDoWhile(x: JsDoWhile) {
|
override fun visitDoWhile(x: JsDoWhile) {
|
||||||
withStatement(x) {
|
withStatement(x) {
|
||||||
handleNodeLocation(x)
|
x.body.accept(this)
|
||||||
x.condition.accept(this)
|
x.condition.accept(this)
|
||||||
}
|
}
|
||||||
x.body.accept(this)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitFor(x: JsFor) {
|
override fun visitFor(x: JsFor) {
|
||||||
@@ -130,8 +129,8 @@ class LineCollector : RecursiveJsVisitor() {
|
|||||||
override fun visit(x: JsSwitch) {
|
override fun visit(x: JsSwitch) {
|
||||||
withStatement(x) {
|
withStatement(x) {
|
||||||
x.expression.accept(this)
|
x.expression.accept(this)
|
||||||
|
x.cases.forEach { accept(it) }
|
||||||
}
|
}
|
||||||
x.cases.forEach { accept(it) }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitThrow(x: JsThrow) {
|
override fun visitThrow(x: JsThrow) {
|
||||||
@@ -140,6 +139,14 @@ class LineCollector : RecursiveJsVisitor() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun visitTry(x: JsTry) {
|
||||||
|
withStatement(x) {
|
||||||
|
x.tryBlock.acceptChildren(this)
|
||||||
|
x.catches?.forEach { accept(it) }
|
||||||
|
x.finallyBlock?.acceptChildren(this)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun withStatement(statement: JsStatement, action: () -> Unit) {
|
private fun withStatement(statement: JsStatement, action: () -> Unit) {
|
||||||
val oldStatement = currentStatement
|
val oldStatement = currentStatement
|
||||||
currentStatement = statement
|
currentStatement = statement
|
||||||
|
|||||||
@@ -73,6 +73,11 @@ class LineOutputToStringVisitor(output: TextOutput, val lineCollector: LineColle
|
|||||||
super.visitReturn(x)
|
super.visitReturn(x)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun visitTry(x: JsTry) {
|
||||||
|
printLineNumbers(x)
|
||||||
|
super.visitTry(x)
|
||||||
|
}
|
||||||
|
|
||||||
override fun visit(x: JsSwitch) {
|
override fun visit(x: JsSwitch) {
|
||||||
printLineNumbers(x)
|
printLineNumbers(x)
|
||||||
super.visit(x)
|
super.visit(x)
|
||||||
|
|||||||
@@ -19,17 +19,24 @@ package org.jetbrains.kotlin.js.facade;
|
|||||||
import com.intellij.openapi.editor.Document;
|
import com.intellij.openapi.editor.Document;
|
||||||
import com.intellij.psi.PsiElement;
|
import com.intellij.psi.PsiElement;
|
||||||
import com.intellij.psi.PsiFile;
|
import com.intellij.psi.PsiFile;
|
||||||
import com.intellij.util.PairConsumer;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
import org.jetbrains.kotlin.js.backend.SourceLocationConsumer;
|
||||||
|
import org.jetbrains.kotlin.js.backend.ast.JsLocation;
|
||||||
import org.jetbrains.kotlin.js.backend.ast.JsLocationWithSource;
|
import org.jetbrains.kotlin.js.backend.ast.JsLocationWithSource;
|
||||||
import org.jetbrains.kotlin.js.sourceMap.SourceFilePathResolver;
|
import org.jetbrains.kotlin.js.sourceMap.SourceFilePathResolver;
|
||||||
import org.jetbrains.kotlin.js.sourceMap.SourceMapBuilder;
|
import org.jetbrains.kotlin.js.sourceMap.SourceMapMappingConsumer;
|
||||||
|
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
import java.nio.charset.Charset;
|
import java.nio.charset.Charset;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
public class SourceMapBuilderConsumer implements PairConsumer<SourceMapBuilder, Object> {
|
public class SourceMapBuilderConsumer implements SourceLocationConsumer {
|
||||||
|
@NotNull
|
||||||
|
private final SourceMapMappingConsumer mappingConsumer;
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
private final SourceFilePathResolver pathResolver;
|
private final SourceFilePathResolver pathResolver;
|
||||||
|
|
||||||
@@ -37,25 +44,50 @@ public class SourceMapBuilderConsumer implements PairConsumer<SourceMapBuilder,
|
|||||||
|
|
||||||
private final boolean provideExternalModuleContent;
|
private final boolean provideExternalModuleContent;
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
private final List<Object> sourceStack = new ArrayList<>();
|
||||||
|
|
||||||
public SourceMapBuilderConsumer(
|
public SourceMapBuilderConsumer(
|
||||||
|
@NotNull SourceMapMappingConsumer mappingConsumer,
|
||||||
@NotNull SourceFilePathResolver pathResolver,
|
@NotNull SourceFilePathResolver pathResolver,
|
||||||
boolean provideCurrentModuleContent, boolean provideExternalModuleContent
|
boolean provideCurrentModuleContent, boolean provideExternalModuleContent
|
||||||
) {
|
) {
|
||||||
|
this.mappingConsumer = mappingConsumer;
|
||||||
this.pathResolver = pathResolver;
|
this.pathResolver = pathResolver;
|
||||||
this.provideCurrentModuleContent = provideCurrentModuleContent;
|
this.provideCurrentModuleContent = provideCurrentModuleContent;
|
||||||
this.provideExternalModuleContent = provideExternalModuleContent;
|
this.provideExternalModuleContent = provideExternalModuleContent;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void consume(SourceMapBuilder builder, Object sourceInfo) {
|
public void newLine() {
|
||||||
|
mappingConsumer.newLine();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void pushSourceInfo(@Nullable Object info) {
|
||||||
|
sourceStack.add(info);
|
||||||
|
addMapping(info);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void popSourceInfo() {
|
||||||
|
sourceStack.remove(sourceStack.size() - 1);
|
||||||
|
Object sourceInfo = !sourceStack.isEmpty() ? sourceStack.get(sourceStack.size() - 1) : null;
|
||||||
|
addMapping(sourceInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addMapping(@Nullable Object sourceInfo) {
|
||||||
|
if (sourceInfo == null) {
|
||||||
|
mappingConsumer.addEmptyMapping();
|
||||||
|
}
|
||||||
if (sourceInfo instanceof PsiElement) {
|
if (sourceInfo instanceof PsiElement) {
|
||||||
PsiElement element = (PsiElement) sourceInfo;
|
PsiElement element = (PsiElement) sourceInfo;
|
||||||
PsiFile psiFile = element.getContainingFile();
|
PsiFile psiFile = element.getContainingFile();
|
||||||
int offset = element.getNode().getStartOffset();
|
int offset = element.getNode().getStartOffset();
|
||||||
Document document = psiFile.getViewProvider().getDocument();
|
Document document = psiFile.getViewProvider().getDocument();
|
||||||
assert document != null;
|
assert document != null;
|
||||||
int line = document.getLineNumber(offset);
|
int sourceLine = document.getLineNumber(offset);
|
||||||
int column = offset - document.getLineStartOffset(line);
|
int sourceColumn = offset - document.getLineStartOffset(sourceLine);
|
||||||
|
|
||||||
File file = new File(psiFile.getViewProvider().getVirtualFile().getPath());
|
File file = new File(psiFile.getViewProvider().getVirtualFile().getPath());
|
||||||
try {
|
try {
|
||||||
@@ -73,7 +105,8 @@ public class SourceMapBuilderConsumer implements PairConsumer<SourceMapBuilder,
|
|||||||
else {
|
else {
|
||||||
contentSupplier = () -> null;
|
contentSupplier = () -> null;
|
||||||
}
|
}
|
||||||
builder.addMapping(pathResolver.getPathRelativeToSourceRoots(file), null, contentSupplier, line, column);
|
mappingConsumer.addMapping(pathResolver.getPathRelativeToSourceRoots(file), null, contentSupplier,
|
||||||
|
sourceLine, sourceColumn);
|
||||||
}
|
}
|
||||||
catch (IOException e) {
|
catch (IOException e) {
|
||||||
throw new RuntimeException("IO error occurred generating source maps", e);
|
throw new RuntimeException("IO error occurred generating source maps", e);
|
||||||
@@ -82,7 +115,7 @@ public class SourceMapBuilderConsumer implements PairConsumer<SourceMapBuilder,
|
|||||||
else if (sourceInfo instanceof JsLocationWithSource) {
|
else if (sourceInfo instanceof JsLocationWithSource) {
|
||||||
JsLocationWithSource location = (JsLocationWithSource) sourceInfo;
|
JsLocationWithSource location = (JsLocationWithSource) sourceInfo;
|
||||||
Supplier<Reader> contentSupplier = provideExternalModuleContent ? location.getSourceProvider()::invoke : () -> null;
|
Supplier<Reader> contentSupplier = provideExternalModuleContent ? location.getSourceProvider()::invoke : () -> null;
|
||||||
builder.addMapping(location.getFile(), location.getIdentityObject(), contentSupplier,
|
mappingConsumer.addMapping(location.getFile(), location.getIdentityObject(), contentSupplier,
|
||||||
location.getStartLine(), location.getStartChar());
|
location.getStartLine(), location.getStartChar());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,14 +20,15 @@ import com.intellij.openapi.util.text.StringUtil
|
|||||||
import com.intellij.openapi.vfs.VfsUtilCore
|
import com.intellij.openapi.vfs.VfsUtilCore
|
||||||
import org.jetbrains.kotlin.backend.common.output.*
|
import org.jetbrains.kotlin.backend.common.output.*
|
||||||
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
|
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
|
||||||
|
import org.jetbrains.kotlin.js.backend.JsToStringGenerationVisitor
|
||||||
|
import org.jetbrains.kotlin.js.backend.NoOpSourceLocationConsumer
|
||||||
import org.jetbrains.kotlin.js.backend.ast.JsProgram
|
import org.jetbrains.kotlin.js.backend.ast.JsProgram
|
||||||
import org.jetbrains.kotlin.js.config.JSConfigurationKeys
|
import org.jetbrains.kotlin.js.config.JSConfigurationKeys
|
||||||
import org.jetbrains.kotlin.js.config.JsConfig
|
import org.jetbrains.kotlin.js.config.JsConfig
|
||||||
import org.jetbrains.kotlin.js.config.SourceMapSourceEmbedding
|
import org.jetbrains.kotlin.js.config.SourceMapSourceEmbedding
|
||||||
import org.jetbrains.kotlin.js.sourceMap.JsSourceGenerationVisitor
|
|
||||||
import org.jetbrains.kotlin.js.sourceMap.SourceFilePathResolver
|
import org.jetbrains.kotlin.js.sourceMap.SourceFilePathResolver
|
||||||
import org.jetbrains.kotlin.js.sourceMap.SourceMap3Builder
|
import org.jetbrains.kotlin.js.sourceMap.SourceMap3Builder
|
||||||
import org.jetbrains.kotlin.js.sourceMap.SourceMapBuilder
|
import org.jetbrains.kotlin.js.backend.SourceLocationConsumer
|
||||||
import org.jetbrains.kotlin.js.translate.general.FileTranslationResult
|
import org.jetbrains.kotlin.js.translate.general.FileTranslationResult
|
||||||
import org.jetbrains.kotlin.js.util.TextOutput
|
import org.jetbrains.kotlin.js.util.TextOutput
|
||||||
import org.jetbrains.kotlin.js.util.TextOutputImpl
|
import org.jetbrains.kotlin.js.util.TextOutputImpl
|
||||||
@@ -55,26 +56,37 @@ abstract class TranslationResult protected constructor(val diagnostics: Diagnost
|
|||||||
val fileTranslationResults: Map<KtFile, FileTranslationResult>
|
val fileTranslationResults: Map<KtFile, FileTranslationResult>
|
||||||
) : TranslationResult(diagnostics) {
|
) : TranslationResult(diagnostics) {
|
||||||
@Suppress("unused") // Used in kotlin-web-demo in WebDemoTranslatorFacade
|
@Suppress("unused") // Used in kotlin-web-demo in WebDemoTranslatorFacade
|
||||||
fun getCode(): String = getCode(TextOutputImpl(), sourceMapBuilder = null)
|
fun getCode(): String {
|
||||||
|
val output = TextOutputImpl()
|
||||||
|
getCode(output, sourceLocationConsumer = null)
|
||||||
|
return output.toString()
|
||||||
|
}
|
||||||
|
|
||||||
fun getOutputFiles(outputFile: File, outputPrefixFile: File?, outputPostfixFile: File?): OutputFileCollection {
|
fun getOutputFiles(outputFile: File, outputPrefixFile: File?, outputPostfixFile: File?): OutputFileCollection {
|
||||||
val output = TextOutputImpl()
|
val output = TextOutputImpl()
|
||||||
val sourceMapBuilder =
|
|
||||||
|
val sourceMapBuilder = SourceMap3Builder(outputFile, output, config.sourceMapPrefix)
|
||||||
|
val sourceMapBuilderConsumer =
|
||||||
if (config.configuration.getBoolean(JSConfigurationKeys.SOURCE_MAP)) {
|
if (config.configuration.getBoolean(JSConfigurationKeys.SOURCE_MAP)) {
|
||||||
val sourceRoots = config.sourceMapRoots.map { File(it) }
|
val sourceRoots = config.sourceMapRoots.map { File(it) }
|
||||||
val sourceMapContentEmbedding = config.sourceMapContentEmbedding
|
val sourceMapContentEmbedding = config.sourceMapContentEmbedding
|
||||||
val pathResolver = SourceFilePathResolver(sourceRoots)
|
val pathResolver = SourceFilePathResolver(sourceRoots)
|
||||||
val consumer = SourceMapBuilderConsumer(
|
SourceMapBuilderConsumer(
|
||||||
|
sourceMapBuilder,
|
||||||
pathResolver,
|
pathResolver,
|
||||||
sourceMapContentEmbedding == SourceMapSourceEmbedding.ALWAYS,
|
sourceMapContentEmbedding == SourceMapSourceEmbedding.ALWAYS,
|
||||||
sourceMapContentEmbedding != SourceMapSourceEmbedding.NEVER)
|
sourceMapContentEmbedding != SourceMapSourceEmbedding.NEVER)
|
||||||
SourceMap3Builder(outputFile, output, config.sourceMapPrefix, consumer)
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
null
|
null
|
||||||
}
|
}
|
||||||
|
|
||||||
val code = getCode(output, sourceMapBuilder)
|
getCode(output, sourceMapBuilderConsumer)
|
||||||
|
if (sourceMapBuilderConsumer != null) {
|
||||||
|
sourceMapBuilder.addLink()
|
||||||
|
}
|
||||||
|
val code = output.toString()
|
||||||
|
|
||||||
val prefix = outputPrefixFile?.readText() ?: ""
|
val prefix = outputPrefixFile?.readText() ?: ""
|
||||||
val postfix = outputPostfixFile?.readText() ?: ""
|
val postfix = outputPostfixFile?.readText() ?: ""
|
||||||
val sourceFiles = files.map {
|
val sourceFiles = files.map {
|
||||||
@@ -108,18 +120,18 @@ abstract class TranslationResult protected constructor(val diagnostics: Diagnost
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sourceMapBuilder != null) {
|
if (sourceMapBuilderConsumer != null) {
|
||||||
sourceMapBuilder.skipLinesAtBeginning(StringUtil.getLineBreakCount(prefix))
|
sourceMapBuilder.skipLinesAtBeginning(StringUtil.getLineBreakCount(prefix))
|
||||||
val sourceMapFile = SimpleOutputFile(sourceFiles, sourceMapBuilder.outFile.name, sourceMapBuilder.build())
|
val sourceMapFile = SimpleOutputFile(sourceFiles, sourceMapBuilder.outFile.name, sourceMapBuilder.build())
|
||||||
outputFiles.add(sourceMapFile)
|
outputFiles.add(sourceMapFile)
|
||||||
|
sourceMapBuilder.addLink()
|
||||||
}
|
}
|
||||||
|
|
||||||
return SimpleOutputFileCollection(outputFiles)
|
return SimpleOutputFileCollection(outputFiles)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getCode(output: TextOutput, sourceMapBuilder: SourceMapBuilder?): String {
|
private fun getCode(output: TextOutput, sourceLocationConsumer: SourceLocationConsumer?) {
|
||||||
program.accept(JsSourceGenerationVisitor(output, sourceMapBuilder))
|
program.accept(JsToStringGenerationVisitor(output, sourceLocationConsumer ?: NoOpSourceLocationConsumer))
|
||||||
return output.toString()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,85 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2010-2017 JetBrains s.r.o.
|
|
||||||
*
|
|
||||||
* 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.jetbrains.kotlin.js.sourceMap;
|
|
||||||
|
|
||||||
import org.jetbrains.kotlin.js.backend.JsToStringGenerationVisitor;
|
|
||||||
import org.jetbrains.kotlin.js.backend.ast.*;
|
|
||||||
import org.jetbrains.kotlin.js.util.TextOutput;
|
|
||||||
import com.intellij.util.SmartList;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
|
||||||
import org.jetbrains.annotations.Nullable;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
public class JsSourceGenerationVisitor extends JsToStringGenerationVisitor implements TextOutput.OutListener {
|
|
||||||
@Nullable
|
|
||||||
private final SourceMapBuilder sourceMapBuilder;
|
|
||||||
|
|
||||||
private final List<Object> pendingSources = new SmartList<>();
|
|
||||||
|
|
||||||
public JsSourceGenerationVisitor(TextOutput out, @Nullable SourceMapBuilder sourceMapBuilder) {
|
|
||||||
super(out);
|
|
||||||
this.sourceMapBuilder = sourceMapBuilder;
|
|
||||||
out.setOutListener(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void newLined() {
|
|
||||||
if (sourceMapBuilder != null) {
|
|
||||||
sourceMapBuilder.newLine();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void indentedAfterNewLine() {
|
|
||||||
if (pendingSources.isEmpty()) return;
|
|
||||||
|
|
||||||
assert sourceMapBuilder != null;
|
|
||||||
for (Object source : pendingSources) {
|
|
||||||
sourceMapBuilder.processSourceInfo(source);
|
|
||||||
}
|
|
||||||
pendingSources.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void accept(JsNode node) {
|
|
||||||
mapSource(node);
|
|
||||||
super.accept(node);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void mapSource(JsNode node) {
|
|
||||||
if (sourceMapBuilder != null) {
|
|
||||||
Object sourceInfo = node.getSource();
|
|
||||||
if (sourceInfo != null) {
|
|
||||||
if (p.isJustNewlined()) {
|
|
||||||
pendingSources.add(sourceInfo);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
sourceMapBuilder.processSourceInfo(sourceInfo);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void visitProgram(@NotNull JsProgram program) {
|
|
||||||
program.acceptChildren(this);
|
|
||||||
if (sourceMapBuilder != null) {
|
|
||||||
sourceMapBuilder.addLink();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -17,11 +17,11 @@
|
|||||||
package org.jetbrains.kotlin.js.sourceMap;
|
package org.jetbrains.kotlin.js.sourceMap;
|
||||||
|
|
||||||
import com.intellij.openapi.util.text.StringUtil;
|
import com.intellij.openapi.util.text.StringUtil;
|
||||||
import com.intellij.util.PairConsumer;
|
|
||||||
import gnu.trove.TObjectIntHashMap;
|
import gnu.trove.TObjectIntHashMap;
|
||||||
import kotlin.io.TextStreamsKt;
|
import kotlin.io.TextStreamsKt;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
import org.jetbrains.kotlin.js.backend.JsToStringGenerationVisitor;
|
import org.jetbrains.kotlin.js.backend.JsToStringGenerationVisitor;
|
||||||
import org.jetbrains.kotlin.js.common.SourceInfo;
|
|
||||||
import org.jetbrains.kotlin.js.util.TextOutput;
|
import org.jetbrains.kotlin.js.util.TextOutput;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
@@ -35,7 +35,6 @@ public class SourceMap3Builder implements SourceMapBuilder {
|
|||||||
private final File generatedFile;
|
private final File generatedFile;
|
||||||
private final TextOutput textOutput;
|
private final TextOutput textOutput;
|
||||||
private final String pathPrefix;
|
private final String pathPrefix;
|
||||||
private final PairConsumer<SourceMapBuilder, Object> sourceInfoConsumer;
|
|
||||||
|
|
||||||
private final TObjectIntHashMap<SourceKey> sources = new TObjectIntHashMap<SourceKey>() {
|
private final TObjectIntHashMap<SourceKey> sources = new TObjectIntHashMap<SourceKey>() {
|
||||||
@Override
|
@Override
|
||||||
@@ -52,13 +51,16 @@ public class SourceMap3Builder implements SourceMapBuilder {
|
|||||||
private int previousSourceIndex;
|
private int previousSourceIndex;
|
||||||
private int previousSourceLine;
|
private int previousSourceLine;
|
||||||
private int previousSourceColumn;
|
private int previousSourceColumn;
|
||||||
|
private int previousMappingOffset;
|
||||||
|
private int previousPreviousSourceIndex;
|
||||||
|
private int previousPreviousSourceLine;
|
||||||
|
private int previousPreviousSourceColumn;
|
||||||
|
private boolean currentMappingIsEmpty = true;
|
||||||
|
|
||||||
public SourceMap3Builder(File generatedFile, TextOutput textOutput, String pathPrefix,
|
public SourceMap3Builder(File generatedFile, TextOutput textOutput, String pathPrefix) {
|
||||||
PairConsumer<SourceMapBuilder, Object> sourceInfoConsumer) {
|
|
||||||
this.generatedFile = generatedFile;
|
this.generatedFile = generatedFile;
|
||||||
this.textOutput = textOutput;
|
this.textOutput = textOutput;
|
||||||
this.pathPrefix = pathPrefix;
|
this.pathPrefix = pathPrefix;
|
||||||
this.sourceInfoConsumer = sourceInfoConsumer;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -130,14 +132,6 @@ public class SourceMap3Builder implements SourceMapBuilder {
|
|||||||
out.insert(0, StringUtil.repeatSymbol(';', count));
|
out.insert(0, StringUtil.repeatSymbol(';', count));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void processSourceInfo(Object sourceInfo) {
|
|
||||||
if (sourceInfo instanceof SourceInfo) {
|
|
||||||
throw new UnsupportedOperationException("SourceInfo is not yet supported");
|
|
||||||
}
|
|
||||||
sourceInfoConsumer.consume(this, sourceInfo);
|
|
||||||
}
|
|
||||||
|
|
||||||
private int getSourceIndex(String source, Object identityObject, Supplier<Reader> contentSupplier) {
|
private int getSourceIndex(String source, Object identityObject, Supplier<Reader> contentSupplier) {
|
||||||
SourceKey key = new SourceKey(source, identityObject);
|
SourceKey key = new SourceKey(source, identityObject);
|
||||||
int sourceIndex = sources.get(key);
|
int sourceIndex = sources.get(key);
|
||||||
@@ -152,26 +146,20 @@ public class SourceMap3Builder implements SourceMapBuilder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void addMapping(String source, Object identityObject, Supplier<Reader> sourceContent, int sourceLine, int sourceColumn) {
|
public void addMapping(
|
||||||
|
@NotNull String source, @Nullable Object identityObject, @NotNull Supplier<Reader> sourceContent,
|
||||||
|
int sourceLine, int sourceColumn
|
||||||
|
) {
|
||||||
source = source.replace(File.separatorChar, '/');
|
source = source.replace(File.separatorChar, '/');
|
||||||
boolean newGroupStarted = previousGeneratedColumn == -1;
|
int sourceIndex = getSourceIndex(source, identityObject, sourceContent);
|
||||||
if (newGroupStarted) {
|
|
||||||
previousGeneratedColumn = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int columnDiff = textOutput.getColumn() - previousGeneratedColumn;
|
if (!currentMappingIsEmpty && previousSourceIndex == sourceIndex && previousSourceLine == sourceLine &&
|
||||||
if (!newGroupStarted && columnDiff == 0) {
|
previousSourceColumn == sourceColumn) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!newGroupStarted) {
|
|
||||||
out.append(',');
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO fix sections overlapping
|
startMapping();
|
||||||
// assert columnDiff != 0;
|
|
||||||
Base64VLQ.encode(out, columnDiff);
|
|
||||||
previousGeneratedColumn = textOutput.getColumn();
|
|
||||||
int sourceIndex = getSourceIndex(source, identityObject, sourceContent);
|
|
||||||
Base64VLQ.encode(out, sourceIndex - previousSourceIndex);
|
Base64VLQ.encode(out, sourceIndex - previousSourceIndex);
|
||||||
previousSourceIndex = sourceIndex;
|
previousSourceIndex = sourceIndex;
|
||||||
|
|
||||||
@@ -180,6 +168,44 @@ public class SourceMap3Builder implements SourceMapBuilder {
|
|||||||
|
|
||||||
Base64VLQ.encode(out, sourceColumn - previousSourceColumn);
|
Base64VLQ.encode(out, sourceColumn - previousSourceColumn);
|
||||||
previousSourceColumn = sourceColumn;
|
previousSourceColumn = sourceColumn;
|
||||||
|
|
||||||
|
currentMappingIsEmpty = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addEmptyMapping() {
|
||||||
|
if (!currentMappingIsEmpty) {
|
||||||
|
startMapping();
|
||||||
|
currentMappingIsEmpty = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void startMapping() {
|
||||||
|
boolean newGroupStarted = previousGeneratedColumn == -1;
|
||||||
|
if (newGroupStarted) {
|
||||||
|
previousGeneratedColumn = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int columnDiff = textOutput.getColumn() - previousGeneratedColumn;
|
||||||
|
if (!newGroupStarted) {
|
||||||
|
out.append(',');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (columnDiff > 0 || newGroupStarted) {
|
||||||
|
Base64VLQ.encode(out, columnDiff);
|
||||||
|
previousGeneratedColumn = textOutput.getColumn();
|
||||||
|
|
||||||
|
previousMappingOffset = out.length();
|
||||||
|
previousPreviousSourceIndex = previousSourceIndex;
|
||||||
|
previousPreviousSourceLine = previousSourceLine;
|
||||||
|
previousPreviousSourceColumn = previousSourceColumn;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
out.setLength(previousMappingOffset);
|
||||||
|
previousSourceIndex = previousPreviousSourceIndex;
|
||||||
|
previousSourceLine = previousPreviousSourceLine;
|
||||||
|
previousSourceColumn = previousPreviousSourceColumn;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2010-2015 JetBrains s.r.o.
|
* Copyright 2010-2017 JetBrains s.r.o.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -17,18 +17,10 @@
|
|||||||
package org.jetbrains.kotlin.js.sourceMap;
|
package org.jetbrains.kotlin.js.sourceMap;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.Reader;
|
|
||||||
import java.util.function.Supplier;
|
|
||||||
|
|
||||||
public interface SourceMapBuilder {
|
|
||||||
void newLine();
|
|
||||||
|
|
||||||
|
public interface SourceMapBuilder extends SourceMapMappingConsumer {
|
||||||
void skipLinesAtBeginning(int count);
|
void skipLinesAtBeginning(int count);
|
||||||
|
|
||||||
void addMapping(String source, Object identityObject, Supplier<Reader> sourceContent, int sourceLine, int sourceColumn);
|
|
||||||
|
|
||||||
void processSourceInfo(Object info);
|
|
||||||
|
|
||||||
void addLink();
|
void addLink();
|
||||||
|
|
||||||
File getOutFile();
|
File getOutFile();
|
||||||
|
|||||||
@@ -0,0 +1,35 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2017 JetBrains s.r.o.
|
||||||
|
*
|
||||||
|
* 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.jetbrains.kotlin.js.sourceMap;
|
||||||
|
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.Reader;
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
|
public interface SourceMapMappingConsumer {
|
||||||
|
void newLine();
|
||||||
|
|
||||||
|
void addMapping(
|
||||||
|
@NotNull String source, @Nullable Object sourceIdentity, @NotNull Supplier<Reader> sourceSupplier,
|
||||||
|
int sourceLine, int sourceColumn
|
||||||
|
);
|
||||||
|
|
||||||
|
void addEmptyMapping();
|
||||||
|
}
|
||||||
@@ -6,4 +6,4 @@ fun box(x: Int, y: Int) {
|
|||||||
|
|
||||||
fun foo(x: Int) = x
|
fun foo(x: Int) = x
|
||||||
|
|
||||||
// LINES: 3 3 3 4 4 4 4 2 3 7
|
// LINES: 3 3 * 3 4 4 * 4 4 2 3 7
|
||||||
@@ -13,4 +13,4 @@ fun box() {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// LINES: 8 3 2 3 3 3 8 11 3 7 12 3 3 4
|
// LINES: 8 3 2 3 3 8 11 * 3 7 12 3 3 4
|
||||||
@@ -6,4 +6,4 @@ enum class Foo {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// LINES: 1 1 1 1 2 4 * 2 2 4 5 * 4 4 4 4 * 1 * 1 1 1 1
|
// LINES: 1 1 1 1 2 4 * 2 2 4 5 * 4 4 4 4 * 1 * 1 1 1
|
||||||
+1
-1
@@ -10,4 +10,4 @@ enum class E {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// LINES: 1 1 1 1 2 4 8 * 2 2 4 4 5 * 4 4 8 8 9 * 8 8 * 1 * 1 1 1 1 1 1
|
// LINES: 1 1 1 1 2 4 8 * 2 2 4 4 5 * 4 4 8 8 9 * 8 8 * 1 * 1 1 1 1 1
|
||||||
+1
-1
@@ -21,4 +21,4 @@ fun bar(x: Int) {
|
|||||||
println("%")
|
println("%")
|
||||||
}
|
}
|
||||||
|
|
||||||
// LINES: 2 3 4 7 9 10 11 14 16 * 20 * 2 3 4 3 7 9 10 11 10 14 16 20 21
|
// LINES: 2 3 4 7 9 10 11 14 16 * 20 * 2 3 4 3 7 9 10 11 10 14 16 * 20 21
|
||||||
@@ -8,4 +8,4 @@ enum class E {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// LINES: 1 1 1 1 2 3 4 * 2 2 * 3 3 4 4 6 * 4 4 * 1 * 1 1 1 1 1 1
|
// LINES: 1 1 1 1 2 3 4 * 2 2 * 3 3 4 4 6 * 4 4 * 1 * 1 1 1 1 1
|
||||||
@@ -12,4 +12,4 @@ fun box() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// LINES: 5 2 3 5 8 3 4 9 3 11
|
// LINES: 5 2 3 5 8 * 3 4 9 3 11
|
||||||
Vendored
+2
-2
@@ -3,10 +3,10 @@
|
|||||||
<head>
|
<head>
|
||||||
<script type="application/javascript" src="../../../dist/js/kotlin.js"></script>
|
<script type="application/javascript" src="../../../dist/js/kotlin.js"></script>
|
||||||
<script type="application/javascript" src="../../../dist/classes/kotlin-test-js/kotlin-test.js"></script>
|
<script type="application/javascript" src="../../../dist/classes/kotlin-test-js/kotlin-test.js"></script>
|
||||||
<script type="application/javascript" src="../../../js/js.translator/testData/out/codegen/box/arrays/primitiveArrays_v5.js"></script>
|
<script type="application/javascript" src="out/box/expression/try/tryCatchExpr_v5.js"></script>
|
||||||
|
|
||||||
<script type="application/javascript">
|
<script type="application/javascript">
|
||||||
console.log(JS_TESTS.box());
|
console.log(JS_TESTS.foo.box());
|
||||||
</script>
|
</script>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
|||||||
Reference in New Issue
Block a user