UNPKG

decaffeinate-parser

Version:

A better AST for CoffeeScript, inspired by CoffeeScriptRedux.

92 lines (91 loc) 4.83 kB
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); }