decaffeinate-parser
Version:
A better AST for CoffeeScript, inspired by CoffeeScriptRedux.
92 lines (91 loc) • 4.83 kB
JavaScript
import { SourceType } from 'coffee-lex';
import { Access, Index, Literal, Slice as CoffeeSlice } from 'decaffeinate-coffeescript2/lib/coffeescript/nodes';
import { inspect } from 'util';
import { DynamicMemberAccessOp, Identifier, MemberAccessOp, ProtoMemberAccessOp, Slice, SoakedDynamicMemberAccessOp, SoakedMemberAccessOp, SoakedProtoMemberAccessOp, SoakedSlice } from '../nodes';
import getLocation from '../util/getLocation';
import UnsupportedNodeError from '../util/UnsupportedNodeError';
import mapAny from './mapAny';
export default function mapValue(context, node) {
var location = getLocation(context, node);
return node.properties.reduce(function (reduced, property) { return reduceProperty(context, location, reduced, property); }, mapAny(context, node.base));
}
export function reduceProperty(context, location, reduced, property) {
if (property instanceof Access) {
var name = property.name;
if (!(name instanceof Literal)) {
throw new Error("unexpected non-Literal property access name: " + inspect(name));
}
var startTokenIndex = tokenIndexAtLocation(context, property.locationData);
var startToken = startTokenIndex && context.sourceTokens.tokenAtIndex(startTokenIndex);
if (startToken && property.soak) {
if (startToken.type !== SourceType.EXISTENCE) {
throw new Error("expected EXISTENCE token ('?') but got " + SourceType[startToken.type] + ": " + inspect(startToken));
}
startTokenIndex = startTokenIndex && startTokenIndex.next();
startToken =
startTokenIndex && context.sourceTokens.tokenAtIndex(startTokenIndex);
}
if (!startToken) {
throw new Error("cannot find token at start of property: " + inspect(property));
}
var last = context.linesAndColumns.indexForLocation({
line: property.locationData.last_line,
column: property.locationData.last_column
});
if (last === null) {
throw new Error("cannot find offset of last character of property: " + inspect(property));
}
var isPrototypeAccess = startToken.type === SourceType.PROTO;
if (isPrototypeAccess) {
var AccessOp = property.soak
? SoakedProtoMemberAccessOp
: ProtoMemberAccessOp;
return new AccessOp(location.line, location.column, location.start, last + 1, context.source.slice(location.start, last + 1), reduced);
}
else {
var member = mapAny(context, name);
if (!(member instanceof Identifier)) {
throw new Error("unexpected non-Identifier access member: " + inspect(member));
}
var AccessOp = property.soak ? SoakedMemberAccessOp : MemberAccessOp;
return new AccessOp(location.line, location.column, location.start, last + 1, context.source.slice(location.start, last + 1), reduced, member);
}
}
else if (property instanceof Index) {
var NodeClass = property.soak
? SoakedDynamicMemberAccessOp
: DynamicMemberAccessOp;
var last = context.linesAndColumns.indexForLocation({
line: property.locationData.last_line,
column: property.locationData.last_column
});
if (last === null) {
throw new Error("cannot find offset of last character of index: " + inspect(property));
}
return new NodeClass(location.line, location.column, location.start, last + 1, context.source.slice(location.start, last + 1), reduced, mapAny(context, property.index));
}
else if (property instanceof CoffeeSlice) {
var last = context.linesAndColumns.indexForLocation({
line: property.locationData.last_line,
column: property.locationData.last_column
});
if (last === null) {
throw new Error("cannot find offset of last character of slice: " + inspect(property));
}
var SliceClass = property.soak ? SoakedSlice : Slice;
return new SliceClass(location.line, location.column, location.start, last + 1, context.source.slice(location.start, last + 1), reduced, property.range.from ? mapAny(context, property.range.from) : null, property.range.to ? mapAny(context, property.range.to) : null, !property.range.exclusive);
}
else {
throw new UnsupportedNodeError(property, 'Unexpected property access.');
}
}
function tokenIndexAtLocation(context, location) {
var start = context.linesAndColumns.indexForLocation({
line: location.first_line,
column: location.first_column
});
if (start === null) {
return null;
}
return context.sourceTokens.indexOfTokenContainingSourceIndex(start);
}