openscad-playground/src/language/openscad-pseudoparser.ts

69 lines
2.2 KiB
TypeScript
Raw Normal View History

// Portions of this file are Copyright 2021 Google LLC, and licensed under GPL2+. See COPYING.
2023-03-24 04:05:45 +00:00
export type ParsedFunctionoidDef = {
path: string,
name: string,
params?: {
name: string,
defaultValue: string,
}[],
signature: string,
referencesChildren: boolean | null,
};
export type ParsedFunctionoidDefs = {[name: string]: ParsedFunctionoidDef};
export type ParsedFile = {
functions: ParsedFunctionoidDefs,
modules: ParsedFunctionoidDefs,
vars: string[],
includes: string[],
uses: string[],
};
export const stripComments = (src: string) => src.replaceAll(/\/\*(.|[\s\S])*?\*\/|\/\/.*?$/gm, '');
export function parseOpenSCAD(path: string, src: string, skipPrivates: boolean): ParsedFile {
const withoutComments = stripComments(src);
const vars = [];
const functions: ParsedFunctionoidDefs = {};
const modules: ParsedFunctionoidDefs = {};
const includes: string[] = [];
const uses: string[] = [];
for (const m of withoutComments.matchAll(/(use|include)\s*<([^>]+)>/g)) {
(m[1] == 'use' ? uses : includes).push(m[2]);
}
for (const m of withoutComments.matchAll(/(?:^|[{};])\s*([$\w]+)\s*=/g)) {
vars.push(m[1]);
}
for (const m of withoutComments.matchAll(/(function|module)\s+([$\w]+)\s*\(([^)]*)\)(?:\s*(?:=\s*)?(\{\}|[^{}]+?;))?/gm)) {
const type = m[1];
const name = m[2];
if (skipPrivates && name.startsWith('_')) {
continue;
}
const paramsStr = m[3];
const optBody = m[4];
const params = [];
if (/^(\s*([$\w]+(\s*=[^,()[]+)?(\s*,\s*[$\w]+(\s*=[^,()[]+)?)*)?\s*)$/m.test(paramsStr)) {
for (const paramStr of paramsStr.split(',')) {
const am = /^\s*([$\w]+)(?:\s*=([^,()[]+))?\s*$/.exec(paramStr);
if (am) {
const paramName = am[1];
const defaultValue = am[2];
params.push({
name: paramName,
defaultValue
});
}
}
}
(type == 'function' ? functions : modules)[name] = {
path,
name,
signature: `${name}(${paramsStr.replaceAll(/[\s]+/gm, ' ').replaceAll(/\b | \b/g, '')})`,
params,
referencesChildren: optBody != null ? (optBody.indexOf('children()') >= 0) : null,
};
}
return {vars, functions, modules, includes, uses};
}