@bscotch/gml-parser
Version:
A parser for GML (GameMaker Language) files for programmatic manipulation and analysis of GameMaker projects.
125 lines • 3.93 kB
JavaScript
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