UNPKG

@bscotch/gml-parser

Version:

A parser for GML (GameMaker Language) files for programmatic manipulation and analysis of GameMaker projects.

125 lines 3.93 kB
import { keysOf } from '@bscotch/utility'; import { isArray, ok } from './util.js'; export function rhsFrom(item) { if (item === undefined) { return; } if (isArray(item)) { return rhsFrom(item[0]?.children); } if ('name' in item) { if (item.name === 'assignmentRightHandSide') { return item.children; } else if (item.name == 'assignment') { return rhsFrom(item.children); } else { // Unexpected item type return undefined; } } if ('assignmentRightHandSide' in item) { return item.assignmentRightHandSide[0].children; } return item; } export function functionFromRhs(rhs) { return rhsFrom(rhs)?.functionExpression?.[0].children; } export function structLiteralFromRhs(rhs) { return rhsFrom(rhs)?.structLiteral?.[0].children; } export function arrayLiteralFromRhs(rhs) { return rhsFrom(rhs)?.expression?.[0].children.primaryExpression?.[0].children .arrayLiteral?.[0]?.children; } export function isEmpty(obj) { return Object.keys(obj).length === 0; } export function sortedFunctionCallParts(node) { return [ node.children.StartParen[0], ...(node.children.functionArgument || []), ...(node.children.Comma || []), node.children.EndParen[0], ].sort((a, b) => { const aLocation = ('location' in a ? a.location : a); const bLocation = ('location' in b ? b.location : b); return aLocation.startOffset - bLocation.startOffset; }); } export function stringLiteralAsString(children) { const start = 'StringStart' in children ? children.StringStart[0].image : 'MultilineSingleStringStart' in children ? children.MultilineSingleStringStart[0].image : children.MultilineDoubleStringStart[0].image; const end = 'StringEnd' in children ? children.StringEnd[0].image : 'MultilineSingleStringEnd' in children ? children.MultilineSingleStringEnd[0].image : children.MultilineDoubleStringEnd[0].image; return `${start}${(children.Substring || []) .map((s) => s.image) .join('')}${end}`; } function getStartOffset(node) { return 'startOffset' in node ? node.startOffset : node.location.startOffset; } export function sortChildren(records) { const sorted = []; for (const key of keysOf(records)) { sorted.push(...records[key]); } sorted.sort((a, b) => getStartOffset(a) - getStartOffset(b)); return sorted; } export function sortedAccessorSuffixes(suffixNodes) { // Convert into a flat array of suffixes, sorted by their position in the source code. const sorted = []; if (!suffixNodes) { return sorted; } for (const node of suffixNodes) { const { children } = node; const suffixKinds = keysOf(children); for (const kind of suffixKinds) { ok(children[kind].length === 1); sorted.push(children[kind][0]); } } sorted.sort((a, b) => a.location.startOffset - b.location.startOffset); return sorted; } const identifierCstNames = [ 'All', 'Global', 'Identifier', 'Noone', 'Other', 'Self', ]; export function identifierFrom(nodes) { let node; if (Array.isArray(nodes)) { node = nodes[0]; } else if ('children' in nodes && 'identifier' in nodes.children) { node = nodes.children.identifier[0]; } else if ('identifier' in nodes) { node = nodes.identifier[0]; } else { node = nodes; } const children = 'children' in node ? node.children : node; const type = identifierCstNames.find((name) => children[name]); if (!type) { return; } const token = children[type][0]; return { token, type, name: token.image }; } //# sourceMappingURL=parser.utility.js.map