Skip to content

Commit

Permalink
fix: don't treat explicit + operations as string interpolations (#71)
Browse files Browse the repository at this point in the history
Closes decaffeinate/decaffeinate#425
Closes decaffeinate/decaffeinate#194

There was already some logic to distinguish between explicit `+` operations and
implicit ones generated as part of string interpolation parsing, but that logic
wasn't used in all places. Now, we also use it in `isInterpolatedString`, which
avoids a problem where `+` was seen as a string interpolation in some cases.
  • Loading branch information
alangpierce authored Oct 30, 2016
1 parent 67b514b commit d01083f
Show file tree
Hide file tree
Showing 5 changed files with 125 additions and 19 deletions.
21 changes: 2 additions & 19 deletions src/util/isImplicitPlusOp.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { OPERATOR } from 'coffee-lex';
import isPlusTokenBetweenRanges from './isPlusTokenBetweenRanges';

/**
* Determine if the operator is a fake + operator for string interpolation.
Expand All @@ -7,22 +7,5 @@ export default function isImplicitPlusOp(op, context) {
if (op.type !== 'PlusOp') {
return false;
}
let tokens = context.sourceTokens;
let leftEnd = tokens.indexOfTokenContainingSourceIndex(op.left.range[1] - 1);
let rightStart = tokens.indexOfTokenContainingSourceIndex(op.right.range[0]);
// Normal '+' operators should find tokens here, so if we don't, this must be
// an implicit '+' operator.
if (!leftEnd || !rightStart) {
return true;
}
let tokensBetweenOperands = tokens.slice(leftEnd.next(), rightStart);
// If we find an actual operator, this must have been a real '+'. Otherwise,
// this must be an implicit '+'.
let foundPlusToken = false;
tokensBetweenOperands.forEach(({ type, start, end }) => {
if (type === OPERATOR && context.source.slice(start, end) === '+') {
foundPlusToken = true;
}
});
return !foundPlusToken;
return !isPlusTokenBetweenRanges(op.left.range, op.right.range, context);
}
5 changes: 5 additions & 0 deletions src/util/isInterpolatedString.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import type from './type.js';
import isPlusTokenBetweenRanges from './isPlusTokenBetweenRanges';

/**
* @param {Object} node
Expand Down Expand Up @@ -43,6 +44,10 @@ function rangeOfInterpolatedStringForNode(node, context) {
if (node.operator !== '+' || !node.second) {
return null;
}
if (isPlusTokenBetweenRanges(
context.getRange(node.first), context.getRange(node.second), context)) {
return null;
}

let range = context.getRange(node);
let tokens = context.sourceTokens;
Expand Down
27 changes: 27 additions & 0 deletions src/util/isPlusTokenBetweenRanges.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { OPERATOR } from 'coffee-lex';

/**
* Given the ranges of two operands, determine from the token list whether there
* is a real '+' operator between them. A plus operation without an actual '+'
* operator is an implicit string interpolation operation.
*/
export default function isPlusTokenBetweenRanges(leftRange, rightRange, context) {
let tokens = context.sourceTokens;
let leftEnd = tokens.indexOfTokenContainingSourceIndex(leftRange[1] - 1);
let rightStart = tokens.indexOfTokenContainingSourceIndex(rightRange[0]);
// Normal '+' operators should find tokens here, so if we don't, this must be
// an implicit '+' operator.
if (!leftEnd || !rightStart) {
return false;
}
let tokensBetweenOperands = tokens.slice(leftEnd.next(), rightStart);
// If we find an actual operator, this must have been a real '+'. Otherwise,
// this must be an implicit '+'.
let foundPlusToken = false;
tokensBetweenOperands.forEach(({ type, start, end }) => {
if (type === OPERATOR && context.source.slice(start, end) === '+') {
foundPlusToken = true;
}
});
return foundPlusToken;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
"#{a}" + "b"
90 changes: 90 additions & 0 deletions test/examples/string-interpolation-plus-normal-string/output.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
{
"type": "Program",
"line": 1,
"column": 1,
"range": [
0,
13
],
"raw": "\"#{a}\" + \"b\"\n",
"body": {
"type": "Block",
"line": 1,
"column": 1,
"range": [
0,
12
],
"statements": [
{
"type": "PlusOp",
"line": 1,
"column": 1,
"range": [
0,
12
],
"left": {
"type": "TemplateLiteral",
"line": 1,
"column": 1,
"range": [
0,
6
],
"raw": "\"#{a}\"",
"quasis": [
{
"type": "String",
"line": 1,
"column": 1,
"range": [
0,
1
],
"data": "",
"raw": "\""
},
{
"type": "String",
"data": "",
"raw": "\"",
"line": 1,
"column": 6,
"range": [
5,
6
]
}
],
"expressions": [
{
"type": "Identifier",
"line": 1,
"column": 4,
"range": [
3,
4
],
"data": "a",
"raw": "a"
}
]
},
"right": {
"type": "String",
"line": 1,
"column": 10,
"range": [
9,
12
],
"data": "b",
"raw": "\"b\""
},
"raw": "\"#{a}\" + \"b\""
}
],
"raw": "\"#{a}\" + \"b\""
}
}

0 comments on commit d01083f

Please sign in to comment.