UNPKG

decaffeinate-parser

Version:

A better AST for CoffeeScript, inspired by CoffeeScriptRedux.

121 lines (120 loc) 5.74 kB
import SourceType from 'coffee-lex/dist/SourceType'; import { Literal, Splat, StringWithInterpolations, SuperCall, Value } from 'decaffeinate-coffeescript2/lib/coffeescript/nodes'; import { inspect } from 'util'; import { AssignOp, BareSuperFunctionApplication, BaseFunction, DefaultParam, DoOp, FunctionApplication, Identifier, NewOp, SoakedFunctionApplication, SoakedNewOp, Super } from '../nodes'; import getLocation from '../util/getLocation'; import isHeregexTemplateNode from '../util/isHeregexTemplateNode'; import locationsEqual from '../util/locationsEqual'; import makeHeregex from '../util/makeHeregex'; import parseString from '../util/parseString'; import UnsupportedNodeError from '../util/UnsupportedNodeError'; import mapAny from './mapAny'; import mapCSX from './mapCSX'; export default function mapCall(context, node) { var _a = getLocation(context, node), line = _a.line, column = _a.column, start = _a.start, end = _a.end, raw = _a.raw; if (node.csx) { return mapCSX(context, node); } if (isHeregexTemplateNode(node, context)) { var firstArg = node.args[0]; if (!(firstArg instanceof Value) || !(firstArg.base instanceof 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 Value) || !(secondArg.base instanceof Literal)) { throw new Error('Expected a string flags value in the heregex AST.'); } flags = parseString(secondArg.base.value); } else { flags = ''; } return makeHeregex(context, strNode, flags); } var args = node.args.map(function (arg) { return mapAny(context, arg); }); if (node instanceof SuperCall) { if (node.args.length === 1 && node.args[0] instanceof Splat && locationsEqual(node.args[0].locationData, node.locationData)) { return new BareSuperFunctionApplication(line, column, start, end, raw); } var superIndex = context.sourceTokens.indexOfTokenStartingAtSourceIndex(start); var superToken = superIndex && context.sourceTokens.tokenAtIndex(superIndex); if (!superToken || superToken.type !== SourceType.SUPER) { throw new Error("unable to find SUPER token in 'super' function call: " + inspect(node)); } var superLocation = context.linesAndColumns.locationForIndex(superToken.start); if (!superLocation) { throw new Error("unable to locate SUPER token for 'super' function call: " + inspect(node)); } return new FunctionApplication(line, column, start, end, raw, new 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(context, node.variable); if (node.isNew) { return mapNewOp(context, node); } if (node.soak) { return new SoakedFunctionApplication(line, column, start, end, raw, callee, args); } if (node["do"]) { return mapDoOp(context, node); } return new FunctionApplication(line, column, start, end, raw, callee, args); } function mapNewOp(context, node) { if (!node.variable) { // This should only happen when `isSuper` is true. throw new UnsupportedNodeError(node); } var _a = getLocation(context, node), line = _a.line, column = _a.column, start = _a.start, end = _a.end, raw = _a.raw; var callee = mapAny(context, node.variable); var args = node.args.map(function (arg) { return mapAny(context, arg); }); if (node.soak) { return new SoakedNewOp(line, column, start, end, raw, callee, args); } else { return new 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(node); } var _a = getLocation(context, node), line = _a.line, column = _a.column, start = _a.start, end = _a.end, raw = _a.raw; var expression = mapAny(context, node.variable); var args = node.args.map(function (arg) { return mapAny(context, arg); }); if (expression instanceof BaseFunction) { expression = augmentDoFunctionWithArgs(context, expression, args); } else if (expression instanceof AssignOp && expression.expression instanceof BaseFunction) { var newRhs = augmentDoFunctionWithArgs(context, expression.expression, args); expression = expression.withExpression(newRhs); } return new 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 Identifier && param instanceof Identifier && arg.data === param.data && arg.start === param.start && arg.end === param.end) { return param; } return new DefaultParam(param.line, param.column, param.start, arg.end, context.source.slice(param.start, arg.end), param, arg); }); return func.withParameters(newParameters); }