From 05c0476529f89b76bef7ce8b98dca3e22c4b13ff Mon Sep 17 00:00:00 2001 From: "andrea.bergia" Date: Tue, 5 Nov 2024 17:47:05 +0100 Subject: [PATCH] WIP: Integrating SNC changes --- .java-version | 1 + .../org/mozilla/javascript/IRFactory.java | 36 +++++++++++++-- .../java/org/mozilla/javascript/Node.java | 33 ++++++++++++++ .../java/org/mozilla/javascript/Parser.java | 44 ++++++++++++++++--- .../org/mozilla/javascript/TokenStream.java | 15 +++++++ .../mozilla/javascript/ast/BigIntLiteral.java | 6 +++ .../javascript/ast/ExpressionStatement.java | 1 + .../javascript/ast/InfixExpression.java | 1 + .../javascript/ast/KeywordLiteral.java | 5 +++ .../java/org/mozilla/javascript/ast/Name.java | 5 +++ .../mozilla/javascript/ast/NumberLiteral.java | 5 +++ .../mozilla/javascript/ast/PropertyGet.java | 2 + 12 files changed, 145 insertions(+), 9 deletions(-) create mode 100644 .java-version diff --git a/.java-version b/.java-version new file mode 100644 index 0000000000..03b6389f32 --- /dev/null +++ b/.java-version @@ -0,0 +1 @@ +17.0 diff --git a/rhino/src/main/java/org/mozilla/javascript/IRFactory.java b/rhino/src/main/java/org/mozilla/javascript/IRFactory.java index 4081909c15..6c4a3680b7 100644 --- a/rhino/src/main/java/org/mozilla/javascript/IRFactory.java +++ b/rhino/src/main/java/org/mozilla/javascript/IRFactory.java @@ -534,7 +534,9 @@ private Node transformElementGet(ElementGet node) { private Node transformExprStmt(ExpressionStatement node) { Node expr = transform(node.getExpression()); - return new Node(node.getType(), expr, node.getLineno()); + Node exprStatementNode = new Node(node.getType(), expr, node.getLineno()); + if (node.wasColumnAssigned()) exprStatementNode.setColumn(node.column()); + return exprStatementNode; } private Node transformForInLoop(ForInLoop loop) { @@ -812,7 +814,20 @@ private Node transformIf(IfStatement n) { private Node transformInfix(InfixExpression node) { Node left = transform(node.getLeft()); Node right = transform(node.getRight()); - return createBinary(node.getType(), left, right); + Node binaryNode = createBinary(node.getType(), left, right); + + // Since we are transforming InfixExpression -> Node, we need to copy over the column and + // line, but only for newly created nodes which have no column information set. + // createBinary() may return a Node reference with the correct line/column. + // Example: `true && ` would return the `` reference from + // createBinary + boolean nodeCreated = (binaryNode != left) && (binaryNode != right); + if (nodeCreated && node.wasColumnAssigned()) { + binaryNode.setColumn(node.column()); + binaryNode.setLineno(node.getLineno()); + } + + return binaryNode; } private Node transformLabeledStatement(LabeledStatement ls) { @@ -878,6 +893,8 @@ private Node transformObjectLiteral(ObjectLiteral node) { // stages don't need to know about object literals. List elems = node.getElements(); Node object = new Node(Token.OBJECTLIT); + object.setColumn(node.column()); + object.setLineno(node.getLineno()); Object[] properties; if (elems.isEmpty()) { properties = ScriptRuntime.emptyArgs; @@ -992,7 +1009,10 @@ private Node transformScript(ScriptNode node) { } private Node transformString(StringLiteral node) { - return Node.newString(node.getValue()); + Node stringNode = Node.newString(node.getValue()); + stringNode.setColumn(node.column()); + stringNode.setLineno(node.getLineno()); + return stringNode; } private Node transformSwitch(SwitchStatement node) { @@ -1063,7 +1083,10 @@ private Node transformSwitch(SwitchStatement node) { private Node transformThrow(ThrowStatement node) { Node value = transform(node.getExpression()); - return new Node(Token.THROW, value, node.getLineno()); + value.setColumn(node.columnOrDefault()); + Node nx = new Node(Token.THROW, value, node.getLineno()); + nx.setColumn(node.columnOrDefault()); + return nx; } private Node transformTry(TryStatement node) { @@ -1753,6 +1776,11 @@ private static Node createIf(Node cond, Node ifTrue, Node ifFalse, int lineno) { result.addChildToBack(ifNotTarget); } + if (cond.getFirstChild() != null) { + Node conditionalChild = cond.getFirstChild(); + if (conditionalChild.wasColumnAssigned()) result.setColumn(conditionalChild.column()); + } + return result; } diff --git a/rhino/src/main/java/org/mozilla/javascript/Node.java b/rhino/src/main/java/org/mozilla/javascript/Node.java index 149326d5c7..9308546e3d 100644 --- a/rhino/src/main/java/org/mozilla/javascript/Node.java +++ b/rhino/src/main/java/org/mozilla/javascript/Node.java @@ -84,6 +84,8 @@ public class Node implements Iterable { ATTRIBUTE_FLAG = 0x2, // x.@y or x..@y DESCENDANTS_FLAG = 0x4; // x..y or x..@i + protected static final int DEFAULT_COLUMN = 1; + private static class PropListItem { PropListItem next; int type; @@ -1253,11 +1255,42 @@ private static void appendPrintId(Node n, Map printIds, StringBui } } + protected void setColumn(int column) { + fColumn = column; + } + + /** + * @return the column of where a Node is defined in source. If the column is -1, it was never + * initialized. + *

May be overridden by sub classes + */ + public int column() { + return fColumn; + } + + /** + * This is a safe retrieval of the column number assigned to a node with the intent of being + * used by ISourceMapper. + * + *

Worst case the mapping is off by the number of lines a transpiler has compacted from + * source. In practice, this should be no more than a few lines. + * + * @return DEFAULT_COLUMN if column was never initialized, else the actual column + */ + public int columnOrDefault() { + return wasColumnAssigned() ? fColumn : DEFAULT_COLUMN; + } + + public boolean wasColumnAssigned() { + return fColumn > 0; + } + protected int type = Token.ERROR; // type of the node, e.g. Token.NAME protected Node next; // next sibling protected Node first; // first element of a linked list of children protected Node last; // last element of a linked list of children protected int lineno = -1; + private int fColumn = -1; /** * Linked list of properties. Since vast majority of nodes would have no more then 2 properties, diff --git a/rhino/src/main/java/org/mozilla/javascript/Parser.java b/rhino/src/main/java/org/mozilla/javascript/Parser.java index 422d4b666d..4f94900204 100644 --- a/rhino/src/main/java/org/mozilla/javascript/Parser.java +++ b/rhino/src/main/java/org/mozilla/javascript/Parser.java @@ -670,6 +670,7 @@ private AstNode parseFunctionBody(int type, FunctionNode fnNode) throws IOExcept ++nestingOfFunction; int pos = ts.tokenBeg; Block pn = new Block(pos); // starts at LC position + pn.setColumn(ts.getTokenColumn()); // Function code that is supplied as the arguments to the built-in // Function, Generator, and AsyncFunction constructors is strict mode code @@ -955,6 +956,7 @@ private FunctionNode function(int type) throws IOException { } FunctionNode fnNode = new FunctionNode(functionSourceStart, name); + fnNode.setColumn(ts.getTokenColumn(functionSourceStart)); fnNode.setFunctionType(type); if (isGenerator) { fnNode.setIsES6Generator(); @@ -1167,6 +1169,7 @@ private AstNode statements(AstNode parent) throws IOException { int pos = ts.tokenBeg; AstNode block = parent != null ? parent : new Block(pos); block.setLineno(ts.lineno); + block.setColumn(ts.getTokenColumn()); int tt; while ((tt = peekToken()) > Token.EOF && tt != Token.RC) { @@ -1418,6 +1421,11 @@ private IfStatement ifStatement() throws IOException { pn.setElsePart(ifFalse); pn.setElsePosition(elsePos); pn.setLineno(lineno); + if (pn.getCondition() != null) { + AstNode condition = pn.getCondition(); + if (condition.wasColumnAssigned()) pn.setColumn(condition.column()); + } + return pn; } @@ -1429,6 +1437,7 @@ private SwitchStatement switchStatement() throws IOException { SwitchStatement pn = new SwitchStatement(pos); if (mustMatchToken(Token.LP, "msg.no.paren.switch", true)) pn.setLp(ts.tokenBeg - pos); pn.setLineno(ts.lineno); + pn.setColumn(ts.getTokenColumn(pos)); AstNode discriminant = expr(false); pn.setExpression(discriminant); @@ -1478,6 +1487,7 @@ private SwitchStatement switchStatement() throws IOException { caseNode.setExpression(caseExpression); caseNode.setLength(ts.tokenEnd - pos); // include colon caseNode.setLineno(caseLineno); + caseNode.setColumn(ts.getTokenColumn(casePos)); while ((tt = peekToken()) != Token.RC && tt != Token.CASE @@ -1511,6 +1521,7 @@ private WhileLoop whileLoop() throws IOException { int pos = ts.tokenBeg; WhileLoop pn = new WhileLoop(pos); pn.setLineno(ts.lineno); + pn.setColumn(ts.getTokenColumn(pos)); enterLoop(pn); try { ConditionData data = condition(); @@ -1532,6 +1543,7 @@ private DoLoop doLoop() throws IOException { int pos = ts.tokenBeg, end; DoLoop pn = new DoLoop(pos); pn.setLineno(ts.lineno); + pn.setColumn(ts.getTokenColumn(pos)); enterLoop(pn); try { AstNode body = getNextStatementAfterInlineComments(pn); @@ -1865,6 +1877,7 @@ private ThrowStatement throwStatement() throws IOException { AstNode expr = expr(false); ThrowStatement pn = new ThrowStatement(pos, expr); pn.setLineno(lineno); + pn.setColumn(ts.getTokenColumn(pos)); return pn; } @@ -2224,6 +2237,7 @@ private VariableDeclaration variables(int declType, int pos, boolean isStatement VariableDeclaration pn = new VariableDeclaration(pos); pn.setType(declType); pn.setLineno(ts.lineno); + pn.setColumn(ts.getTokenColumn()); Comment varjsdocNode = getAndResetJsDoc(); if (varjsdocNode != null) { pn.setJsDocNode(varjsdocNode); @@ -2273,6 +2287,7 @@ private VariableDeclaration variables(int declType, int pos, boolean isStatement } VariableInitializer vi = new VariableInitializer(kidPos, end - kidPos); + vi.setColumn(ts.getTokenColumn(kidPos)); if (destructuring != null) { if (init == null && !inForInit) { reportError("msg.destruct.assign.no.init"); @@ -2442,7 +2457,9 @@ private AstNode assignExpr() throws IOException { if (isNotValidSimpleAssignmentTarget(pn)) reportError("msg.syntax.invalid.assignment.lhs"); + Node left = pn; pn = new Assignment(tt, pn, assignExpr(), opPos); + if (left.wasColumnAssigned()) pn.setColumn(left.column()); if (jsdocNode != null) { pn.setJsDocNode(jsdocNode); @@ -2698,6 +2715,7 @@ private AstNode unaryExpr() throws IOException { consumeToken(); node = new UnaryExpression(tt, ts.tokenBeg, unaryExpr()); node.setLineno(line); + node.setColumn(ts.getTokenColumn()); return node; case Token.ADD: @@ -2705,6 +2723,7 @@ private AstNode unaryExpr() throws IOException { // Convert to special POS token in parse tree node = new UnaryExpression(Token.POS, ts.tokenBeg, unaryExpr()); node.setLineno(line); + node.setColumn(ts.getTokenColumn()); return node; case Token.SUB: @@ -2712,6 +2731,7 @@ private AstNode unaryExpr() throws IOException { // Convert to special NEG token in parse tree node = new UnaryExpression(Token.NEG, ts.tokenBeg, unaryExpr()); node.setLineno(line); + node.setColumn(ts.getTokenColumn()); return node; case Token.INC: @@ -2719,6 +2739,7 @@ private AstNode unaryExpr() throws IOException { consumeToken(); UpdateExpression expr = new UpdateExpression(tt, ts.tokenBeg, memberExpr(true)); expr.setLineno(line); + expr.setColumn(ts.getTokenColumn()); checkBadIncDec(expr); return expr; @@ -2726,6 +2747,7 @@ private AstNode unaryExpr() throws IOException { consumeToken(); node = new UnaryExpression(tt, ts.tokenBeg, unaryExpr()); node.setLineno(line); + node.setColumn(ts.getTokenColumn()); return node; case Token.ERROR: @@ -2750,6 +2772,7 @@ private AstNode unaryExpr() throws IOException { consumeToken(); UpdateExpression uexpr = new UpdateExpression(tt, ts.tokenBeg, pn, true); uexpr.setLineno(line); + uexpr.setColumn(ts.getTokenColumn()); checkBadIncDec(uexpr); return uexpr; } @@ -2843,6 +2866,7 @@ private AstNode memberExpr(boolean allowCallSyntax) throws IOException { consumeToken(); int pos = ts.tokenBeg; NewExpression nx = new NewExpression(pos); + nx.setColumn(ts.getTokenColumn()); AstNode target = memberExpr(false); int end = getNodeEnd(target); @@ -2968,6 +2992,7 @@ private FunctionCall makeFunctionCall(AstNode pn, int pos, int lineno, boolean i // Assign the line number for the function call to where // the paren appeared, not where the name expression started. f.setLineno(lineno); + f.setColumn(ts.getTokenColumn()); f.setLp(ts.tokenBeg - pos); List args = argumentList(); if (args != null && args.size() > ARGC_LIMIT) reportError("msg.too.many.function.args"); @@ -3122,6 +3147,7 @@ private ElementGet makeElemGet(AstNode pn, int lb, int lineno) throws IOExceptio g.setElement(expr); g.setParens(lb, rb); g.setLineno(lineno); + g.setColumn(ts.getTokenColumn()); return g; } @@ -3303,6 +3329,7 @@ private AstNode primaryExpr() throws IOException { RegExpLiteral re = new RegExpLiteral(pos, end - pos); re.setValue(ts.getString()); re.setFlags(ts.readAndClearRegExpFlags()); + re.setColumn(ts.getTokenColumn()); return re; case Token.NULL: @@ -3312,7 +3339,7 @@ private AstNode primaryExpr() throws IOException { consumeToken(); pos = ts.tokenBeg; end = ts.tokenEnd; - return new KeywordLiteral(pos, end - pos, tt); + return new KeywordLiteral(pos, end - pos, tt, ts.getTokenColumn(pos)); case Token.TEMPLATE_LITERAL: consumeToken(); @@ -3783,6 +3810,7 @@ private ObjectLiteral objectLiteral() throws IOException { mustMatchToken(Token.RC, "msg.no.brace.prop", true); ObjectLiteral pn = new ObjectLiteral(pos, ts.tokenEnd - pos); + pn.setColumn(ts.getTokenColumn()); if (objectLiteralDestructuringDefault) { pn.putIntProp(Node.OBJECT_LITERAL_DESTRUCTURING, 1); } @@ -3815,6 +3843,7 @@ private AstNode objliteralProperty() throws IOException { if (compilerEnv.getLanguageVersion() >= Context.VERSION_ES6) { int pos = ts.tokenBeg; int lineno = ts.lineno; + int col = ts.tokenBeg; nextToken(); AstNode expr = assignExpr(); if (peekToken() != Token.RB) { @@ -3824,6 +3853,7 @@ private AstNode objliteralProperty() throws IOException { pname = new ComputedPropertyKey(pos, ts.tokenEnd - pos); pname.setLineno(lineno); + pname.setColumn(col); ((ComputedPropertyKey) pname).setExpression(expr); } else { reportError("msg.bad.prop"); @@ -3938,7 +3968,7 @@ private Name createNameNode(boolean checkActivation, int token) { codeBug(); } } - Name name = new Name(beg, s); + Name name = new Name(beg, s, ts.getTokenColumn(beg)); name.setLineno(lineno); if (checkActivation) { checkActivationName(s, token); @@ -3950,6 +3980,7 @@ private StringLiteral createStringLiteral() { int pos = ts.tokenBeg, end = ts.tokenEnd; StringLiteral s = new StringLiteral(pos, end - pos); s.setLineno(ts.lineno); + s.setColumn(ts.getTokenColumn()); s.setValue(ts.getString()); s.setQuoteCharacter(ts.getQuoteChar()); return s; @@ -4012,9 +4043,9 @@ private AstNode createNumericLiteral(int tt, boolean isProperty) { } } if (tt == Token.BIGINT) { - return new BigIntLiteral(ts.tokenBeg, s + "n", ts.getBigInt()); + return new BigIntLiteral(ts.tokenBeg, s + "n", ts.getBigInt(), ts.getTokenColumn()); } else { - return new NumberLiteral(ts.tokenBeg, s, ts.getNumber()); + return new NumberLiteral(ts.tokenBeg, s, ts.getNumber(), ts.getTokenColumn()); } } @@ -4076,6 +4107,7 @@ private void checkBadIncDec(UpdateExpression expr) { private ErrorNode makeErrorNode() { ErrorNode pn = new ErrorNode(ts.tokenBeg, ts.tokenEnd - ts.tokenBeg); pn.setLineno(ts.lineno); + pn.setColumn(ts.getTokenColumn()); return pn; } @@ -4584,7 +4616,9 @@ protected Node simpleAssignment(Node left, Node right, Transformer transformer) reportError("msg.bad.id.strict", name); } left.setType(Token.BINDNAME); - return new Node(Token.SETNAME, left, right); + Node node = new Node(Token.SETNAME, left, right); + if (left.wasColumnAssigned()) node.setColumn(left.column()); + return node; case Token.GETPROP: case Token.GETELEM: diff --git a/rhino/src/main/java/org/mozilla/javascript/TokenStream.java b/rhino/src/main/java/org/mozilla/javascript/TokenStream.java index 07a51ac940..71fd4625b2 100644 --- a/rhino/src/main/java/org/mozilla/javascript/TokenStream.java +++ b/rhino/src/main/java/org/mozilla/javascript/TokenStream.java @@ -2180,6 +2180,7 @@ private int getChar(boolean skipFormattingChars, boolean ignoreLineEnd) throws I } lineEndChar = -1; lineStart = sourceCursor - 1; + lastLineEnd = tokenEnd; lineno++; } @@ -2432,6 +2433,18 @@ public int getLength() { return tokenEnd - tokenBeg; } + public int getTokenColumn() { + return getTokenColumn(tokenBeg); + } + + /** + * @param tokenPosition absolute start of the token position + * @return the 1-indexed column + */ + public int getTokenColumn(int tokenPosition) { + return tokenPosition - lastLineEnd + 1; + } + // stuff other than whitespace since start of line private boolean dirtyLine; @@ -2483,6 +2496,8 @@ public int getLength() { // Record start and end positions of last scanned token. int tokenBeg; int tokenEnd; + + private int lastLineEnd; // Type of last comment scanned. Token.CommentType commentType; diff --git a/rhino/src/main/java/org/mozilla/javascript/ast/BigIntLiteral.java b/rhino/src/main/java/org/mozilla/javascript/ast/BigIntLiteral.java index 86751f13e4..bed35b354e 100644 --- a/rhino/src/main/java/org/mozilla/javascript/ast/BigIntLiteral.java +++ b/rhino/src/main/java/org/mozilla/javascript/ast/BigIntLiteral.java @@ -42,6 +42,12 @@ public BigIntLiteral(int pos, String value, BigInteger bigInt) { setBigInt(bigInt); } + /** Constructor. Sets the length to the length of the {@code value} string. */ + public BigIntLiteral(int pos, String value, BigInteger bigInt, int column) { + this(pos, value, bigInt); + super.setColumn(column); + } + /** Returns the node's string value (the original source token) */ public String getValue() { return value; diff --git a/rhino/src/main/java/org/mozilla/javascript/ast/ExpressionStatement.java b/rhino/src/main/java/org/mozilla/javascript/ast/ExpressionStatement.java index 475941548b..ed016dc963 100644 --- a/rhino/src/main/java/org/mozilla/javascript/ast/ExpressionStatement.java +++ b/rhino/src/main/java/org/mozilla/javascript/ast/ExpressionStatement.java @@ -68,6 +68,7 @@ public ExpressionStatement(int pos, int len) { public ExpressionStatement(int pos, int len, AstNode expr) { super(pos, len); setExpression(expr); + if (expr.wasColumnAssigned()) super.setColumn(expr.column()); } /** Returns the wrapped expression */ diff --git a/rhino/src/main/java/org/mozilla/javascript/ast/InfixExpression.java b/rhino/src/main/java/org/mozilla/javascript/ast/InfixExpression.java index afdde7c84f..6fe4efcded 100644 --- a/rhino/src/main/java/org/mozilla/javascript/ast/InfixExpression.java +++ b/rhino/src/main/java/org/mozilla/javascript/ast/InfixExpression.java @@ -48,6 +48,7 @@ public InfixExpression(int operator, AstNode left, AstNode right, int operatorPo setType(operator); setOperatorPosition(operatorPos - left.getPosition()); setLeftAndRight(left, right); + if (left.wasColumnAssigned()) setColumn(left.column()); } public void setLeftAndRight(AstNode left, AstNode right) { diff --git a/rhino/src/main/java/org/mozilla/javascript/ast/KeywordLiteral.java b/rhino/src/main/java/org/mozilla/javascript/ast/KeywordLiteral.java index e760f2cbc6..b47c71aa8f 100644 --- a/rhino/src/main/java/org/mozilla/javascript/ast/KeywordLiteral.java +++ b/rhino/src/main/java/org/mozilla/javascript/ast/KeywordLiteral.java @@ -35,6 +35,11 @@ public KeywordLiteral(int pos, int len, int nodeType) { setType(nodeType); } + public KeywordLiteral(int pos, int len, int nodeType, int column) { + this(pos, len, nodeType); + super.setColumn(column); + } + /** * Sets node token type * diff --git a/rhino/src/main/java/org/mozilla/javascript/ast/Name.java b/rhino/src/main/java/org/mozilla/javascript/ast/Name.java index 83fd1d545a..cf7ec02c74 100644 --- a/rhino/src/main/java/org/mozilla/javascript/ast/Name.java +++ b/rhino/src/main/java/org/mozilla/javascript/ast/Name.java @@ -54,6 +54,11 @@ public Name(int pos, String name) { setLength(name.length()); } + public Name(int pos, String name, int column) { + this(pos, name); + super.setColumn(column); + } + /** Returns the node's identifier */ public String getIdentifier() { return identifier; diff --git a/rhino/src/main/java/org/mozilla/javascript/ast/NumberLiteral.java b/rhino/src/main/java/org/mozilla/javascript/ast/NumberLiteral.java index 28f3c20009..b6ead7b66a 100644 --- a/rhino/src/main/java/org/mozilla/javascript/ast/NumberLiteral.java +++ b/rhino/src/main/java/org/mozilla/javascript/ast/NumberLiteral.java @@ -41,6 +41,11 @@ public NumberLiteral(int pos, String value, double number) { setDouble(number); } + public NumberLiteral(int pos, String value, double number, int column) { + this(pos, value, number); + super.setColumn(column); + } + public NumberLiteral(double number) { setDouble(number); setValue(Double.toString(number)); diff --git a/rhino/src/main/java/org/mozilla/javascript/ast/PropertyGet.java b/rhino/src/main/java/org/mozilla/javascript/ast/PropertyGet.java index 4f67a84354..cb7c39c783 100644 --- a/rhino/src/main/java/org/mozilla/javascript/ast/PropertyGet.java +++ b/rhino/src/main/java/org/mozilla/javascript/ast/PropertyGet.java @@ -35,10 +35,12 @@ public PropertyGet(int pos, int len, AstNode target, Name property) { */ public PropertyGet(AstNode target, Name property) { super(target, property); + super.setColumn(property.column()); } public PropertyGet(AstNode target, Name property, int dotPosition) { super(Token.GETPROP, target, property, dotPosition); + super.setColumn(property.column()); } /** Returns the object on which the property is being fetched. Should never be {@code null}. */