decaffeinate-parser
Version:
A better AST for CoffeeScript, inspired by CoffeeScriptRedux.
124 lines (123 loc) • 6.03 kB
JavaScript
"use strict";
exports.__esModule = true;
var SourceType_1 = require("coffee-lex/dist/SourceType");
var nodes_1 = require("decaffeinate-coffeescript2/lib/coffeescript/nodes");
var util_1 = require("util");
var nodes_2 = require("../nodes");
var getLocation_1 = require("../util/getLocation");
var isHeregexTemplateNode_1 = require("../util/isHeregexTemplateNode");
var locationsEqual_1 = require("../util/locationsEqual");
var makeHeregex_1 = require("../util/makeHeregex");
var parseString_1 = require("../util/parseString");
var UnsupportedNodeError_1 = require("../util/UnsupportedNodeError");
var mapAny_1 = require("./mapAny");
var mapCSX_1 = require("./mapCSX");
function mapCall(context, node) {
var _a = getLocation_1["default"](context, node), line = _a.line, column = _a.column, start = _a.start, end = _a.end, raw = _a.raw;
if (node.csx) {
return mapCSX_1["default"](context, node);
}
if (isHeregexTemplateNode_1["default"](node, context)) {
var firstArg = node.args[0];
if (!(firstArg instanceof nodes_1.Value) ||
!(firstArg.base instanceof nodes_1.StringWithInterpolations)) {
throw new Error('Expected a valid first heregex arg in the AST.');
}
var strNode = firstArg.base.body.expressions[0];
var flags = void 0;
if (node.args.length > 1) {
var secondArg = node.args[1];
if (!(secondArg instanceof nodes_1.Value) ||
!(secondArg.base instanceof nodes_1.Literal)) {
throw new Error('Expected a string flags value in the heregex AST.');
}
flags = parseString_1["default"](secondArg.base.value);
}
else {
flags = '';
}
return makeHeregex_1["default"](context, strNode, flags);
}
var args = node.args.map(function (arg) { return mapAny_1["default"](context, arg); });
if (node instanceof nodes_1.SuperCall) {
if (node.args.length === 1 &&
node.args[0] instanceof nodes_1.Splat &&
locationsEqual_1["default"](node.args[0].locationData, node.locationData)) {
return new nodes_2.BareSuperFunctionApplication(line, column, start, end, raw);
}
var superIndex = context.sourceTokens.indexOfTokenStartingAtSourceIndex(start);
var superToken = superIndex && context.sourceTokens.tokenAtIndex(superIndex);
if (!superToken || superToken.type !== SourceType_1["default"].SUPER) {
throw new Error("unable to find SUPER token in 'super' function call: " + util_1.inspect(node));
}
var superLocation = context.linesAndColumns.locationForIndex(superToken.start);
if (!superLocation) {
throw new Error("unable to locate SUPER token for 'super' function call: " + util_1.inspect(node));
}
return new nodes_2.FunctionApplication(line, column, start, end, raw, new nodes_2.Super(superLocation.line + 1, superLocation.column + 1, superToken.start, superToken.end, context.source.slice(superToken.start, superToken.end)), args);
}
if (!node.variable) {
throw new Error('Expected non-super call to have a variable defined.');
}
var callee = mapAny_1["default"](context, node.variable);
if (node.isNew) {
return mapNewOp(context, node);
}
if (node.soak) {
return new nodes_2.SoakedFunctionApplication(line, column, start, end, raw, callee, args);
}
if (node["do"]) {
return mapDoOp(context, node);
}
return new nodes_2.FunctionApplication(line, column, start, end, raw, callee, args);
}
exports["default"] = mapCall;
function mapNewOp(context, node) {
if (!node.variable) {
// This should only happen when `isSuper` is true.
throw new UnsupportedNodeError_1["default"](node);
}
var _a = getLocation_1["default"](context, node), line = _a.line, column = _a.column, start = _a.start, end = _a.end, raw = _a.raw;
var callee = mapAny_1["default"](context, node.variable);
var args = node.args.map(function (arg) { return mapAny_1["default"](context, arg); });
if (node.soak) {
return new nodes_2.SoakedNewOp(line, column, start, end, raw, callee, args);
}
else {
return new nodes_2.NewOp(line, column, start, end, raw, callee, args);
}
}
function mapDoOp(context, node) {
if (!node.variable) {
// This should only happen when `isSuper` is true.
throw new UnsupportedNodeError_1["default"](node);
}
var _a = getLocation_1["default"](context, node), line = _a.line, column = _a.column, start = _a.start, end = _a.end, raw = _a.raw;
var expression = mapAny_1["default"](context, node.variable);
var args = node.args.map(function (arg) { return mapAny_1["default"](context, arg); });
if (expression instanceof nodes_2.BaseFunction) {
expression = augmentDoFunctionWithArgs(context, expression, args);
}
else if (expression instanceof nodes_2.AssignOp &&
expression.expression instanceof nodes_2.BaseFunction) {
var newRhs = augmentDoFunctionWithArgs(context, expression.expression, args);
expression = expression.withExpression(newRhs);
}
return new nodes_2.DoOp(line, column, start, end, raw, expression);
}
function augmentDoFunctionWithArgs(context, func, args) {
var newParameters = func.parameters.map(function (param, i) {
var arg = args[i];
// If there's a parameter with no default, CoffeeScript will insert a fake
// arg with the same value and location.
if (arg instanceof nodes_2.Identifier &&
param instanceof nodes_2.Identifier &&
arg.data === param.data &&
arg.start === param.start &&
arg.end === param.end) {
return param;
}
return new nodes_2.DefaultParam(param.line, param.column, param.start, arg.end, context.source.slice(param.start, arg.end), param, arg);
});
return func.withParameters(newParameters);
}